* Add support for the SPMP8000 SoC and Letcool board
@ 2011-10-09 16:36 Zoltan Devai
2011-10-09 16:36 ` [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS Zoltan Devai
` (11 more replies)
0 siblings, 12 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Hi,
This series adds support for the Sunplus SPMP8000 SoC, an ARM926EJ-S based
MCU, which is most commonly found in handheld game consoles and digital cams.
Most of the work was done during GSoC 2011, with Greg KH as my mentor.
The board I'm using for development is the Letcool N350JP handheld.
The patches are based on Arnds for-next branch with Jamie Iles' vic-dt patches
on top.
No static platform devices are used, everything is inited from DT, with some
hacks for drivers that don't have any bindings yet.
(Documentation for own, custom bindings will follow in next version.)
So far, these peripherals are supported, with drivers not submitted yet:
gpio, fb, cpufreq, slave-dma, mmc, ASoC (i2s, codec, pcm, card).
Reviews, instructions for mainlining it are very welcome.
Thanks, Cheers,
Zoltan
arch/arm/Kconfig | 16 +
arch/arm/Makefile | 1 +
arch/arm/boot/dts/spmp8000-letcool.dts | 163 ++++++
arch/arm/boot/dts/spmp8000.dtsi | 169 ++++++
arch/arm/common/vic.c | 1 -
arch/arm/mach-spmp8000/Makefile | 11 +
arch/arm/mach-spmp8000/Makefile.boot | 1 +
arch/arm/mach-spmp8000/adc.c | 465 ++++++++++++++++
arch/arm/mach-spmp8000/board_letcool.c | 154 ++++++
arch/arm/mach-spmp8000/clkdev.c | 586 +++++++++++++++++++++
arch/arm/mach-spmp8000/clock.c | 155 ++++++
arch/arm/mach-spmp8000/core.c | 103 ++++
arch/arm/mach-spmp8000/include/mach/clock.h | 37 ++
arch/arm/mach-spmp8000/include/mach/core.h | 29 +
arch/arm/mach-spmp8000/include/mach/debug-macro.S | 19 +
arch/arm/mach-spmp8000/include/mach/dma.h | 45 ++
arch/arm/mach-spmp8000/include/mach/entry-macro.S | 14 +
arch/arm/mach-spmp8000/include/mach/gpio.h | 21 +
arch/arm/mach-spmp8000/include/mach/hardware.h | 27 +
arch/arm/mach-spmp8000/include/mach/io.h | 20 +
arch/arm/mach-spmp8000/include/mach/irqs.h | 21 +
arch/arm/mach-spmp8000/include/mach/memory.h | 16 +
arch/arm/mach-spmp8000/include/mach/regs-timer.h | 32 ++
arch/arm/mach-spmp8000/include/mach/scu.h | 146 +++++
arch/arm/mach-spmp8000/include/mach/spmp8000adc.h | 29 +
arch/arm/mach-spmp8000/include/mach/spmp8000fb.h | 32 ++
arch/arm/mach-spmp8000/include/mach/system.h | 45 ++
arch/arm/mach-spmp8000/include/mach/timex.h | 17 +
arch/arm/mach-spmp8000/include/mach/uncompress.h | 37 ++
arch/arm/mach-spmp8000/include/mach/vmalloc.h | 16 +
arch/arm/mach-spmp8000/pinmux.c | 131 +++++
arch/arm/mach-spmp8000/pwm.c | 246 +++++++++
arch/arm/mach-spmp8000/timer.c | 160 ++++++
33 files changed, 2964 insertions(+), 1 deletions(-)
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-10 1:35 ` Linus Walleij
2011-10-09 16:36 ` [PATCH 2/9] ARM: SPMP8000: Add machine base files Zoltan Devai
` (10 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
This is unneeded and causes an abort on the SPMP8000 platform.
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/common/vic.c | 1 -
1 files changed, 0 insertions(+), 1 deletions(-)
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index b22b83d..651c77d 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -274,7 +274,6 @@ static void __init vic_disable(void __iomem *base)
writel(0, base + VIC_INT_SELECT);
writel(0, base + VIC_INT_ENABLE);
writel(~0, base + VIC_INT_ENABLE_CLEAR);
- writel(0, base + VIC_IRQ_STATUS);
writel(0, base + VIC_ITCR);
writel(~0, base + VIC_INT_SOFT_CLEAR);
}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
2011-10-09 16:36 ` [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-09 17:22 ` Jamie Iles
2011-10-11 14:44 ` Arnd Bergmann
2011-10-09 16:36 ` [PATCH 3/9] ARM: SPMP8000: Add clk support Zoltan Devai
` (9 subsequent siblings)
11 siblings, 2 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Add the files for the basic support of the SPMP8000 SoC
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/Makefile | 11 ++
arch/arm/mach-spmp8000/Makefile.boot | 1 +
arch/arm/mach-spmp8000/core.c | 103 +++++++++++++
arch/arm/mach-spmp8000/include/mach/core.h | 29 ++++
arch/arm/mach-spmp8000/include/mach/debug-macro.S | 19 +++
arch/arm/mach-spmp8000/include/mach/dma.h | 45 ++++++
arch/arm/mach-spmp8000/include/mach/entry-macro.S | 14 ++
arch/arm/mach-spmp8000/include/mach/gpio.h | 21 +++
arch/arm/mach-spmp8000/include/mach/hardware.h | 27 ++++
arch/arm/mach-spmp8000/include/mach/io.h | 20 +++
arch/arm/mach-spmp8000/include/mach/irqs.h | 21 +++
arch/arm/mach-spmp8000/include/mach/memory.h | 16 ++
arch/arm/mach-spmp8000/include/mach/regs-timer.h | 32 ++++
arch/arm/mach-spmp8000/include/mach/scu.h | 146 +++++++++++++++++++
arch/arm/mach-spmp8000/include/mach/system.h | 45 ++++++
arch/arm/mach-spmp8000/include/mach/timex.h | 17 +++
arch/arm/mach-spmp8000/include/mach/uncompress.h | 37 +++++
arch/arm/mach-spmp8000/include/mach/vmalloc.h | 16 ++
arch/arm/mach-spmp8000/timer.c | 160 +++++++++++++++++++++
19 files changed, 780 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/Makefile
create mode 100644 arch/arm/mach-spmp8000/Makefile.boot
create mode 100644 arch/arm/mach-spmp8000/core.c
create mode 100644 arch/arm/mach-spmp8000/include/mach/core.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/debug-macro.S
create mode 100644 arch/arm/mach-spmp8000/include/mach/dma.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/entry-macro.S
create mode 100644 arch/arm/mach-spmp8000/include/mach/gpio.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/hardware.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/io.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/irqs.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/memory.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/regs-timer.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/scu.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/system.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/timex.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/uncompress.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/vmalloc.h
create mode 100644 arch/arm/mach-spmp8000/timer.c
diff --git a/arch/arm/mach-spmp8000/Makefile b/arch/arm/mach-spmp8000/Makefile
new file mode 100644
index 0000000..9d35cca
--- /dev/null
+++ b/arch/arm/mach-spmp8000/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux kernel.
+#
+obj-y := core.o
+obj-y += timer.o
+obj-y += pinmux.o
+obj-y += clock.o
+obj-y += clkdev.o
+obj-y += board_letcool.o
+obj-y += adc.o
+obj-y += pwm.o
diff --git a/arch/arm/mach-spmp8000/Makefile.boot b/arch/arm/mach-spmp8000/Makefile.boot
new file mode 100644
index 0000000..dae9661
--- /dev/null
+++ b/arch/arm/mach-spmp8000/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y := 0x00008000
diff --git a/arch/arm/mach-spmp8000/core.c b/arch/arm/mach-spmp8000/core.c
new file mode 100644
index 0000000..ba05614
--- /dev/null
+++ b/arch/arm/mach-spmp8000/core.c
@@ -0,0 +1,103 @@
+/*
+ * SPMP8000 machines core functions
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/vic.h>
+#include <mach/hardware.h>
+#include <mach/scu.h>
+
+/* Static mappings:
+ * SCU: timer needs clk support which is inited in init_early
+ * UART: needed for earlyprintk
+ */
+static struct map_desc io_desc[] __initdata = {
+ {
+ .virtual = IO_ADDRESS(SPMP8000_SCU_A_BASE),
+ .pfn = __phys_to_pfn(SPMP8000_SCU_A_BASE),
+ .length = SPMP8000_SCU_A_SIZE,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(SPMP8000_SCU_B_BASE),
+ .pfn = __phys_to_pfn(SPMP8000_SCU_B_BASE),
+ .length = SPMP8000_SCU_B_SIZE,
+ .type = MT_DEVICE,
+ }, {
+ .virtual = IO_ADDRESS(SPMP8000_SCU_C_BASE),
+ .pfn = __phys_to_pfn(SPMP8000_SCU_C_BASE),
+ .length = SPMP8000_SCU_C_SIZE,
+ .type = MT_DEVICE,
+ },
+#ifdef CONFIG_DEBUG_LL
+ {
+ .virtual = IO_ADDRESS(SPMP8000_UARTC0_BASE),
+ .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
+ .length = SPMP8000_UARTC0_SIZE,
+ .type = MT_DEVICE,
+ },
+#endif
+};
+
+#define IO_PTR(x) ((void __iomem *)IO_ADDRESS(x))
+/* Make the lookup of SCU base and clk enable registers easy for the clk
+ * code, as they are not at the same offset in each controller */
+struct scu_reg_t scu_regs[3] = {
+ { /* SCU_A */
+ .base = IO_PTR(SPMP8000_SCU_A_BASE),
+ .clken = IO_PTR(SPMP8000_SCU_A_BASE) + SCU_A_PERI_CLKEN,
+ },
+ { /* SCU_B */
+ .base = IO_PTR(SPMP8000_SCU_B_BASE),
+ .clken = IO_PTR(SPMP8000_SCU_B_BASE) + SCU_B_PERI_CLKEN,
+ },
+ { /* SCU_C */
+ .base = IO_PTR(SPMP8000_SCU_C_BASE),
+ .clken = IO_PTR(SPMP8000_SCU_C_BASE) + SCU_C_PERI_CLKEN,
+ },
+};
+
+/* DMA controller names to be used for the filter
+ * function of the DMA-Engine API. */
+char *spmp8000_dma_controller_names[] = {
+ "93010000.dma", /* APBDMA_A */
+ "92b00000.dma", /* APBDMA_C */
+};
+
+void __init spmp8000_map_io(void)
+{
+ iotable_init(io_desc, ARRAY_SIZE(io_desc));
+}
+
+void __init spmp8000_init_irq(void)
+{
+ struct device_node *np;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "arm,pl192");
+ if (!np)
+ panic("Can't find VIC0 interrupt controller\n");
+
+ ret = vic_of_init(np, NULL);
+ if (ret)
+ panic("Can't init VIC0 interrupt controller\n");
+
+ np = of_find_compatible_node(np, NULL, "arm,pl192");
+ if (!np)
+ panic("Can't find VIC1 interrupt controller\n");
+
+ ret = vic_of_init(np, NULL);
+ if (ret)
+ panic("Can't init VIC1 interrupt controller\n");
+
+ of_node_put(np);
+}
diff --git a/arch/arm/mach-spmp8000/include/mach/core.h b/arch/arm/mach-spmp8000/include/mach/core.h
new file mode 100644
index 0000000..fa1d522
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/core.h
@@ -0,0 +1,29 @@
+/*
+ * SPMP8000 generic includes
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_GENERIC_H__
+#define __MACH_SPMP8000_GENERIC_H__
+
+/* core.c */
+extern void __init spmp8000_map_io(void);
+extern void __init spmp8000_init_irq(void);
+extern struct sys_timer spmp8000_sys_timer;
+
+/* clkdev.c */
+extern void __init spmp8000_init_clkdev(void);
+extern void spmp8000_update_arm_freqs(void); /* For cpufreq driver */
+
+/* pinmux.c */
+extern void spmp8000_pinmux_pgc_set(int pc, unsigned int conf);
+extern unsigned int spmp8000_pinmux_pgc_get(int pc);
+extern void spmp8000_pinmux_pgs_set(unsigned int pg, unsigned int func);
+extern int spmp8000_pinmux_pgs_get(int pg);
+
+#endif /* __MACH_SPMP8000_GENERIC_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/debug-macro.S b/arch/arm/mach-spmp8000/include/mach/debug-macro.S
new file mode 100644
index 0000000..698c37e
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/debug-macro.S
@@ -0,0 +1,19 @@
+/*
+ * SPMP8000 debug-macro.S
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+ .macro addruart, rp, rv
+ mov \rp, #0x92000000
+ add \rp, #0x00B00000
+ add \rp, #0x00004000
+ orr \rv, \rp, #0xF0000000
+ .endm
+
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-spmp8000/include/mach/dma.h b/arch/arm/mach-spmp8000/include/mach/dma.h
new file mode 100644
index 0000000..44bc9f2
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/dma.h
@@ -0,0 +1,45 @@
+/*
+ * SPMP8000 dma.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+
+#ifndef __MACH_SPMP8000_DMA_H__
+#define __MACH_SPMP8000_DMA_H__
+
+enum spmp8000_dma_controller {
+ SPMP8000_APBDMA_A = 0,
+ SPMP8000_APBDMA_C,
+};
+
+extern char *spmp8000_dma_controller_names[];
+
+struct spmp8000_dma_params {
+ char *dma_controller;
+ dma_addr_t dma_address;
+ enum dma_slave_buswidth dma_width;
+ int maxburst;
+};
+
+/* Driver parameters */
+#define SPMP8000_APBDMA_MAX_PERIODS 64
+
+static bool spmp8000_dma_filter(struct dma_chan *chan, const char *name)
+{
+ int ret;
+
+ ret = strcmp(dev_name(chan->device->dev), name);
+
+ if (ret)
+ return false;
+
+ return true;
+}
+
+#endif /* __MACH_SPMP8000_DMA_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/entry-macro.S b/arch/arm/mach-spmp8000/include/mach/entry-macro.S
new file mode 100644
index 0000000..3d26088
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/entry-macro.S
@@ -0,0 +1,14 @@
+/*
+ * SPMP8000 entry-macro.S
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+ .macro disable_fiq
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h b/arch/arm/mach-spmp8000/include/mach/gpio.h
new file mode 100644
index 0000000..3eafac2
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/gpio.h
@@ -0,0 +1,21 @@
+/*
+ * SPMP8000 machines gpio support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_GPIO_H__
+#define __MACH_SPMP8000_GPIO_H__
+
+#include <asm-generic/gpio.h>
+
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#define gpio_to_irq __gpio_to_irq
+
+#endif /* __MACH_SPMP8000_GPIO_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/hardware.h b/arch/arm/mach-spmp8000/include/mach/hardware.h
new file mode 100644
index 0000000..998a184
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/hardware.h
@@ -0,0 +1,27 @@
+/*
+ * SPMP8000 hardware.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_HARDWARE_H__
+#define __MACH_SPMP8000_HARDWARE_H__
+
+/* Vitual to physical translation of statically mapped space */
+#define IO_ADDRESS(x) ((x) | 0xF0000000)
+
+/* Needed for the static mappings and uncompress.h */
+#define SPMP8000_UARTC0_BASE 0x92B04000
+#define SPMP8000_UARTC0_SIZE SZ_4K
+#define SPMP8000_SCU_C_BASE 0x92005000
+#define SPMP8000_SCU_C_SIZE SZ_4K
+#define SPMP8000_SCU_A_BASE 0x93007000
+#define SPMP8000_SCU_A_SIZE SZ_4K
+#define SPMP8000_SCU_B_BASE 0x90005000
+#define SPMP8000_SCU_B_SIZE SZ_4K
+
+#endif /* __MACH_SPMP8000_HARDWARE_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/io.h b/arch/arm/mach-spmp8000/include/mach/io.h
new file mode 100644
index 0000000..a8ea8f0
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/io.h
@@ -0,0 +1,20 @@
+/*
+ * SPMP8000 io.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_IO_H__
+#define __MACH_SPMP8000_IO_H__
+
+/* FIXME This should go away */
+#define IO_SPACE_LIMIT 0
+
+#define __mem_pci(a) (a)
+#define __io(a) __typesafe_io(a)
+
+#endif /* __MACH_SPMP8000_IO_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/irqs.h b/arch/arm/mach-spmp8000/include/mach/irqs.h
new file mode 100644
index 0000000..7f305d3
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/irqs.h
@@ -0,0 +1,21 @@
+/*
+ * SPMP8000 irqs.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_IRQS_H__
+#define __MACH_SPMP8000_IRQS_H__
+
+#define SPMP8000_HW_IRQS 64
+#define SPMP8000_GPIO_IRQS_START SPMP8000_HW_IRQS
+#define SPMP8000_GPIO_IRQS (16 + 32)
+#define SPMP8000_TOTAL_IRQS (SPMP8000_HW_IRQS + SPMP8000_GPIO_IRQS)
+
+#define NR_IRQS SPMP8000_TOTAL_IRQS
+
+#endif /* __MACH_SPMP8000_IRQS_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/memory.h b/arch/arm/mach-spmp8000/include/mach/memory.h
new file mode 100644
index 0000000..d2f1089
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/memory.h
@@ -0,0 +1,16 @@
+/*
+ * SPMP8000 memory.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_MEMORY_H__
+#define __MACH_SPMP8000_MEMORY_H__
+
+#define PLAT_PHYS_OFFSET UL(0x00000000)
+
+#endif /* __MACH_SPMP8000_MEMORY_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/regs-timer.h b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
new file mode 100644
index 0000000..90735df
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
@@ -0,0 +1,32 @@
+/*
+ * SPMP8000 timer support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * These timer reg definitions are used by the timer and pwm drivers
+ */
+#ifndef __MACH_SPMP8000_REGS_TIMER_H__
+#define __MACH_SPMP8000_REGS_TIMER_H__
+
+#define SPMP8000_TMRB(tnum) (tnum * 0x20)
+#define SPMP8000_TMRB_CTR 0x00
+#define SPMP8000_TMRB_CTR_TE BIT(0)
+#define SPMP8000_TMRB_CTR_IE BIT(1)
+#define SPMP8000_TMRB_CTR_OE BIT(2)
+#define SPMP8000_TMRB_CTR_PWMON BIT(3)
+#define SPMP8000_TMRB_CTR_UD BIT(4)
+#define SPMP8000_TMRB_CTR_UDS BIT(5)
+#define SPMP8000_TMRB_CTR_OM BIT(6)
+#define SPMP8000_TMRB_CTR_ES_SH 8
+#define SPMP8000_TMRB_CTR_M_SH 10
+#define SPMP8000_TMRB_PSR 0x04
+#define SPMP8000_TMRB_LDR 0x08
+#define SPMP8000_TMRB_VLR 0x08
+#define SPMP8000_TMRB_ISR 0x0C
+#define SPMP8000_TMRB_CMP 0x10
+
+#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/scu.h b/arch/arm/mach-spmp8000/include/mach/scu.h
new file mode 100644
index 0000000..e3a98d4
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/scu.h
@@ -0,0 +1,146 @@
+/*
+ * SPMP8000 System Control Unit register definitions
+ * SCUs are a random collection of reset, clock, gpio, pinmux, etc. controllers
+ * so that these definitions are needed at several places.
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/bitops.h>
+#include <mach/hardware.h>
+
+#ifndef __MACH_SPMP8000_SCU_H__
+#define __MACH_SPMP8000_SCU_H__
+
+/* Used by to the clock code to directly access the SCU base and clock
+ * enabling registers, without looking up the according registers first.
+ */
+struct scu_reg_t {
+ void *base;
+ void *clken;
+};
+
+extern struct scu_reg_t scu_regs[];
+
+#define REG_SCU_BASE(x) scu_regs[x].base
+#define REG_SCU_CLKEN(x) scu_regs[x].clken
+#define REG_SCU_A_ID 0
+#define REG_SCU_B_ID 1
+#define REG_SCU_C_ID 2
+#define REG_SCU_A(x) (scu_regs[REG_SCU_A_ID].base + x)
+#define REG_SCU_B(x) (scu_regs[REG_SCU_B_ID].base + x)
+#define REG_SCU_C(x) (scu_regs[REG_SCU_C_ID].base + x)
+
+#define SCU_A_PERI_RST 0x00
+#define SCU_A_PERI_CLKEN 0x04
+#define SCU_A_PERI_DGCLKEN 0x0C
+
+#define SCU_A_APLL_CFG 0x44
+#define APLL_CFG_P BIT(0)
+#define APLL_CFG_S BIT(1)
+#define APLL_CFG_F BIT(2)
+#define APLL_CFG_E BIT(3)
+#define APLL_CFG_AS_MASK 0x3F0
+#define APLL_CFG_AS_SHIFT 4
+#define APLL_CFG_AS_MAGIC 0x12
+#define APLL_CFG_C BIT(10)
+#define APLL_CFG_R BIT(11)
+#define APLL_CFG_DAR_SHIFT 16
+#define APLL_CFG_DAR_MASK (7 << APLL_CFG_DAR_SHIFT)
+#define APLL_CFG_DS BIT(19)
+#define APLL_CFG_ADR_SHIFT 24
+#define APLL_CFG_ADR_MASK (7 << APLL_CFG_ADR_SHIFT)
+#define APLL_CFG_AS BIT(27)
+
+#define SCU_A_LCD_CLK_CFG 0x80
+#define LCD_CLK_CFG_RATIO_MASK 0xFF
+#define LCD_CLK_CFG_EN BIT(8)
+#define SCU_A_CSI_CLK_CFG 0x84
+#define CSI_CLK_CFG_RATIO_MASK 0xFF
+#define CSI_CLK_CFG_EN BIT(8)
+#define SCU_A_I2S_BCK_CFG 0x90
+#define I2S_BCK_CFG_RATIO_MASK 0xFF
+#define I2S_BCK_CFG_EN BIT(8)
+#define SCU_A_UART_CFG 0x94
+#define UART_CFG_RATIO_MASK 0xFF
+#define UART_CFG_EN BIT(8)
+#define DIVIDER_ENABLE_BIT BIT(8)
+
+#define SCU_A_CODEC_CFG 0xB0
+#define SCU_A_CODEC_CFG_VAL 0x5A
+
+#define SCU_A_SAR_GPIO_CTRL 0xE0
+#define SCU_A_SAR_GPIO_OEN 0xE4
+#define SCU_A_SAR_GPIO_O 0xE8
+#define SCU_A_SAR_GPIO_I 0xEC
+
+#define SCU_B_PERI_RST 0x00
+#define SCU_B_PERI_CLKEN 0x20
+#define SCU_B_PERI_DGCLKEN 0x24
+#define SCU_B_UPDATE_ARM_RATIO 0x28
+
+#define SCU_B_SPLL_CFG 0x04
+#define SPLL_CFG_R_MASK 3
+#define SPLL_CFG_R_SHIFT 0
+#define SPLL_CFG_F_MASK 0xFC
+#define SPLL_CFG_F_SHIFT 2
+#define SPLL_CFG_BS BIT(8)
+#define SPLL_CFG_OD BIT(9)
+#define SPLL_CFG_BP BIT(10)
+#define SPLL_CFG_PD BIT(11)
+#define SPLL_CFG_CSEL_MASK (BIT(13) | BIT(12))
+#define SPLL_CFG_CSEL_SHIFT 12
+#define SPLL_CFG_ASEL_MASK (BIT(15) | BIT(14))
+#define SPLL_CFG_ASEL_SHIFT 14
+#define SPLL_CFG_SE BIT(17)
+#define SPLL_CFG_XE BIT(18)
+#define SPLL_CFG_AE BIT(19)
+#define SPLL_CFG_XR BIT(20)
+#define SPLL_CFG_PL BIT(31)
+
+#define SCU_B_GPIO3_I 0x70
+#define SCU_B_GPIO3_O 0x74
+#define SCU_B_GPIO3_E 0x78
+
+#define SCU_B_PGS0 0x80
+#define SCU_B_PGS1 0x84
+#define SCU_B_PGS2 0x88
+#define SCU_B_PGS3 0x8C
+#define SCU_B_PGC0 0x90
+#define SCU_B_PGC1 0x94
+#define SCU_B_PGC2 0x98
+#define SCU_B_PGC3 0x9C
+
+#define SCU_B_ARM_RATIO 0xD0
+#define SCU_B_ARM_AHB_RATIO 0xD4
+#define SCU_B_ARM_APB_RATIO 0xD8
+#define SCU_B_SYS_CNT_EN 0xDC
+#define SYS_CNT_EN_SYS BIT(0)
+#define SYS_CNT_EN_SYS_RT BIT(1)
+#define SYS_CNT_EN_SYS_AHB BIT(2)
+#define SYS_CNT_EN_SYS_APB BIT(3)
+#define SYS_CNT_EN_SYS_CHECK BIT(31)
+
+#define SCU_C_PERI_RST 0x00
+#define SCU_C_PERI_CLKEN 0x04
+#define SCU_C_PERI_DGCLKEN 0x08
+
+#define SCU_C_UPDATE_SYS_RATIO 0x28
+#define SCU_C_SYS_RATIO 0x100
+#define SCU_C_SYS_RT_RATIO 0x104
+#define SCU_C_SYS_AHB_RATIO 0x108
+#define SCU_C_SYS_APB_RATIO 0x10C
+#define SCU_C_CEVA_RATIO 0x110
+#define SCU_C_CEVA_AHB_RATIO 0x114
+#define SCU_C_CEVA_APB_RATIO 0x118
+#define SCU_C_CEVA_CNT_EN 0x11C
+#define CEVA_CNT_EN_CEVA BIT(0)
+#define CEVA_CNT_EN_CEVA_AHB BIT(1)
+#define CEVA_CNT_EN_CEVA_APB BIT(2)
+#define CEVA_CNT_EN_CEVA_CHECK BIT(31)
+
+#endif /* __MACH_SPMP8000_SCU_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/system.h b/arch/arm/mach-spmp8000/include/mach/system.h
new file mode 100644
index 0000000..be53ff3
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/system.h
@@ -0,0 +1,45 @@
+/*
+ * SPMP8000 system.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_SYSTEM_H__
+#define __MACH_SPMP8000_SYSTEM_H__
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+
+#define SPMP8000_WDT_BASE 0x90001000
+#define SPMP8000_WDT_SIZE 0x1000
+
+#define SPMP8000_WDT_CTR 0x00
+#define SPMP8000_WDT_CTR_TE BIT(0)
+#define SPMP8000_WDT_CTR_RE BIT(3)
+
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+ void *base;
+
+ base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
+ if (!base) {
+ pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
+ "Halt.");
+ while (1);
+ }
+
+ /* Trigger a watchdog reset */
+ writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
+ base + SPMP8000_WDT_CTR);
+}
+
+#endif /* __MACH_SPMP8000_SYSTEM_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/timex.h b/arch/arm/mach-spmp8000/include/mach/timex.h
new file mode 100644
index 0000000..77069c2
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/timex.h
@@ -0,0 +1,17 @@
+/*
+ * SPMP8000 timex.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_TIMEX_H__
+#define __MACH_SPMP8000_TIMEX_H__
+
+/* TODO this should go away */
+#define CLOCK_TICK_RATE (100 * HZ)
+
+#endif /* __MACH_SPMP8000_TIMEX_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/uncompress.h b/arch/arm/mach-spmp8000/include/mach/uncompress.h
new file mode 100644
index 0000000..105778b
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/uncompress.h
@@ -0,0 +1,37 @@
+/*
+ * SPMP8000 uncompress.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * Based on the mach-kirkwood implementation
+ *
+ * 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/serial_reg.h>
+#include <mach/hardware.h>
+
+#define SERIAL_BASE ((volatile unsigned char *)SPMP8000_UARTC0_BASE)
+
+static void putc(const char c)
+{
+ volatile unsigned char *base = SERIAL_BASE;
+ int i;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (base[UART_LSR << 2] & UART_LSR_THRE)
+ break;
+ barrier();
+ }
+
+ base[UART_TX << 2] = c;
+}
+
+static void flush(void)
+{
+}
+
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-spmp8000/include/mach/vmalloc.h b/arch/arm/mach-spmp8000/include/mach/vmalloc.h
new file mode 100644
index 0000000..ff40d1c
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * SPMP8000 vmalloc.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_VMALLOC_H__
+#define __MACH_SPMP8000_VMALLOC_H__
+
+#define VMALLOC_END 0xF0000000UL
+
+#endif /* __MACH_SPMP8000_VMALLOC_H__ */
diff --git a/arch/arm/mach-spmp8000/timer.c b/arch/arm/mach-spmp8000/timer.c
new file mode 100644
index 0000000..7d5d0eb
--- /dev/null
+++ b/arch/arm/mach-spmp8000/timer.c
@@ -0,0 +1,160 @@
+/*
+ * SPMP8000 machines timer functions
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <asm/mach/time.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-timer.h>
+#include <mach/irqs.h>
+
+static unsigned long clkrate;
+static const unsigned int tickrate = 1012500;
+
+/* The TIMER_B block is used as system timer
+ * T2: Clocksource
+ * T1: Clockevent
+ * T0: PWM for LCD backlight
+ * T3,4: Could be used as additional clockevent devices
+ * Timer constraints:
+ * - WDT: Can't clear the irq directly, only by resetting the whole counter
+ * in the ISR, which means that IRQs will jitter
+ * - Timer_B: Can't reset the timer value, so at start, the first IRQ
+ * will happen at some random time.
+ */
+#define CS_TIMER 2
+#define CE_TIMER 1
+static void __iomem *cs_base;
+static void __iomem *ce_base;
+
+static void tmrb_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel((tickrate / HZ), ce_base + SPMP8000_TMRB_LDR);
+ /* Configure as periodic, down counter, IEN, enable timer */
+ writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_IE |
+ (1 << SPMP8000_TMRB_CTR_M_SH),
+ ce_base + SPMP8000_TMRB_CTR);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ BUG();
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* Disable timer */
+ writel(0, ce_base + SPMP8000_TMRB_CTR);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ BUG();
+ break;
+ }
+}
+
+static struct clock_event_device tmrb1_clkevt = {
+ .name = "tmrb1",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .rating = 200,
+ .set_mode = tmrb_set_mode,
+};
+
+static irqreturn_t tmrb1_isr(int irq, void *dev_id)
+{
+ tmrb1_clkevt.event_handler(&tmrb1_clkevt);
+
+ /* Clear IRQ */
+ writel(0, ce_base + SPMP8000_TMRB_ISR);
+
+ return IRQ_HANDLED;
+};
+
+static struct irqaction tmrb1_irq = {
+ .name = "tmrb1_irq",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = tmrb1_isr,
+};
+
+static void __init spmp8000_sys_timer_init(void)
+{
+ struct device_node *np;
+ unsigned int irq;
+ struct clk *clk;
+ void *tmrb_base;
+
+ np = of_find_compatible_node(NULL, NULL, "sunplus,spmp8000-timer");
+ if (!np)
+ panic("spmp8000: unable to find timer node in dtb\n");
+
+ tmrb_base = of_iomap(np, 0);
+ if (!tmrb_base)
+ panic("spmp8000: unable to map timer cpu registers\n");
+
+ irq = of_irq_to_resource(np, CE_TIMER, NULL);
+ if (irq == NO_IRQ)
+ panic("spmp8000: unable to get interrupts of timer\n");
+
+ of_node_put(np);
+
+ cs_base = tmrb_base + SPMP8000_TMRB(CS_TIMER);
+ ce_base = tmrb_base + SPMP8000_TMRB(CE_TIMER);
+
+ clk = clk_get(NULL, "arm_apb");
+ if (IS_ERR_OR_NULL(clk))
+ panic("spmp8000: Can't get clock for timer device");
+
+ clk_enable(clk);
+ clkrate = clk_get_rate(clk);
+
+ /* Clocksource */
+ /* Disable timer */
+ writel(0, cs_base + SPMP8000_TMRB_CTR);
+
+ /* Reset counter value
+ * Not really possible unless setting end-1 LDR value and waiting
+ * until the counter reaches that */
+
+ /* Prescale timer */
+ writel((clkrate / tickrate) - 1, cs_base + SPMP8000_TMRB_PSR);
+
+ /* Register the clocksource */
+ clocksource_mmio_init(cs_base + SPMP8000_TMRB_VLR, "tmrb2",
+ tickrate, 200, 16, clocksource_mmio_readl_up);
+
+ /* Configure as free running (0 - 0xFFFF), up counter, enable timer */
+ writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_UD,
+ cs_base + SPMP8000_TMRB_CTR);
+
+ /* Clockevent */
+ setup_irq(irq, &tmrb1_irq);
+
+ /* Disable timer */
+ writel(0, ce_base + SPMP8000_TMRB_CTR);
+
+ /* Prescale timer */
+ writel((clkrate / tickrate) - 1, ce_base + SPMP8000_TMRB_PSR);
+
+ clockevents_register_device(&tmrb1_clkevt);
+}
+
+struct sys_timer spmp8000_sys_timer = {
+ .init = spmp8000_sys_timer_init,
+};
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 3/9] ARM: SPMP8000: Add clk support
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
2011-10-09 16:36 ` [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS Zoltan Devai
2011-10-09 16:36 ` [PATCH 2/9] ARM: SPMP8000: Add machine base files Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-13 9:38 ` Russell King - ARM Linux
2011-10-09 16:36 ` [PATCH 4/9] ARM: SPMP8000: Add ADC driver Zoltan Devai
` (8 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/clkdev.c | 586 +++++++++++++++++++++++++++
arch/arm/mach-spmp8000/clock.c | 155 +++++++
arch/arm/mach-spmp8000/include/mach/clock.h | 37 ++
3 files changed, 778 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/clkdev.c
create mode 100644 arch/arm/mach-spmp8000/clock.c
create mode 100644 arch/arm/mach-spmp8000/include/mach/clock.h
diff --git a/arch/arm/mach-spmp8000/clkdev.c b/arch/arm/mach-spmp8000/clkdev.c
new file mode 100644
index 0000000..c492d20
--- /dev/null
+++ b/arch/arm/mach-spmp8000/clkdev.c
@@ -0,0 +1,586 @@
+/*
+ * SPMP8000 machines clock support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <mach/clock.h>
+#include <mach/scu.h>
+
+/* The SoC doesn't support anything else, so no need to make these machine
+ * configurable.
+ */
+#define XTAL_FREQ 27000000UL
+#define XTAL_32K_FREQ 32768UL
+#define APLL_48K_FREQ 73728000UL
+#define APLL_44K_FREQ 67737600UL
+
+static unsigned long spll_get_rate(struct clk *clk)
+{
+ unsigned int f, r, od;
+ unsigned long osc;
+ u32 cfg;
+
+ cfg = readl(REG_SCU_B(SCU_B_SPLL_CFG));
+ osc = XTAL_FREQ;
+
+ /* SPLL off ? */
+ if ((cfg & (SPLL_CFG_XR | SPLL_CFG_PD | SPLL_CFG_BP)) ||
+ (~cfg & (SPLL_CFG_PL | SPLL_CFG_XE | SPLL_CFG_SE))) {
+ return 0;
+ }
+
+ f = (cfg & SPLL_CFG_F_MASK) >> SPLL_CFG_F_SHIFT;
+ r = (cfg & SPLL_CFG_R_MASK) >> SPLL_CFG_R_SHIFT;
+ od = !!(cfg & SPLL_CFG_OD);
+ clk->rate = (osc * (f + 1) * 2) / ((r + 1) * (od + 1));
+
+ return clk->rate;
+}
+
+static unsigned long pll_mux_get_rate(int ratesel, struct clk *clk)
+{
+ int pll_rate;
+
+ switch (ratesel) {
+ case 0:
+ clk->rate = XTAL_FREQ;
+ break;
+ case 1:
+ clk->rate = XTAL_32K_FREQ;
+ break;
+ case 2:
+ pll_rate = clk_get_rate(clk->parent);
+ clk->rate = pll_rate / 2;
+ break;
+ case 3:
+ pll_rate = clk_get_rate(clk->parent);
+ clk->rate = pll_rate / 3;
+ break;
+ }
+
+ return clk->rate;
+}
+
+static unsigned long ref_arm_get_rate(struct clk *clk)
+{
+ int ratesel;
+ u32 spll_cfg;
+
+ spll_cfg = readl(REG_SCU_B(SCU_B_SPLL_CFG));
+ ratesel = (spll_cfg & SPLL_CFG_ASEL_MASK) >> SPLL_CFG_ASEL_SHIFT;
+ return pll_mux_get_rate(ratesel, clk);
+}
+
+static unsigned long ref_ceva_get_rate(struct clk *clk)
+{
+ int ratesel;
+ u32 spll_cfg;
+
+ spll_cfg = readl(REG_SCU_B(SCU_B_SPLL_CFG));
+ ratesel = (spll_cfg & SPLL_CFG_CSEL_MASK) >> SPLL_CFG_CSEL_SHIFT;
+ return pll_mux_get_rate(ratesel, clk);
+}
+
+static unsigned long apll_get_rate(void)
+{
+ u32 cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+
+ if ((cfg & APLL_CFG_R) || (~cfg & (APLL_CFG_P | APLL_CFG_E)) ||
+ (((cfg & APLL_CFG_AS_MASK) >> APLL_CFG_AS_SHIFT)
+ != APLL_CFG_AS_MAGIC)) {
+ return 0;
+ }
+
+ /* Not dealing with the input oscillator frequency as the settings
+ * for non-27Mhz are unknown, and all platforms use that anyway */
+ if (cfg & APLL_CFG_S)
+ return APLL_44K_FREQ;
+ else
+ return APLL_48K_FREQ;
+}
+
+static void apll_enable(struct clk *clk)
+{
+ u32 cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+
+ /* Store new config with reset, then disable reset */
+ cfg |= APLL_CFG_R;
+ cfg |= APLL_CFG_E | APLL_CFG_P | APLL_CFG_F;
+ cfg |= APLL_CFG_AS_MAGIC << APLL_CFG_AS_SHIFT;
+
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+
+ cfg &= ~APLL_CFG_R;
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+}
+
+static void apll_disable(struct clk *clk)
+{
+ u32 cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+
+ cfg &= ~APLL_CFG_P;
+ cfg |= APLL_CFG_E;
+
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+}
+
+static int apll_set_rate(unsigned long rate)
+{
+ u32 cfg;
+
+ cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+
+ switch (rate) {
+ case 67737600:
+ cfg |= APLL_CFG_S;
+ break;
+ case 73728000:
+ cfg &= ~APLL_CFG_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+
+ return 0;
+}
+
+static void i2s_mck_switch(u32 mask, int enable)
+{
+ u32 cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+ if (enable)
+ cfg &= ~mask;
+ else
+ cfg |= mask;
+
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+}
+
+static void i2stx_mck_enable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_DS, 1);
+}
+
+static void i2stx_mck_disable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_DS, 0);
+}
+
+static void i2srx_mck_enable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_AS, 1);
+}
+
+static void i2srx_mck_disable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_AS, 0);
+}
+
+static const int apll_dividers[7] = {
+ 3, 6, 9, 12, 18, 24, 32,
+};
+
+static unsigned long i2s_mck_get_rate(struct clk *clk, u32 msk, u32 sh)
+{
+ unsigned long apll_rate = apll_get_rate();
+ u32 cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+ int divider;
+
+ divider = (cfg & msk) >> sh;
+
+ if (divider == ARRAY_SIZE(apll_dividers))
+ return 0;
+
+ divider = apll_dividers[divider];
+
+ return apll_rate / divider;
+}
+
+static unsigned long i2stx_mck_get_rate(struct clk *clk)
+{
+ return i2s_mck_get_rate(clk, APLL_CFG_DAR_MASK, APLL_CFG_DAR_SHIFT);
+}
+
+static unsigned long i2srx_mck_get_rate(struct clk *clk)
+{
+ return i2s_mck_get_rate(clk, APLL_CFG_ADR_MASK, APLL_CFG_ADR_SHIFT);
+}
+
+static int i2s_mck_set_rate(struct clk *clk, unsigned long rate,
+ u32 msk, u32 sh)
+{
+ int i = ARRAY_SIZE(apll_dividers) - 1;
+ unsigned long apll_rate;
+ int divider = -1;
+ u32 cfg;
+
+ /* Set up APLL */
+ if (rate % 8000)
+ apll_rate = APLL_44K_FREQ;
+ else
+ apll_rate = APLL_48K_FREQ;
+
+ apll_set_rate(apll_rate);
+
+ cfg = readl(REG_SCU_A(SCU_A_APLL_CFG));
+
+ /* Get the biggest possible divider for MCK */
+ while (i >= 0) {
+ if (apll_rate / apll_dividers[i] == rate) {
+ divider = apll_dividers[i];
+ break;
+ }
+
+ i--;
+ }
+
+ if (divider < 0)
+ return -EINVAL;
+
+ cfg &= ~msk;
+ cfg |= (i << sh);
+
+ writel(cfg, REG_SCU_A(SCU_A_APLL_CFG));
+
+ return 0;
+}
+
+static int i2stx_mck_set_rate(struct clk *clk, unsigned long rate)
+{
+ return i2s_mck_set_rate(clk, rate,
+ APLL_CFG_DAR_MASK, APLL_CFG_DAR_SHIFT);
+}
+
+static int i2srx_mck_set_rate(struct clk *clk, unsigned long rate)
+{
+ return i2s_mck_set_rate(clk, rate,
+ APLL_CFG_ADR_MASK, APLL_CFG_ADR_SHIFT);
+}
+
+static int divider_set_clock(struct clk *clk, int on)
+{
+ u32 divider;
+
+ if (!(clk->flags & CLK_DIVIDER_WITH_ENABLE))
+ return -EINVAL;
+
+ divider = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
+ if (on)
+ divider |= DIVIDER_ENABLE_BIT;
+ else
+ divider = 0;
+ writel(divider, REG_SCU_BASE(clk->scu) + clk->dividerreg);
+
+ return 0;
+}
+
+static void divider_enable_clock(struct clk *clk)
+{
+ divider_set_clock(clk, 1);
+}
+
+static void divider_disable_clock(struct clk *clk)
+{
+ divider_set_clock(clk, 0);
+}
+
+static unsigned long divider_get_rate(struct clk *clk)
+{
+ u32 divider;
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+
+ if (!parent_rate) {
+ clk->rate = 0;
+ return clk->rate;
+ }
+
+ divider = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
+ if ((clk->flags & CLK_DIVIDER_WITH_ENABLE) &&
+ !(divider & DIVIDER_ENABLE_BIT)) {
+ clk->rate = 0UL;
+ return clk->rate;
+ }
+
+ clk->rate = parent_rate / ((divider & clk->divmask) + 1);
+
+ return clk->rate;
+}
+
+static int divider_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+ u32 divider, divider_old;
+
+ if (unlikely(!parent_rate || rate > parent_rate)) {
+ clk->rate = 0;
+ pr_debug("parent rate not sufficient\n");
+ return -EINVAL;
+ }
+
+ divider = (parent_rate / rate) - 1;
+
+ if (divider > clk->divmask) {
+ pr_debug("input clock too high\n");
+ return -EINVAL;
+ };
+
+ divider_old = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
+ writel(0, REG_SCU_BASE(clk->scu) + clk->dividerreg);
+ writel(divider, REG_SCU_BASE(clk->scu) + clk->dividerreg);
+
+ /* Re-enable clock if it was enabled before */
+ if (divider_old & DIVIDER_ENABLE_BIT)
+ writel(divider | DIVIDER_ENABLE_BIT,
+ REG_SCU_BASE(clk->scu) + clk->dividerreg);
+
+ clk->rate = parent_rate / (divider + 1);
+
+ return 0;
+}
+static void periph_enable_clock(struct clk *clk)
+{
+ u32 scu_reg = readl(REG_SCU_CLKEN(clk->scu));
+
+ scu_reg |= (1 << clk->scu_periph_id);
+
+ writel(scu_reg, REG_SCU_CLKEN(clk->scu));
+}
+
+static void periph_disable_clock(struct clk *clk)
+{
+ u32 scu_reg = readl(REG_SCU_CLKEN(clk->scu));
+
+ scu_reg &= ~(1 << clk->scu_periph_id);
+
+ writel(scu_reg, REG_SCU_CLKEN(clk->scu));
+}
+
+void spmp8000_update_arm_freqs(void)
+{
+ writel(7, REG_SCU_B(SCU_B_UPDATE_ARM_RATIO));
+}
+EXPORT_SYMBOL(spmp8000_update_arm_freqs);
+
+static struct clk clk_spll = {
+ .get_rate = spll_get_rate,
+ .flags = CLK_FIXED_RATE,
+};
+
+static struct clk clk_ref_arm = {
+ .parent = &clk_spll,
+ .get_rate = ref_arm_get_rate,
+};
+
+static struct clk clk_ref_ceva = {
+ .parent = &clk_spll,
+ .get_rate = ref_ceva_get_rate,
+};
+
+static struct clk clk_apll = {
+ .name = "clk_apll",
+ .enable = apll_enable,
+ .disable = apll_disable,
+};
+
+static struct clk clk_i2stx_mck = {
+ .name = "clk_i2stx_mck",
+ .parent = &clk_apll,
+ .enable = i2stx_mck_enable,
+ .disable = i2stx_mck_disable,
+ .get_rate = i2stx_mck_get_rate,
+ .set_rate = i2stx_mck_set_rate,
+};
+
+static struct clk clk_i2srx_mck = {
+ .name = "clk_i2srx_mck",
+ .parent = &clk_apll,
+ .enable = i2srx_mck_enable,
+ .disable = i2srx_mck_disable,
+ .get_rate = i2srx_mck_get_rate,
+ .set_rate = i2srx_mck_set_rate,
+};
+
+#define SYSTEM_CLK(__name, __parent, __scu, __divider, __divmask, __flags) \
+static struct clk clk_##__name = { \
+ .name = "clk_" #__name, \
+ .parent = &clk_##__parent, \
+ .scu = REG_SCU_##__scu##_ID, \
+ .dividerreg = __divider, \
+ .divmask = __divmask, \
+ .flags = __flags, \
+ .enable = ÷r_enable_clock, \
+ .disable = ÷r_disable_clock, \
+ .get_rate = ÷r_get_rate, \
+ .set_rate = ÷r_set_rate, \
+}
+
+SYSTEM_CLK(arm, ref_arm, B, SCU_B_ARM_RATIO, 0x3F, 0);
+SYSTEM_CLK(arm_ahb, arm, B, SCU_B_ARM_AHB_RATIO, 0x3F, 0);
+SYSTEM_CLK(arm_apb, arm_ahb, B, SCU_B_ARM_APB_RATIO, 0x3F, 0);
+SYSTEM_CLK(ceva, ref_ceva, C, SCU_C_CEVA_RATIO, 0x3F, 0);
+SYSTEM_CLK(ceva_ahb, ceva, C, SCU_C_CEVA_AHB_RATIO, 0x3F, 0);
+SYSTEM_CLK(ceva_apb, ceva_ahb, C, SCU_C_CEVA_APB_RATIO, 0x3F, 0);
+SYSTEM_CLK(sys, ref_ceva, C, SCU_C_SYS_RATIO, 0x3F, 0);
+SYSTEM_CLK(sys_ahb, sys, C, SCU_C_SYS_AHB_RATIO, 0x3F, 0);
+SYSTEM_CLK(sys_apb, sys_ahb, C, SCU_C_SYS_APB_RATIO, 0x3F, 0);
+
+SYSTEM_CLK(uart, ref_ceva, A, SCU_A_UART_CFG, 0xFF, CLK_DIVIDER_WITH_ENABLE);
+SYSTEM_CLK(lcd, ref_ceva, A, SCU_A_LCD_CLK_CFG, 0xFF, CLK_DIVIDER_WITH_ENABLE);
+SYSTEM_CLK(csi, ref_ceva, A, SCU_A_CSI_CLK_CFG, 0xFF, CLK_DIVIDER_WITH_ENABLE);
+SYSTEM_CLK(i2srx_bck, i2srx_mck, A, SCU_A_I2S_BCK_CFG, 0xFF,
+ CLK_DIVIDER_WITH_ENABLE);
+SYSTEM_CLK(i2stx_bck, i2stx_mck, A, SCU_A_I2S_BCK_CFG, 0xFF,
+ CLK_DIVIDER_WITH_ENABLE);
+
+
+/* Peripherals */
+#define PERIPH_CLK(__name, __parent, __scu, __id) \
+static struct clk clk_##__name = { \
+ .name = "clk_" #__name, \
+ .parent = &__parent, \
+ .scu = REG_SCU_##__scu##_ID, \
+ .scu_periph_id = __id, \
+ .enable = periph_enable_clock, \
+ .disable = periph_disable_clock, \
+}
+
+/* Not needed yet for any driver */
+#if 0
+PERIPH_CLK(drm, clk_sys_ahb, A, 2);
+PERIPH_CLK(usb_host, clk_sys_ahb, A, 3);
+PERIPH_CLK(usb_device, clk_sys_ahb, A, 4);
+PERIPH_CLK(scu_a, clk_sys_ahb, A, 6);
+PERIPH_CLK(tvout, clk_sys, A, 7);
+PERIPH_CLK(csi_ctrl, clk_sys, A, 10);
+PERIPH_CLK(nand0, clk_sys_ahb, A, 11);
+PERIPH_CLK(nand1, clk_sys_ahb, A, 12);
+PERIPH_CLK(ecc, clk_sys_ahb, A, 13);
+PERIPH_CLK(uart_con, clk_sys_ahb, A, 15);
+PERIPH_CLK(aahbm212, clk_sys, A, 16);
+PERIPH_CLK(nand_abt, clk_sys_ahb, A, 20);
+PERIPH_CLK(rt_abt212, clk_sys, A, 22);
+PERIPH_CLK(cahbm212, clk_sys, A, 23);
+
+PERIPH_CLK(tcm_bist, clk_arm, B, 0);
+PERIPH_CLK(tcm_ctrl, clk_arm, B, 1);
+PERIPH_CLK(ahb2ahb, clk_arm, B, 2);
+PERIPH_CLK(ahbsw, clk_arm, B, 3);
+PERIPH_CLK(vic0, clk_arm_ahb, B, 4);
+PERIPH_CLK(vic1, clk_arm_ahb, B, 5);
+PERIPH_CLK(dpm, clk_arm_ahb, B, 6);
+PERIPH_CLK(apbb, clk_arm_ahb, B, 7);
+PERIPH_CLK(arm926, clk_arm, B, 8);
+PERIPH_CLK(wdt, clk_arm_apb, B, 10);
+PERIPH_CLK(uartapb, clk_arm_apb, B, 11);
+PERIPH_CLK(i2c, clk_arm_apb, B, 12);
+PERIPH_CLK(rand, clk_arm_apb, B, 13);
+PERIPH_CLK(gpio0, clk_arm_apb, B, 14);
+PERIPH_CLK(rtc, clk_arm_apb, B, 15);
+
+PERIPH_CLK(fabricc, clk_sys, C, 0);
+PERIPH_CLK(dmac0, clk_sys, C, 1);
+PERIPH_CLK(dmac1, clk_sys, C, 2);
+PERIPH_CLK(dram_ctrl, clk_sys, C, 4);
+PERIPH_CLK(scu_c, clk_sys, C, 5);
+PERIPH_CLK(i2c_ctrl, clk_sys, C, 6);
+PERIPH_CLK(2d, clk_sys, C, 8);
+PERIPH_CLK(extmem, clk_sys, C, 9);
+PERIPH_CLK(cf, clk_sys_apb, C, 10);
+PERIPH_CLK(ms, clk_sys_apb, C, 11);
+PERIPH_CLK(intmem, clk_sys, C, 12);
+PERIPH_CLK(uartc0, clk_sys_apb, C, 13);
+PERIPH_CLK(uartc1, clk_sys_apb, C, 14);
+PERIPH_CLK(uartc2, clk_sys_apb, C, 15);
+PERIPH_CLK(ssp0, clk_sys_apb, C, 16);
+PERIPH_CLK(ssp1, clk_sys_apb, C, 17);
+PERIPH_CLK(sd1, clk_sys_apb, C, 19);
+PERIPH_CLK(i2c_sys, clk_sys_apb, C, 20);
+PERIPH_CLK(scale, clk_sys, C, 21);
+PERIPH_CLK(scaleabt, clk_sys, C, 22);
+PERIPH_CLK(ti2c, clk_sys_apb, C, 23);
+PERIPH_CLK(fabric_a, clk_sys, C, 24);
+PERIPH_CLK(cxmp_sl, clk_sys, C, 25);
+PERIPH_CLK(cxmd_sl, clk_sys, C, 26);
+#endif
+
+PERIPH_CLK(rt_abt, clk_sys, A, 21);
+/* Make the parent rt_abt to auto-enable it when enabling the lcdc clock */
+PERIPH_CLK(lcd_ctrl, clk_rt_abt, A, 1);
+PERIPH_CLK(apbdma_a, clk_rt_abt, A, 9);
+PERIPH_CLK(apll_ctrl, clk_sys_ahb, A, 14);
+PERIPH_CLK(i2stx_ctrl, clk_apbdma_a, A, 17);
+PERIPH_CLK(i2srx_ctrl, clk_apbdma_a, A, 18);
+PERIPH_CLK(saacc, clk_sys_apb, A, 19);
+
+PERIPH_CLK(tmrb, clk_arm_apb, B, 9);
+PERIPH_CLK(apbdma_c, clk_sys_apb, C, 7);
+PERIPH_CLK(sd0, clk_sys_apb, C, 18);
+
+/* TODO use common macro once available */
+#define _DEFINE_CLKDEV_CON(n) \
+ { \
+ .dev_id = NULL, \
+ .con_id = #n, \
+ .clk = &clk_##n, \
+ }
+
+#define _DEFINE_CLKDEV_DEV(d, c) \
+ { \
+ .dev_id = d, \
+ .con_id = NULL, \
+ .clk = &clk_##c, \
+ }
+
+static struct clk_lookup lookups[] = {
+ _DEFINE_CLKDEV_CON(arm),
+ _DEFINE_CLKDEV_CON(arm_ahb),
+ _DEFINE_CLKDEV_CON(arm_apb),
+ _DEFINE_CLKDEV_CON(ceva),
+ _DEFINE_CLKDEV_CON(ceva_ahb),
+ _DEFINE_CLKDEV_CON(ceva_apb),
+ _DEFINE_CLKDEV_CON(sys),
+ _DEFINE_CLKDEV_CON(sys_ahb),
+ _DEFINE_CLKDEV_CON(sys_apb),
+ _DEFINE_CLKDEV_CON(lcd),
+ _DEFINE_CLKDEV_CON(apbdma_a),
+ _DEFINE_CLKDEV_CON(saacc),
+ _DEFINE_CLKDEV_CON(i2stx_mck),
+ _DEFINE_CLKDEV_CON(i2srx_mck),
+ _DEFINE_CLKDEV_CON(i2stx_bck),
+ _DEFINE_CLKDEV_CON(i2srx_bck),
+ _DEFINE_CLKDEV_DEV("uart.0", uart),
+ _DEFINE_CLKDEV_DEV("uart.1", uart),
+ _DEFINE_CLKDEV_DEV("uart.2", uart),
+ _DEFINE_CLKDEV_DEV("93000000.fb", lcd_ctrl),
+ _DEFINE_CLKDEV_DEV("90000000.pwm", tmrb),
+ _DEFINE_CLKDEV_DEV("92b00000.dma", apbdma_c),
+ _DEFINE_CLKDEV_DEV("92b0b000.mmc", sd0),
+ _DEFINE_CLKDEV_DEV("93010000.dma", apbdma_a),
+ _DEFINE_CLKDEV_DEV("93012000.i2s", i2stx_ctrl),
+ _DEFINE_CLKDEV_DEV("9301d000.i2s", i2srx_ctrl),
+};
+
+void __init spmp8000_init_clkdev(void)
+{
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ /* Enable the apll control registers here, as the according clock
+ * isn't exported, but used by the mck/bck clocks. If we wouldn't
+ * enable it here, the freq of the pll couldn't be set up before
+ * enabling one of its child clocks.
+ * The PLL clock itself will be auto-enabled on demand by them.
+ */
+ clk_enable(&clk_apll_ctrl);
+}
diff --git a/arch/arm/mach-spmp8000/clock.c b/arch/arm/mach-spmp8000/clock.c
new file mode 100644
index 0000000..5652aff
--- /dev/null
+++ b/arch/arm/mach-spmp8000/clock.c
@@ -0,0 +1,155 @@
+/*
+ * Usual clk API boilerplate
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#include <mach/clock.h>
+
+static DEFINE_MUTEX(clocks_mutex);
+
+static void __clk_disable(struct clk *clk)
+{
+ BUG_ON(clk->refcount == 0);
+
+ if (!(--clk->refcount) && clk->disable) {
+ clk->disable(clk);
+ if (clk->parent)
+ __clk_disable(clk->parent);
+ }
+}
+
+static int __clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (clk->refcount++ == 0 && clk->enable) {
+ if (clk->parent)
+ ret = __clk_enable(clk->parent);
+ if (ret)
+ return ret;
+ else
+ clk->enable(clk);
+ }
+
+ return 0;
+}
+
+int clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ ret = __clk_enable(clk);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return;
+
+ mutex_lock(&clocks_mutex);
+ __clk_disable(clk);
+ mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return 0UL;
+
+ /* Is fixed and has been calculated already */
+ if ((clk->flags & CLK_FIXED_RATE) && clk->rate)
+ return clk->rate;
+
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
+ return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return 0;
+ if (unlikely(!clk->round_rate))
+ return 0;
+
+ return clk->round_rate(clk, rate);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EINVAL;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return ret;
+
+ if (unlikely(clk->flags & CLK_FIXED_RATE))
+ return ret;
+
+ if (unlikely(!clk->set_rate || !rate))
+ return ret;
+
+ mutex_lock(&clocks_mutex);
+ ret = clk->set_rate(clk, rate);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk *old;
+ int ret = -EINVAL;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return ret;
+ if (unlikely(!clk->set_parent || !parent))
+ return ret;
+
+ mutex_lock(&clocks_mutex);
+ old = clk->parent;
+ if (clk->refcount)
+ __clk_enable(parent);
+ ret = clk->set_parent(clk, parent);
+ if (ret)
+ old = parent;
+ if (clk->refcount)
+ __clk_disable(old);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return NULL;
+
+ return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
diff --git a/arch/arm/mach-spmp8000/include/mach/clock.h b/arch/arm/mach-spmp8000/include/mach/clock.h
new file mode 100644
index 0000000..e5cdbd2
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/clock.h
@@ -0,0 +1,37 @@
+/*
+ * SPMP8000 machines clock support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __MACH_SPMP8000_CLOCK_H__
+#define __MACH_SPMP8000_CLOCK_H__
+
+struct clk {
+ char *name;
+ unsigned long rate;
+ unsigned int id;
+ unsigned int refcount;
+ int scu;
+ int scu_periph_id;
+ int dividerreg;
+ int divmask;
+ unsigned long flags;
+/* Either really fixed rate (crystal) or which we don't change for sure */
+#define CLK_FIXED_RATE BIT(0)
+/* SPMP8000 has two types of dividers, one of them needs enabling */
+#define CLK_DIVIDER_WITH_ENABLE BIT(1)
+
+ struct clk *parent;
+ unsigned long (*get_rate)(struct clk *clk);
+ unsigned long (*round_rate) (struct clk *, u32);
+ int (*set_rate) (struct clk *, unsigned long);
+ int (*set_parent) (struct clk *clk, struct clk *parent);
+ void (*enable) (struct clk *);
+ void (*disable) (struct clk *);
+};
+
+#endif /* __MACH_SPMP8000_CLOCK_H__ */
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (2 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 3/9] ARM: SPMP8000: Add clk support Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-10 1:29 ` Linus Walleij
2011-10-09 16:36 ` [PATCH 5/9] ARM: SPMP8000: Add pinmux driver Zoltan Devai
` (7 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/adc.c | 465 +++++++++++++++++++++
arch/arm/mach-spmp8000/include/mach/spmp8000adc.h | 29 ++
2 files changed, 494 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/adc.c
create mode 100644 arch/arm/mach-spmp8000/include/mach/spmp8000adc.h
diff --git a/arch/arm/mach-spmp8000/adc.c b/arch/arm/mach-spmp8000/adc.c
new file mode 100644
index 0000000..c517116
--- /dev/null
+++ b/arch/arm/mach-spmp8000/adc.c
@@ -0,0 +1,465 @@
+/*
+ * SPMP8000 ADC support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <mach/spmp8000adc.h>
+#include <mach/scu.h>
+
+#define SARCTRL 0x00
+#define SARCTRL_BUSY BIT(21)
+#define SARCTRL_REF BIT(17)
+#define SARCTRL_TOG_EN BIT(16)
+#define SARCTRL_DIVNUM_OFF 8
+#define SARCTRL_DIVNUM_MASK 0xFF00
+#define SARCTRL_BACK2INT BIT(7)
+#define SARCTRL_TPS_OFF 5
+#define SARCTRL_TPS_MASK (3 << 5)
+#define SARCTRL_TPS_NOP 0
+#define SARCTRL_TPS_TEST 1
+#define SARCTRL_TPS_TP 2
+#define SARCTRL_TPS_INT 3
+#define SARCTRL_SARS_OFF 2
+#define SARCTRL_SARS_MASK (7 << 2)
+#define SARCTRL_SARS_TPXP 0
+#define SARCTRL_SARS_TPXN 1
+#define SARCTRL_SARS_TPYP 2
+#define SARCTRL_SARS_TPYN 3
+#define SARCTRL_SARS_SARIN4 4
+#define SARCTRL_SARS_SARIN5 5
+#define SARCTRL_SARS_SARIN6 6
+#define SARCTRL_SARS_SARIN7 7
+#define SARCTRL_MANCON BIT(1)
+#define SARCTRL_AUTOCON BIT(0)
+
+#define SARCONDLY 0x04
+#define SARAUTODLY 0x08
+#define SARDEBTIME 0x0C
+#define SARDEBTIME_DEBDLY_OFF 0
+#define SARDEBTIME_DEBDLY_MASK 0xFFFF
+#define SARDEBTIME_CHKDLY_OFF 16
+#define SARDEBTIME_CHKDLY_MASK 0xFFFF0000UL
+#define SARPNL 0x10
+#define SARAUX 0x14
+#define SARINTEN 0x18
+#define SARINTF 0x1C
+#define SARINT_NAUX BIT(3)
+#define SARINT_NPNL BIT(2)
+#define SARINT_PENUP BIT(1)
+#define SARINT_PENDOWN BIT(0)
+
+#define SAR_CLKRATE 400000UL
+#define ADC_CHANNELS 8
+
+struct spmp8000_adc {
+ void __iomem *reg_base;
+ struct device *dev;
+ struct clk *clk_apbdma;
+ struct clk *clk_saacc;
+ spinlock_t lock;
+ /* These are callbacks that get served with the measurement data
+ *@their according channel interrupt. */
+ struct spmp8000adc_client_chan *chan[ADC_CHANNELS];
+ /* Same for the touch-panel data */
+ struct spmp8000adc_client_tp *tp;
+};
+
+static struct spmp8000_adc *adc_dev;
+
+static int spmp8000adc_should_run(struct spmp8000_adc *adc)
+{
+ int i = ADC_CHANNELS - 1;
+
+ while (i-- >= 0) {
+ if (adc->chan[i])
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Starts or stops the ADC controller */
+static void spmp8000adc_ctrl(struct spmp8000_adc *adc, int start, int chan)
+{
+ u32 ctrl_reg;
+
+ ctrl_reg = readl(adc->reg_base + SARCTRL);
+
+ if (start) {
+ ctrl_reg &= ~SARCTRL_SARS_MASK;
+ ctrl_reg |= (chan << SARCTRL_SARS_OFF);
+ ctrl_reg |= (SARCTRL_TPS_TEST << SARCTRL_TPS_OFF) |
+ SARCTRL_MANCON;
+ } else
+ ctrl_reg &= ~SARCTRL_MANCON;
+
+ writel(ctrl_reg, adc->reg_base + SARCTRL);
+}
+
+/* Request an ADC channel to be measured. Measurement starts automatically
+ * when at least one channel is requested. IRQ code loops around all channels
+ * to be measured.
+ */
+int spmp8000adc_request_channel(unsigned int chan,
+ struct spmp8000adc_client_chan *c)
+{
+ struct spmp8000_adc *adc = adc_dev;
+ unsigned long flags;
+
+ if (chan > ADC_CHANNELS - 1)
+ return -EINVAL;
+
+ if (!c)
+ return -EINVAL;
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ if (adc->chan[chan]) {
+ spin_unlock_irqrestore(&adc->lock, flags);
+ return -EBUSY;
+ }
+
+ adc->chan[chan] = c;
+
+ if (spmp8000adc_should_run(adc))
+ spmp8000adc_ctrl(adc, 1, chan);
+
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(spmp8000adc_request_channel);
+
+/* Release an ADC channel. If no more channels are to be measured,
+ * the controller is shut down
+ */
+int spmp8000adc_release_channel(unsigned int chan)
+{
+ struct spmp8000_adc *adc = adc_dev;
+ unsigned long flags;
+
+ if (chan > ADC_CHANNELS - 1)
+ return -EINVAL;
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ if (!spmp8000adc_should_run(adc))
+ spmp8000adc_ctrl(adc, 0, 0);
+
+ adc->chan[chan] = NULL;
+
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(spmp8000adc_release_channel);
+
+/* Request touch panel measurement */
+int spmp8000adc_request_tp(struct spmp8000adc_client_tp *tp)
+{
+ struct spmp8000_adc *adc = adc_dev;
+ unsigned long flags;
+ u32 ctrl_reg;
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ if (adc->tp) {
+ spin_unlock_irqrestore(&adc->lock, flags);
+ return -EBUSY;
+ }
+
+ adc->tp = tp;
+
+ ctrl_reg = readl(adc->reg_base + SARCTRL);
+ ctrl_reg |= SARCTRL_AUTOCON;
+ writel(ctrl_reg, adc->reg_base + SARCTRL);
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(spmp8000adc_request_tp);
+
+/* Relase touch panel measurement */
+void spmp8000adc_release_tp(void)
+{
+ struct spmp8000_adc *adc = adc_dev;
+ unsigned long flags;
+ u32 ctrl_reg;
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ ctrl_reg = readl(adc->reg_base + SARCTRL);
+ ctrl_reg &= ~SARCTRL_AUTOCON;
+ writel(ctrl_reg, adc->reg_base + SARCTRL);
+ adc->tp = NULL;
+
+ spin_unlock_irqrestore(&adc->lock, flags);
+}
+EXPORT_SYMBOL(spmp8000adc_release_tp);
+
+static irqreturn_t spmp8000adc_irq(int irq, void *dev)
+{
+ struct spmp8000_adc *adc = dev;
+ void __iomem *regs = adc->reg_base;
+ u32 ints, ctrl;
+ s32 val_tp;
+ s16 val_chan;
+ int curchan;
+
+ ints = readl(regs + SARINTF);
+
+ dev_vdbg(adc->dev, "irq: %08X\n", ints);
+
+ if (unlikely(!ints))
+ return IRQ_NONE;
+
+ if (unlikely(ints & SARINT_PENDOWN))
+ dev_dbg(adc->dev, "IRQ: Pen down\n");
+
+ if (unlikely(ints & SARINT_PENUP))
+ dev_dbg(adc->dev, "IRQ: Pen up\n");
+
+ /* Channel measurement end in manual mode */
+ if (ints & SARINT_NAUX) {
+ spin_lock(&adc->lock);
+
+ ctrl = readl(regs + SARCTRL);
+ curchan = (ctrl & SARCTRL_SARS_MASK) >> SARCTRL_SARS_OFF;
+ dev_vdbg(adc->dev, "irq aux chan: %d\n", curchan);
+
+ /* The read also clears the interrupt */
+ val_chan = readl(regs + SARAUX);
+ if (adc->chan[curchan])
+ adc->chan[curchan]->cb(val_chan,
+ adc->chan[curchan]->priv);
+
+ if (!spmp8000adc_should_run(adc)) {
+ spin_unlock(&adc->lock);
+ return IRQ_HANDLED;
+ }
+
+ /* Select next channel */
+ curchan++;
+ if (curchan == ADC_CHANNELS - 1)
+ curchan = 0;
+
+ /* Set up next measurement */
+ spmp8000adc_ctrl(adc, 1, curchan);
+
+ spin_unlock(&adc->lock);
+ }
+
+ /* Touch panel measurement end in automatic mode */
+ if (ints & SARINT_NPNL) {
+ /* The read also clears the interrupt */
+ val_tp = readl(regs + SARPNL);
+ if (adc->tp)
+ adc->tp->cb(val_tp, adc->tp->priv);
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static int __devinit spmp8000adc_probe(struct platform_device *pdev)
+{
+ struct spmp8000_adc *adc;
+ struct clk *clk_apbdma, *clk_saacc;
+ unsigned long clkrate;
+ struct resource *r;
+ int ret, irq;
+
+ if (adc_dev) {
+ dev_err(&pdev->dev, "ADC driver already initialized\n");
+ return -EINVAL;
+ }
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ r = request_mem_region(r->start, resource_size(r), pdev->name);
+ if (!r) {
+ dev_err(&pdev->dev, "Failed to request base memory region\n");
+ return -EBUSY;
+ }
+
+ adc = kzalloc(sizeof(struct spmp8000_adc), GFP_KERNEL);
+ if (!adc) {
+ ret = -ENOMEM;
+ goto out_release_mem;
+ }
+
+ adc->reg_base = ioremap(r->start, resource_size(r));
+ if (!adc->reg_base) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ clk_apbdma = clk_get(&pdev->dev, "apbdma_a");
+ if (IS_ERR_OR_NULL(clk_apbdma)) {
+ dev_err(&pdev->dev, "Can't get data path clock\n");
+ ret = -ENODEV;
+ goto out_iounmap;
+ }
+
+ clk_saacc = clk_get(&pdev->dev, "saacc");
+ if (IS_ERR_OR_NULL(clk_saacc)) {
+ dev_err(&pdev->dev, "Can't get controller clock\n");
+ ret = -ENODEV;
+ goto out_put_clk_apbdma;
+ }
+
+ clk_enable(clk_apbdma);
+ clk_enable(clk_saacc);
+
+ clkrate = clk_get_rate(clk_saacc);
+
+ clkrate = DIV_ROUND_UP(clkrate, SAR_CLKRATE); /* Target clkrate */
+ clkrate = DIV_ROUND_UP(clkrate, 2) - 1; /* Divisor */
+
+ dev_dbg(&pdev->dev, "clock rate: %ld\n", clk_get_rate(clk_saacc) /
+ ((clkrate + 1) * 2));
+
+ if (clkrate > 255) {
+ dev_err(&pdev->dev, "Input clockrate too high\n");
+ ret = -EINVAL;
+ goto out_clk_disable;
+ }
+
+ spin_lock_init(&adc->lock);
+ adc->dev = &pdev->dev;
+ adc->clk_apbdma = clk_apbdma;
+ adc->clk_saacc = clk_saacc;
+
+ ret = request_irq(irq, spmp8000adc_irq, 0, dev_name(&pdev->dev), adc);
+ if (ret)
+ goto out_clk_disable;
+
+ adc_dev = adc;
+ platform_set_drvdata(pdev, adc);
+
+ /* Set internal clock divider */
+ writel(clkrate << SARCTRL_DIVNUM_OFF, adc->reg_base + SARCTRL);
+
+ /* Set conversion time defaults */
+ writel(0x10010, adc->reg_base + SARAUTODLY);
+ writel(0x1000, adc->reg_base + SARDEBTIME);
+ writel(0xFF, adc->reg_base + SARCONDLY);
+
+ /* Clear pending interrupts */
+ writel(0xF, adc->reg_base + SARINTF);
+
+ /* Enable interrupts */
+ writel(0xF, adc->reg_base + SARINTEN);
+
+ dev_info(&pdev->dev, "registered\n");
+
+ return 0;
+
+out_clk_disable:
+ clk_disable(clk_saacc);
+ clk_disable(clk_apbdma);
+ clk_put(clk_saacc);
+out_put_clk_apbdma:
+ clk_put(clk_apbdma);
+out_iounmap:
+ iounmap(adc->reg_base);
+out_free:
+ kfree(adc);
+out_release_mem:
+ release_mem_region(r->start, resource_size(r));
+
+ return ret;
+}
+
+static int __devexit spmp8000adc_remove(struct platform_device *pdev)
+{
+ struct spmp8000_adc *adc;
+ struct resource *r;
+ int irq;
+
+ adc = platform_get_drvdata(pdev);
+
+ /* Disable and clear remaining interrupts */
+ writel(0, adc->reg_base + SARCTRL);
+ writel(0xF, adc->reg_base + SARINTEN);
+ writel(0xF, adc->reg_base + SARINTF);
+
+ clk_disable(adc->clk_saacc);
+ clk_disable(adc->clk_apbdma);
+ clk_put(adc->clk_saacc);
+ clk_put(adc->clk_apbdma);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ free_irq(irq, adc);
+
+ iounmap(adc->reg_base);
+
+ kfree(adc);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
+
+ release_mem_region(r->start, resource_size(r));
+
+ platform_set_drvdata(pdev, NULL);
+
+ dev_info(&pdev->dev, "registered\n");
+
+ return 0;
+}
+
+static const struct of_device_id spmp8000_adc_match[] __devinitdata = {
+ { .compatible = "sunplus,spmp8000-adc" },
+ {},
+};
+
+static struct platform_driver spmp8000adc_driver = {
+ .driver = {
+ .name = "spmp8000-adc",
+ .owner = THIS_MODULE,
+ .of_match_table = spmp8000_adc_match,
+ },
+ .probe = spmp8000adc_probe,
+ .remove = __devexit_p(spmp8000adc_remove),
+};
+
+
+static int __init spmp8000adc_init(void)
+{
+ return platform_driver_register(&spmp8000adc_driver);
+}
+module_init(spmp8000adc_init);
+
+static void __exit spmp8000adc_exit(void)
+{
+ platform_driver_unregister(&spmp8000adc_driver);
+}
+module_exit(spmp8000adc_exit);
+
+MODULE_AUTHOR("Zoltan Devai <zoss@devai.org>");
+MODULE_DESCRIPTION("ADC driver for Sunplus SPMP8000 SoC");
+MODULE_LICENSE("GPL");
diff --git a/arch/arm/mach-spmp8000/include/mach/spmp8000adc.h b/arch/arm/mach-spmp8000/include/mach/spmp8000adc.h
new file mode 100644
index 0000000..df5dfad
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/spmp8000adc.h
@@ -0,0 +1,29 @@
+/*
+ * SPMP8000 ADC support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __MACH_SPMP8000_ADC_H__
+#define __MACH_SPMP8000_ADC_H__
+
+struct spmp8000adc_client_chan {
+ void (*cb)(s16, void*); /* Callback for every measurement value */
+ void *priv; /* Private data for client passed to cb */
+};
+
+struct spmp8000adc_client_tp {
+ void (*cb)(s32, void*); /* Callback for every measurement value */
+ void *priv; /* Private data for client passed to cb */
+};
+
+extern int spmp8000adc_request_channel(unsigned int chan,
+ struct spmp8000adc_client_chan *c);
+extern int spmp8000adc_release_channel(unsigned int chan);
+extern int spmp8000adc_request_tp(struct spmp8000adc_client_tp *tp);
+extern void spmp8000adc_release_tp(void);
+
+#endif /* __MACH_SPMP8000_ADC_H__ */
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 5/9] ARM: SPMP8000: Add pinmux driver
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (3 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 4/9] ARM: SPMP8000: Add ADC driver Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-10 1:32 ` Linus Walleij
2011-10-09 16:36 ` [PATCH 6/9] ARM: SPMP8000: Add pwm driver Zoltan Devai
` (6 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/pinmux.c | 131 +++++++++++++++++++++++++++++++++++++++
1 files changed, 131 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/pinmux.c
diff --git a/arch/arm/mach-spmp8000/pinmux.c b/arch/arm/mach-spmp8000/pinmux.c
new file mode 100644
index 0000000..61174d5
--- /dev/null
+++ b/arch/arm/mach-spmp8000/pinmux.c
@@ -0,0 +1,131 @@
+/*
+ * SPMP8000 machines pinmux functions
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+
+#include <mach/scu.h>
+
+static int pgc_to_regs(int pc, void __iomem **reg, int *off, int *mask_bits)
+{
+ if (pc > 52) {
+ pr_err("Invalid pad group control number\n");
+ return -EINVAL;
+ }
+
+ *mask_bits = 1;
+
+ /* The pin controls are nicely scattered around */
+ if (pc < 10) {
+ *reg = REG_SCU_B(SCU_B_PGC0);
+ *off = pc * 3;
+ *mask_bits = 3;
+ } else if (pc == 10) {
+ *reg = REG_SCU_B(SCU_B_PGC1);
+ *off = 0;
+ } else if (pc < 42) {
+ *reg = REG_SCU_B(SCU_B_PGC2);
+ *off = pc - 10;
+ } else {
+ *reg = REG_SCU_B(SCU_B_PGC3);
+ *off = pc - 42;
+ }
+
+ return 0;
+}
+
+/**
+ * Set the control function (usually pull-up/down) of a pin group
+ * @pc Pin control group number
+ * @conf Control function state
+ */
+void spmp8000_pinmux_pgc_set(int pc, unsigned int conf)
+{
+ void __iomem *pgc_reg;
+ int ret, pgc_off, mask_bits;
+ u32 reg;
+
+ ret = pgc_to_regs(pc, &pgc_reg, &pgc_off, &mask_bits);
+ if (ret)
+ return;
+
+ pr_debug("pgc_set: %d, reg: %p, off: %d, mask: %d\n", pc, pgc_reg,
+ pgc_off, mask_bits);
+
+ reg = readl(pgc_reg);
+ reg &= ~(((1 << mask_bits) - 1) << pgc_off);
+ reg |= (conf << pgc_off);
+ writel(reg, pgc_reg);
+}
+
+/**
+ * Get the control function (usually pull-up/down) of a pin group
+ * @pc Pin control group number
+ * @returns Current function control state
+ */
+unsigned int spmp8000_pinmux_pgc_get(int pc)
+{
+ void __iomem *pgc_reg;
+ int ret, pgc_off, mask_bits;
+ u32 reg;
+
+ ret = pgc_to_regs(pc, &pgc_reg, &pgc_off, &mask_bits);
+ if (ret)
+ return ret;
+
+ reg = readl(pgc_reg);
+ reg >>= pgc_off;
+ reg &= (1 << mask_bits) - 1;
+ return reg;
+}
+
+static inline int pgs_to_reg(unsigned int pg)
+{
+ return (pg / 16) * 4;
+}
+
+static inline int pgs_to_off(unsigned int pg)
+{
+ return (pg % 16) * 2;
+}
+
+/**
+ * Set the function of a pin group
+ * @pg Pin group
+ * @func Function
+ */
+void spmp8000_pinmux_pgs_set(unsigned int pg, unsigned int func)
+{
+ u32 reg;
+
+ if ((pg > 63) || (func > 3)) {
+ pr_err("Invalid pad group function select\n");
+ return;
+ }
+
+ reg = readl(REG_SCU_B(SCU_B_PGS0 + pgs_to_reg(pg)));
+ reg &= ~(3 << pgs_to_off(pg));
+ reg |= (func << pgs_to_off(pg));
+ writel(reg, REG_SCU_B(SCU_B_PGS0 + pgs_to_reg(pg)));
+}
+/**
+ * Get the current function associated to the pin group
+ * @pg Pin group
+ * @returns The current function of the pin group
+ */
+int spmp8000_pinmux_pgs_get(int pg)
+{
+ u32 reg;
+
+ reg = readl(REG_SCU_B(SCU_B_PGS0 + pgs_to_reg(pg)));
+ reg = (reg >> pgs_to_off(pg)) & 3;
+ return reg;
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 6/9] ARM: SPMP8000: Add pwm driver
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (4 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 5/9] ARM: SPMP8000: Add pinmux driver Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-10 1:50 ` Linus Walleij
2011-10-09 16:36 ` [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board Zoltan Devai
` (5 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/pwm.c | 246 ++++++++++++++++++++++++++++++++++++++++++
1 files changed, 246 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/pwm.c
diff --git a/arch/arm/mach-spmp8000/pwm.c b/arch/arm/mach-spmp8000/pwm.c
new file mode 100644
index 0000000..a6418bf
--- /dev/null
+++ b/arch/arm/mach-spmp8000/pwm.c
@@ -0,0 +1,246 @@
+/*
+ * SPMP8000 machines PWM support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/pwm.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <asm/div64.h>
+
+#include <mach/regs-timer.h>
+
+static DEFINE_MUTEX(pwm_lock);
+static LIST_HEAD(pwm_list);
+
+struct pwm_device {
+ const char *label;
+ void __iomem *regbase;
+ unsigned int use_count;
+ unsigned int pwm_id;
+ unsigned long clkrate;
+ struct device *dev;
+ struct list_head node;
+};
+
+int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
+{
+ unsigned long long c;
+ unsigned long period_cycles, duty_cycles, prescale;
+
+ if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
+ return -EINVAL;
+
+ c = pwm->clkrate;
+ c = c * period_ns;
+ do_div(c, 1000000000);
+ period_cycles = c;
+
+ prescale = (period_cycles - 1) / 65536;
+
+ if (prescale > 65535)
+ return -EINVAL;
+
+ if (prescale < 1)
+ prescale = 1;
+
+ period_cycles /= prescale;
+
+ if (period_cycles > 65536)
+ return -EINVAL;
+
+ c = (unsigned long long)period_cycles * duty_ns;
+ do_div(c, period_ns);
+ duty_cycles = c;
+
+ dev_dbg(pwm->dev, "period_ns: %d, duty_ns: %d, prescale: %ld,"
+ " period: %ld, duty: %ld\n",
+ period_ns, duty_ns, prescale, period_cycles,
+ duty_cycles);
+
+ writel(prescale - 1, pwm->regbase + SPMP8000_TMRB_PSR);
+ writel(period_cycles, pwm->regbase + SPMP8000_TMRB_LDR);
+ writel(duty_cycles, pwm->regbase + SPMP8000_TMRB_CMP);
+
+ return 0;
+}
+EXPORT_SYMBOL(pwm_config);
+
+int pwm_enable(struct pwm_device *pwm)
+{
+ writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_OE |
+ SPMP8000_TMRB_CTR_PWMON | SPMP8000_TMRB_CTR_UD |
+ (1 << SPMP8000_TMRB_CTR_M_SH),
+ pwm->regbase + SPMP8000_TMRB_CTR);
+ return 0;
+}
+EXPORT_SYMBOL(pwm_enable);
+
+void pwm_disable(struct pwm_device *pwm)
+{
+ writel(0, pwm->regbase + SPMP8000_TMRB_CTR);
+}
+EXPORT_SYMBOL(pwm_disable);
+
+struct pwm_device *pwm_request(int pwm_id, const char *label)
+{
+ struct pwm_device *pwm;
+ int found = 0;
+
+ mutex_lock(&pwm_lock);
+
+ list_for_each_entry(pwm, &pwm_list, node) {
+ if (pwm->pwm_id == pwm_id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ if (pwm->use_count == 0) {
+ pwm->use_count++;
+ pwm->label = label;
+ } else {
+ pwm = ERR_PTR(-EBUSY);
+ }
+ } else {
+ pwm = ERR_PTR(-ENOENT);
+ }
+
+ mutex_unlock(&pwm_lock);
+ return pwm;
+}
+EXPORT_SYMBOL(pwm_request);
+
+void pwm_free(struct pwm_device *pwm)
+{
+ mutex_lock(&pwm_lock);
+
+ if (pwm->use_count) {
+ pwm->use_count--;
+ pwm->label = NULL;
+ } else {
+ pr_warning("PWM device already freed\n");
+ }
+
+ mutex_unlock(&pwm_lock);
+}
+EXPORT_SYMBOL(pwm_free);
+
+static inline void __add_pwm(struct pwm_device *pwm)
+{
+ mutex_lock(&pwm_lock);
+ list_add_tail(&pwm->node, &pwm_list);
+ mutex_unlock(&pwm_lock);
+}
+
+static int __devinit pwm_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ const unsigned int *id;
+ struct pwm_device *pwm;
+ void __iomem *base;
+ struct clk *clk;
+
+ id = of_get_property(np, "id", NULL);
+ if (!id) {
+ dev_dbg(&pdev->dev, "No id specified\n");
+ return -ENODEV;
+ }
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ dev_dbg(&pdev->dev, "Can't map registers");
+ return -ENOMEM;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_dbg(&pdev->dev, "Unable to get pwm device clock");
+ return -ENODEV;
+ }
+
+ pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
+ if (pwm == NULL) {
+ dev_dbg(&pdev->dev, "failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ pwm->dev = &pdev->dev;
+ pwm->use_count = 0;
+ pwm->pwm_id = *id;
+ pwm->regbase = base;
+ pwm->clkrate = clk_get_rate(clk);
+
+ dev_dbg(&pdev->dev, "register pwm.%d, regbase %p, clkrate: %ld\n",
+ pwm->pwm_id, pwm->regbase, pwm->clkrate);
+
+ dev_info(&pdev->dev, "pwm %d registered\n", pwm->pwm_id);
+
+ __add_pwm(pwm);
+
+ platform_set_drvdata(pdev, pwm);
+ return 0;
+}
+
+static int __devexit pwm_remove(struct platform_device *pdev)
+{
+ struct pwm_device *pwm;
+
+ pwm = platform_get_drvdata(pdev);
+ if (pwm == NULL)
+ return -ENODEV;
+
+ mutex_lock(&pwm_lock);
+ list_del(&pwm->node);
+ mutex_unlock(&pwm_lock);
+
+ kfree(pwm);
+ return 0;
+}
+
+static const __devinitconst struct of_device_id spmp8000_pwm_match[] = {
+ {
+ .compatible = "sunplus,spmp8000-pwm",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, spmp8000_pwm_match);
+
+static struct platform_driver pwm_driver = {
+ .driver = {
+ .name = "spmp8000-pwm",
+ .owner = THIS_MODULE,
+ .of_match_table = spmp8000_pwm_match,
+ },
+ .probe = pwm_probe,
+ .remove = __devexit_p(pwm_remove),
+};
+
+static int __init pwm_init(void)
+{
+ return platform_driver_register(&pwm_driver);
+}
+arch_initcall(pwm_init);
+
+static void __exit pwm_exit(void)
+{
+ platform_driver_unregister(&pwm_driver);
+}
+module_exit(pwm_exit);
+
+MODULE_AUTHOR("Zoltan Devai <zoss@devai.org>");
+MODULE_LICENSE("GPL");
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (5 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 6/9] ARM: SPMP8000: Add pwm driver Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-10 8:54 ` Jamie Iles
2011-10-09 16:36 ` [PATCH 8/9] ARM: SPMP8000: Add support for the " Zoltan Devai
` (4 subsequent siblings)
11 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/boot/dts/spmp8000-letcool.dts | 163 ++++++++++++++++++++++++++++++
arch/arm/boot/dts/spmp8000.dtsi | 169 ++++++++++++++++++++++++++++++++
2 files changed, 332 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/boot/dts/spmp8000-letcool.dts
create mode 100644 arch/arm/boot/dts/spmp8000.dtsi
diff --git a/arch/arm/boot/dts/spmp8000-letcool.dts b/arch/arm/boot/dts/spmp8000-letcool.dts
new file mode 100644
index 0000000..270f00e
--- /dev/null
+++ b/arch/arm/boot/dts/spmp8000-letcool.dts
@@ -0,0 +1,163 @@
+/dts-v1/;
+/include/ "spmp8000.dtsi"
+/ {
+ model = "Letcool N350JP handheld game console";
+ compatible = "gameware,letcool", "sunplus,spmp8000";
+
+ memory {
+ reg = <0x00000000 0x02000000>;
+ };
+
+ chosen {
+ bootargs = "console=tty0 mem=32M root=/dev/mmcblk0p1 console=ttyS0,115200 rootdelay=5 loglevel=8 earlyprintk";
+ linux,stdout-path = &uart0;
+ };
+
+ pwm-backlight {
+ compatible = "pwm-backlight";
+ reg = <0 0>; /* Hack to pass platform data as AUXDATA */
+ };
+
+ plat {
+ plat-apb {
+ mmc at 92B0B000 {
+ cd-gpios = <&gpio0 9 0>;
+ };
+ };
+ };
+
+ armapb {
+ gpio at 9000A000 {
+ polarity = <0>;
+ sticky = <0>;
+ direction = <0xFFFFFFFF>;
+ debounce-val = <100>;
+ debounce = <0xFFFFFFFF>;
+ };
+
+ gpio at 9000A004 {
+ polarity = <0>;
+ sticky = <0>;
+ direction = <0xFFFFFFFF>;
+ debounce-val = <100>;
+ debounce = <0xFFFFFFFF>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ autorepeat;
+
+ up {
+ label = "D-Pad Up";
+ gpios = <&gpio0 0 0>;
+ linux,code = <103>; /* KEY_UP */
+ gpio-key,wakeup;
+ };
+
+ right {
+ label = "D-Pad Right";
+ gpios = <&gpio0 1 0>;
+ linux,code = <106>; /* KEY_RIGHT */
+ gpio-key,wakeup;
+ };
+
+ down {
+ label = "D-Pad Down";
+ gpios = <&gpio0 2 0>;
+ linux,code = <108>; /* KEY_DOWN */
+ gpio-key,wakeup;
+ };
+
+ left {
+ label = "D-Pad Left";
+ gpios = <&gpio0 3 0>;
+ linux,code = <105>; /* KEY_LEFT */
+ gpio-key,wakeup;
+ };
+
+ button-x {
+ label = "Button X";
+ gpios = <&gpio0 4 0>;
+ linux,code = <45>; /* KEY_X */
+ gpio-key,wakeup;
+ };
+
+ button-a {
+ label = "Button A";
+ gpios = <&gpio0 5 0>;
+ linux,code = <30>; /* KEY_A */
+ gpio-key,wakeup;
+ };
+
+ button-y {
+ label = "Button Y";
+ gpios = <&gpio0 6 0>;
+ linux,code = <21>; /* KEY_Y */
+ gpio-key,wakeup;
+ };
+
+ button-b {
+ label = "Button B";
+ gpios = <&gpio0 7 0>;
+ linux,code = <48>; /* KEY_B */
+ gpio-key,wakeup;
+ };
+ };
+
+ analog-keys {
+ compatible = "spmp8000-ak";
+
+ channel-1 {
+ adc-channel = <1>;
+ idle-value = <0>;
+ tolerance = <10>;
+
+ button-left {
+ adc-value = <0x00B0>;
+ linux,code = <0x110>; /* BTN_LEFT */
+ };
+
+ button-right {
+ adc-value = <0xFEAB>;
+ linux,code = <0x111>; /* BTN_RIGHT */
+ };
+
+ button-volup {
+ adc-value = <0x015E>;
+ linux,code = <115>; /* KEY_VOLUMEUP */
+ };
+
+ button-voldown {
+ adc-value = <0xFF56>;
+ linux,code = <114>; /* KEY_VOLUMEDOWN */
+ };
+ };
+
+ channel-3 {
+ adc-channel = <3>;
+ idle-value = <5>;
+ tolerance = <10>;
+
+ button-select {
+ adc-value = <0x0113>;
+ linux,code = <0x13a>; /* BTN_SELECT */
+ };
+
+ button-start {
+ adc-value = <0xFEF7>;
+ linux,code = <0x13b>; /* BTN_START */
+ };
+ };
+
+ };
+
+ snd-card {
+ compatible = "spmp8000-sndcard";
+ hp-detect-gpios = <&gpio0 8 0>;
+ spk-enable-gpios = <&gpio3 12 0>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/spmp8000.dtsi b/arch/arm/boot/dts/spmp8000.dtsi
new file mode 100644
index 0000000..74764b2c6
--- /dev/null
+++ b/arch/arm/boot/dts/spmp8000.dtsi
@@ -0,0 +1,169 @@
+/ {
+ compatible = "sunplus,spmp8000";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ armapb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x90000000 0x90000000 0x10000>;
+
+ timer at 90000000 {
+ compatible = "sunplus,spmp8000-timer";
+ reg = <0x90000000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <7 8 9>;
+ };
+
+ pwm at 90000000 {
+ compatible = "sunplus,spmp8000-pwm";
+ reg = <0x90000000 0x1000>;
+ id = <0>;
+ };
+
+ gpio3: gpio at 90005070 {
+ compatible = "basic-mmio-gpio"; /* No DT binding yet */
+ reg = <0x90005070 0xC>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio0: gpio at 9000A000 {
+ compatible = "sunplus,spmp8000-gpio";
+ reg = <0x9000A000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ bits = <16>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ gpio1: gpio at 9000A004 {
+ compatible = "sunplus,spmp8000-gpio";
+ reg = <0x9000A004 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ bits = <32>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ armahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x90010000 0x90010000 0x20000>;
+
+ vic0: interrupt-controller at 90010000 {
+ compatible = "arm,pl192";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x90010000 0x1000>;
+ };
+
+ vic1: interrupt-controller at 900020000 {
+ compatible = "arm,pl192";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x90020000 0x1000>;
+ };
+ };
+
+ plat {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x92000000 0x92000000 0x1000000>;
+
+ plat-apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x92B00000 0x92B00000 0x10000>;
+
+ dma at 92B00000 {
+ compatible = "sunplus,spmp8000-apbdma-c";
+ reg = <0x92B00000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <28 29 30 31>;
+ };
+
+ uart0: uart-c0 at 92B04000 {
+ compatible = "ns16550a";
+ reg = <0x92B04000 0x1000>;
+ clock-frequency = <2076923>;
+ interrupt-parent = <&vic1>;
+ interrupts = <24>;
+ current-speed = <115200>;
+ reg-shift = <2>;
+ };
+
+ mmc at 92B0B000 {
+ compatible = "sunplus,mmc";
+ reg = <0x92B0B000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <8>;
+ };
+ };
+ };
+
+ axi {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x93000000 0x93000000 0x800000>;
+
+ fb at 93000000 {
+ compatible = "sunplus,spmp8000-lcd";
+ reg = <0x93000000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <23>;
+ };
+
+ axi-apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x93010000 0x93010000 0x10000>;
+
+ dma at 93010000 {
+ compatible = "sunplus,spmp8000-apbdma-a";
+ reg = <0x93010000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <24 25 26 27>;
+ };
+
+ i2s at 93012000 {
+ compatible = "sunplus,spmp8000-i2s-tx";
+ reg = <0x93012000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <13>;
+ };
+
+ i2s at 9301D000 {
+ compatible = "sunplus,spmp8000-i2s-rx";
+ reg = <0x9301D000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <14>;
+ };
+
+ adc at 9301F000 {
+ compatible = "sunplus,spmp8000-adc";
+ reg = <0x9301F000 0x20>;
+ interrupt-parent = <&vic1>;
+ interrupts = <27>;
+ };
+
+ codec at 9301F020 {
+ compatible = "sunplus,spmp8000-codec";
+ reg = <0x9301F020 0x20>;
+ };
+ };
+ };
+};
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 8/9] ARM: SPMP8000: Add support for the Letcool board
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (6 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-11 14:09 ` Arnd Bergmann
2011-10-13 9:54 ` Russell King - ARM Linux
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
` (3 subsequent siblings)
11 siblings, 2 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/board_letcool.c | 154 ++++++++++++++++++++++
arch/arm/mach-spmp8000/include/mach/spmp8000fb.h | 32 +++++
2 files changed, 186 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/board_letcool.c
create mode 100644 arch/arm/mach-spmp8000/include/mach/spmp8000fb.h
diff --git a/arch/arm/mach-spmp8000/board_letcool.c b/arch/arm/mach-spmp8000/board_letcool.c
new file mode 100644
index 0000000..8d6c081
--- /dev/null
+++ b/arch/arm/mach-spmp8000/board_letcool.c
@@ -0,0 +1,154 @@
+/*
+ * Letcool board support file
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pwm_backlight.h>
+#include <linux/input.h>
+#include <linux/basic_mmio_gpio.h>
+#include <linux/gpio_keys.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/hardware/vic.h>
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <mach/core.h>
+#include <mach/gpio.h>
+#include <mach/scu.h>
+#include <mach/spmp8000fb.h>
+
+/* Backlight */
+static struct platform_pwm_backlight_data backlight_letcool = {
+ .pwm_id = 0,
+ .max_brightness = 100,
+ .dft_brightness = 20,
+ .pwm_period_ns = 100000,
+};
+
+/* Framebuffer */
+static struct spmp8000fb_pdata spmp8000fb_letcool = {
+ .data_fmt = TFT_FMT_RGB565,
+ .mode = {
+ .name = "A035QN02V6",
+ .refresh = 60,
+ .xres = 320,
+ .yres = 240,
+ .pixclock = KHZ2PICOS(5000),
+ .left_margin = 8,
+ .right_margin = 8,
+ .upper_margin = 2,
+ .lower_margin = 2,
+ .hsync_len = 1,
+ .vsync_len = 1,
+ },
+};
+
+/* GPIO3 */
+static struct resource spmp8000_gpio3_resources[] = {
+ [0] = {
+ .name = "dat",
+ .start = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_I,
+ .end = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_I + 3,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .name = "set",
+ .start = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_O,
+ .end = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_O + 3,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = {
+ .name = "dirin",
+ .start = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_E,
+ .end = SPMP8000_SCU_B_BASE + SCU_B_GPIO3_E + 3,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct of_dev_auxdata letcool_auxdata_lookup[] __initdata = {
+ OF_DEV_AUXDATA("pwm-backlight", 0, "pwm-backlight",
+ &backlight_letcool),
+ OF_DEV_AUXDATA("sunplus,spmp8000-lcd", 0x93000000, "93000000.fb",
+ &spmp8000fb_letcool),
+ OF_DEV_AUXDATA("basic-mmio-gpio", 0x90005070, "basic-mmio-gpio",
+ NULL),
+ { /* sentinel */ },
+};
+
+static void __init letcool_dt_init(void)
+{
+ struct device_node *gpio3_np;
+ struct platform_device *gpio3_pdev;
+
+ /* Static board setup stuff */
+
+ /* Switch off pull-down on SD Card detect pin */
+ spmp8000_pinmux_pgc_set(47, 0);
+
+ /* Set GPIO0 pins as GPIO */
+ spmp8000_pinmux_pgs_set(31, 2);
+ spmp8000_pinmux_pgs_set(32, 2);
+ spmp8000_pinmux_pgs_set(37, 1);
+ spmp8000_pinmux_pgs_set(38, 1);
+
+ /* Set up SAR-GPIOs for the ADC power supply */
+ writel(0xCC, REG_SCU_A(SCU_A_SAR_GPIO_CTRL));
+ writel(0x3, REG_SCU_A(SCU_A_SAR_GPIO_OEN));
+ writel(0xC, REG_SCU_A(SCU_A_SAR_GPIO_O));
+
+ /* Switch UART_MISC_TX and RX to GPIO3 pins */
+ spmp8000_pinmux_pgs_set(43, 2);
+ spmp8000_pinmux_pgs_set(44, 2);
+
+ /* Codec errata fix */
+ writel(SCU_A_CODEC_CFG_VAL, REG_SCU_A(SCU_A_CODEC_CFG));
+
+ /* DT and platform device setup */
+
+ /* Create platform devces */
+ of_platform_populate(NULL, of_default_bus_match_table,
+ letcool_auxdata_lookup, NULL);
+
+ /* Fix-up GPIO3 platform device resources to make gpio-generic work.
+ * Should be removed once it has DT bindings. */
+ gpio3_np = of_find_compatible_node(NULL, NULL, "basic-mmio-gpio");
+ if (!gpio3_np) {
+ pr_err("letcool: Can't find gpio3 DT node\n");
+ return;
+ }
+
+ gpio3_pdev = of_find_device_by_node(gpio3_np);
+ if (!gpio3_pdev) {
+ pr_err("letcool: Can't find gpio3 platform device\n");
+ return;
+ }
+
+ gpio3_pdev->num_resources = ARRAY_SIZE(spmp8000_gpio3_resources);
+ gpio3_pdev->resource = spmp8000_gpio3_resources;
+}
+
+static const char *letcool_dt_match[] __initconst = {
+ "gameware,letcool",
+ NULL,
+};
+
+DT_MACHINE_START(LETCOOL, "Letcool N350JP")
+ .map_io = spmp8000_map_io,
+ .init_early = spmp8000_init_clkdev,
+ .init_irq = spmp8000_init_irq,
+ .handle_irq = vic_handle_irq,
+ .nr_irqs = SPMP8000_TOTAL_IRQS,
+ .init_machine = letcool_dt_init,
+ .timer = &spmp8000_sys_timer,
+ .dt_compat = letcool_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-spmp8000/include/mach/spmp8000fb.h b/arch/arm/mach-spmp8000/include/mach/spmp8000fb.h
new file mode 100644
index 0000000..525e23f
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/spmp8000fb.h
@@ -0,0 +1,32 @@
+/*
+ * SPMP8000 machines LCD controller support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_FB_H__
+#define __MACH_SPMP8000_FB_H__
+
+#include <linux/fb.h>
+
+#define TFT_FMT_RGB565 0
+#define TFT_FMT_SRGB 1
+#define TFT_FMT_RGBDM 2
+#define TFT_FMT_CCIR601 3
+#define TFT_FMT_CCIR656 4
+#define TFT_FMT_RGB24B 5
+#define TFT_FMT_CCIR_720M (1 << 8)
+
+struct spmp8000fb_pdata {
+ u32 data_fmt;
+ u32 xres_virtual;
+ u32 yres_virtual;
+ u32 bpp;
+ struct fb_videomode mode;
+};
+
+#endif /* __MACH_SPMP8000_FB_H__ */
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (7 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 8/9] ARM: SPMP8000: Add support for the " Zoltan Devai
@ 2011-10-09 16:36 ` Zoltan Devai
2011-10-09 17:25 ` Jamie Iles
` (2 more replies)
2011-10-10 8:55 ` Add support for the SPMP8000 SoC and Letcool board Jamie Iles
` (2 subsequent siblings)
11 siblings, 3 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-09 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/Kconfig | 16 ++++++++++++++++
arch/arm/Makefile | 1 +
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9426e26..f34f10d 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -831,6 +831,22 @@ config ARCH_SHARK
Support for the StrongARM based Digital DNARD machine, also known
as "Shark" (<http://www.shark-linux.de/shark.html>).
+config ARCH_SPMP8000
+ bool "Sunplus SPMP8000"
+ select CPU_ARM926T
+ select ARM_VIC
+ select GENERIC_IRQ_CHIP
+ select MULTI_IRQ_HANDLER
+ select CLKSRC_MMIO
+ select GENERIC_CLOCKEVENTS
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select USE_OF
+ select CLKDEV_LOOKUP
+ select HAVE_PWM
+ select ARCH_HAS_CPUFREQ
+ help
+ Support for Sunplus SPMP8000A/8010A/8016A SoC.
+
config ARCH_TCC_926
bool "Telechips TCC ARM926-based systems"
select CLKSRC_MMIO
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index e0ac6eb..f837a3b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -180,6 +180,7 @@ machine-$(CONFIG_ARCH_EXYNOS4) := exynos4
machine-$(CONFIG_ARCH_SA1100) := sa1100
machine-$(CONFIG_ARCH_SHARK) := shark
machine-$(CONFIG_ARCH_SHMOBILE) := shmobile
+machine-$(CONFIG_ARCH_SPMP8000) := spmp8000
machine-$(CONFIG_ARCH_TCC8K) := tcc8k
machine-$(CONFIG_ARCH_TEGRA) := tegra
machine-$(CONFIG_ARCH_U300) := u300
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-09 16:36 ` [PATCH 2/9] ARM: SPMP8000: Add machine base files Zoltan Devai
@ 2011-10-09 17:22 ` Jamie Iles
2011-10-10 11:36 ` Zoltan Devai
2011-10-11 14:44 ` Arnd Bergmann
1 sibling, 1 reply; 78+ messages in thread
From: Jamie Iles @ 2011-10-09 17:22 UTC (permalink / raw)
To: linux-arm-kernel
Hi Zoltan,
A couple of minor comments inline but this looks really good!
Jamie
On Sun, Oct 09, 2011 at 06:36:05PM +0200, Zoltan Devai wrote:
[...]
> diff --git a/arch/arm/mach-spmp8000/Makefile b/arch/arm/mach-spmp8000/Makefile
> new file mode 100644
> index 0000000..9d35cca
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/Makefile
> @@ -0,0 +1,11 @@
> +#
> +# Makefile for the linux kernel.
> +#
Nit: I don't think this comment adds a great deal of value.
> +obj-y := core.o
> +obj-y += timer.o
> +obj-y += pinmux.o
> +obj-y += clock.o
> +obj-y += clkdev.o
> +obj-y += board_letcool.o
> +obj-y += adc.o
> +obj-y += pwm.o
> diff --git a/arch/arm/mach-spmp8000/core.c
> b/arch/arm/mach-spmp8000/core.c
> new file mode 100644
> index 0000000..ba05614
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/core.c
> @@ -0,0 +1,103 @@
> +/*
> + * SPMP8000 machines core functions
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <asm/mach/map.h>
> +#include <asm/hardware/vic.h>
> +#include <mach/hardware.h>
> +#include <mach/scu.h>
> +
> +/* Static mappings:
> + * SCU: timer needs clk support which is inited in init_early
> + * UART: needed for earlyprintk
> + */
> +static struct map_desc io_desc[] __initdata = {
> + {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_A_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_A_BASE),
> + .length = SPMP8000_SCU_A_SIZE,
> + .type = MT_DEVICE,
> + }, {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_B_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_B_BASE),
> + .length = SPMP8000_SCU_B_SIZE,
> + .type = MT_DEVICE,
> + }, {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_C_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_C_BASE),
> + .length = SPMP8000_SCU_C_SIZE,
> + .type = MT_DEVICE,
> + },
> +#ifdef CONFIG_DEBUG_LL
> + {
> + .virtual = IO_ADDRESS(SPMP8000_UARTC0_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
> + .length = SPMP8000_UARTC0_SIZE,
> + .type = MT_DEVICE,
> + },
> +#endif
> +};
> +
> +#define IO_PTR(x) ((void __iomem *)IO_ADDRESS(x))
Generally IO_ADDRESS returns a void __iomem pointer so it would be
easier if you could have the cast in there (though it may need to be
enclosed in #ifndef __ASSEMBLY__ conditionals).
> +/* Make the lookup of SCU base and clk enable registers easy for the clk
> + * code, as they are not at the same offset in each controller */
> +struct scu_reg_t scu_regs[3] = {
> + { /* SCU_A */
> + .base = IO_PTR(SPMP8000_SCU_A_BASE),
> + .clken = IO_PTR(SPMP8000_SCU_A_BASE) + SCU_A_PERI_CLKEN,
> + },
> + { /* SCU_B */
> + .base = IO_PTR(SPMP8000_SCU_B_BASE),
> + .clken = IO_PTR(SPMP8000_SCU_B_BASE) + SCU_B_PERI_CLKEN,
> + },
> + { /* SCU_C */
> + .base = IO_PTR(SPMP8000_SCU_C_BASE),
> + .clken = IO_PTR(SPMP8000_SCU_C_BASE) + SCU_C_PERI_CLKEN,
> + },
> +};
> +
> +/* DMA controller names to be used for the filter
> + * function of the DMA-Engine API. */
> +char *spmp8000_dma_controller_names[] = {
const char * const?
> + "93010000.dma", /* APBDMA_A */
> + "92b00000.dma", /* APBDMA_C */
> +};
> +
> +void __init spmp8000_map_io(void)
> +{
> + iotable_init(io_desc, ARRAY_SIZE(io_desc));
> +}
> +
> +void __init spmp8000_init_irq(void)
> +{
> + struct device_node *np;
> + int ret;
> +
> + np = of_find_compatible_node(NULL, NULL, "arm,pl192");
> + if (!np)
> + panic("Can't find VIC0 interrupt controller\n");
> +
> + ret = vic_of_init(np, NULL);
> + if (ret)
> + panic("Can't init VIC0 interrupt controller\n");
> +
> + np = of_find_compatible_node(np, NULL, "arm,pl192");
> + if (!np)
> + panic("Can't find VIC1 interrupt controller\n");
> +
> + ret = vic_of_init(np, NULL);
> + if (ret)
> + panic("Can't init VIC1 interrupt controller\n");
> +
> + of_node_put(np);
So with Rob Herring's of_irq_init patches you should be able to reduce
this to:
static const struct of_device_id spmp8000_vic_matches[] = {
{ .compatible = "arm,pl192", .data = vic_of_init },
};
of_irq_init(spmp8000_vic_matches);
and that will handle both VIC's and ordering.
> +}
> diff --git a/arch/arm/mach-spmp8000/include/mach/core.h b/arch/arm/mach-spmp8000/include/mach/core.h
> new file mode 100644
> index 0000000..fa1d522
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/core.h
> @@ -0,0 +1,29 @@
> +/*
> + * SPMP8000 generic includes
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __MACH_SPMP8000_GENERIC_H__
> +#define __MACH_SPMP8000_GENERIC_H__
> +
> +/* core.c */
> +extern void __init spmp8000_map_io(void);
> +extern void __init spmp8000_init_irq(void);
Nit: you don't need the __init attributes in the header files.
> +extern struct sys_timer spmp8000_sys_timer;
> +
> +/* clkdev.c */
> +extern void __init spmp8000_init_clkdev(void);
> +extern void spmp8000_update_arm_freqs(void); /* For cpufreq driver */
> +
> +/* pinmux.c */
> +extern void spmp8000_pinmux_pgc_set(int pc, unsigned int conf);
> +extern unsigned int spmp8000_pinmux_pgc_get(int pc);
> +extern void spmp8000_pinmux_pgs_set(unsigned int pg, unsigned int func);
> +extern int spmp8000_pinmux_pgs_get(int pg);
> +
> +#endif /* __MACH_SPMP8000_GENERIC_H__ */
[...]
> diff --git a/arch/arm/mach-spmp8000/include/mach/dma.h b/arch/arm/mach-spmp8000/include/mach/dma.h
> new file mode 100644
> index 0000000..44bc9f2
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/dma.h
> @@ -0,0 +1,45 @@
> +/*
> + * SPMP8000 dma.h
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +#include <linux/module.h>
> +#include <linux/dmaengine.h>
It may be worth splitting the DMA part out into a separate patch unless
this really is required for basic functionality.
> +
> +#ifndef __MACH_SPMP8000_DMA_H__
> +#define __MACH_SPMP8000_DMA_H__
> +
> +enum spmp8000_dma_controller {
> + SPMP8000_APBDMA_A = 0,
> + SPMP8000_APBDMA_C,
> +};
> +
> +extern char *spmp8000_dma_controller_names[];
> +
> +struct spmp8000_dma_params {
> + char *dma_controller;
> + dma_addr_t dma_address;
> + enum dma_slave_buswidth dma_width;
> + int maxburst;
> +};
dmaengine has dma_slave_config that could be used for this, but I don't
see any of this file being used in this series so perhaps it's worth
adding in after the core stuff has been merged?
> +
> +/* Driver parameters */
> +#define SPMP8000_APBDMA_MAX_PERIODS 64
> +
> +static bool spmp8000_dma_filter(struct dma_chan *chan, const char *name)
> +{
> + int ret;
> +
> + ret = strcmp(dev_name(chan->device->dev), name);
> +
> + if (ret)
> + return false;
> +
> + return true;
I think you can reduce this function to just
return !strcmp(dev_name(chan->device->dev), name);
and the compiler will do the right thing with int->bool conversion.
> diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h
> b/arch/arm/mach-spmp8000/include/mach/gpio.h
> new file mode 100644
> index 0000000..3eafac2
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/gpio.h
> @@ -0,0 +1,21 @@
> +/*
> + * SPMP8000 machines gpio support
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __MACH_SPMP8000_GPIO_H__
> +#define __MACH_SPMP8000_GPIO_H__
> +
> +#include <asm-generic/gpio.h>
> +
> +#define gpio_get_value __gpio_get_value
> +#define gpio_set_value __gpio_set_value
> +#define gpio_cansleep __gpio_cansleep
> +#define gpio_to_irq __gpio_to_irq
Russell has a patch (ARM: gpio: make trivial GPIOLIB implementation the
default) in for-next that means you shouldn't need these definitions
anymore.
> diff --git a/arch/arm/mach-spmp8000/include/mach/irqs.h
> b/arch/arm/mach-spmp8000/include/mach/irqs.h
> new file mode 100644
> index 0000000..7f305d3
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/irqs.h
> @@ -0,0 +1,21 @@
> +/*
> + * SPMP8000 irqs.h
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __MACH_SPMP8000_IRQS_H__
> +#define __MACH_SPMP8000_IRQS_H__
> +
> +#define SPMP8000_HW_IRQS 64
> +#define SPMP8000_GPIO_IRQS_START SPMP8000_HW_IRQS
> +#define SPMP8000_GPIO_IRQS (16 + 32)
> +#define SPMP8000_TOTAL_IRQS (SPMP8000_HW_IRQS + SPMP8000_GPIO_IRQS)
> +
> +#define NR_IRQS SPMP8000_TOTAL_IRQS
I think that if you use my VIC patches then you can actually define
NR_IRQS to 0 as all IRQ descs are dynamically allocated (otherwise
you'll be reserving a bunch of irq_descs that never get used).
> diff --git a/arch/arm/mach-spmp8000/include/mach/regs-timer.h
> b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
> new file mode 100644
> index 0000000..90735df
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
> @@ -0,0 +1,32 @@
> +/*
> + * SPMP8000 timer support
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + *
> + * These timer reg definitions are used by the timer and pwm drivers
> + */
If these definitions are only being used inside arch/arm/mach-spmp8000
then I'd put the headers in there rather than the
arch/arm/mach-spmp8000/include/mach subdir so that the visibility is
restricted to the mach code.
> +#ifndef __MACH_SPMP8000_REGS_TIMER_H__
> +#define __MACH_SPMP8000_REGS_TIMER_H__
> +
> +#define SPMP8000_TMRB(tnum) (tnum * 0x20)
> +#define SPMP8000_TMRB_CTR 0x00
> +#define SPMP8000_TMRB_CTR_TE BIT(0)
> +#define SPMP8000_TMRB_CTR_IE BIT(1)
> +#define SPMP8000_TMRB_CTR_OE BIT(2)
> +#define SPMP8000_TMRB_CTR_PWMON BIT(3)
> +#define SPMP8000_TMRB_CTR_UD BIT(4)
> +#define SPMP8000_TMRB_CTR_UDS BIT(5)
> +#define SPMP8000_TMRB_CTR_OM BIT(6)
> +#define SPMP8000_TMRB_CTR_ES_SH 8
> +#define SPMP8000_TMRB_CTR_M_SH 10
> +#define SPMP8000_TMRB_PSR 0x04
> +#define SPMP8000_TMRB_LDR 0x08
> +#define SPMP8000_TMRB_VLR 0x08
> +#define SPMP8000_TMRB_ISR 0x0C
> +#define SPMP8000_TMRB_CMP 0x10
> +
> +#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
> diff --git a/arch/arm/mach-spmp8000/include/mach/scu.h b/arch/arm/mach-spmp8000/include/mach/scu.h
> new file mode 100644
> index 0000000..e3a98d4
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/scu.h
Same here as the timer regs stuff.
> @@ -0,0 +1,146 @@
> +/*
> + * SPMP8000 System Control Unit register definitions
> + * SCUs are a random collection of reset, clock, gpio, pinmux, etc. controllers
> + * so that these definitions are needed at several places.
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/bitops.h>
> +#include <mach/hardware.h>
> +
> +#ifndef __MACH_SPMP8000_SCU_H__
> +#define __MACH_SPMP8000_SCU_H__
> +
> +/* Used by to the clock code to directly access the SCU base and clock
> + * enabling registers, without looking up the according registers first.
> + */
> +struct scu_reg_t {
Generally speaking _t isn't used for structs.
> + void *base;
> + void *clken;
Shouldn't these be void __iomem *?
> +};
> +
> +extern struct scu_reg_t scu_regs[];
> +
> +#define REG_SCU_BASE(x) scu_regs[x].base
> +#define REG_SCU_CLKEN(x) scu_regs[x].clken
> +#define REG_SCU_A_ID 0
> +#define REG_SCU_B_ID 1
> +#define REG_SCU_C_ID 2
> +#define REG_SCU_A(x) (scu_regs[REG_SCU_A_ID].base + x)
> +#define REG_SCU_B(x) (scu_regs[REG_SCU_B_ID].base + x)
> +#define REG_SCU_C(x) (scu_regs[REG_SCU_C_ID].base + x)
macros that assume there is a variable in scope with a given name
(scu_regs) are generally frowned upon as it's difficult to see what's
going on and can be a little error prone.
> diff --git a/arch/arm/mach-spmp8000/include/mach/system.h
> b/arch/arm/mach-spmp8000/include/mach/system.h
> new file mode 100644
> index 0000000..be53ff3
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/system.h
> @@ -0,0 +1,45 @@
> +/*
> + * SPMP8000 system.h
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __MACH_SPMP8000_SYSTEM_H__
> +#define __MACH_SPMP8000_SYSTEM_H__
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +
> +#define SPMP8000_WDT_BASE 0x90001000
> +#define SPMP8000_WDT_SIZE 0x1000
> +
> +#define SPMP8000_WDT_CTR 0x00
> +#define SPMP8000_WDT_CTR_TE BIT(0)
> +#define SPMP8000_WDT_CTR_RE BIT(3)
> +
> +static inline void arch_idle(void)
> +{
> + cpu_do_idle();
> +}
> +
> +static inline void arch_reset(char mode, const char *cmd)
> +{
> + void *base;
> +
> + base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
> + if (!base) {
> + pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
> + "Halt.");
> + while (1);
> + }
It may be worth doing the ioremap earlier when the system is in a known
good state with all functions available rather than at reset time.
> +
> + /* Trigger a watchdog reset */
> + writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
> + base + SPMP8000_WDT_CTR);
> +}
[...]
> diff --git a/arch/arm/mach-spmp8000/timer.c
> b/arch/arm/mach-spmp8000/timer.c
> new file mode 100644
> index 0000000..7d5d0eb
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/timer.c
> @@ -0,0 +1,160 @@
> +/*
> + * SPMP8000 machines timer functions
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/irq.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/bitops.h>
> +#include <linux/interrupt.h>
> +#include <linux/clockchips.h>
> +#include <linux/clk.h>
> +#include <asm/mach/time.h>
> +
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/regs-timer.h>
> +#include <mach/irqs.h>
> +
> +static unsigned long clkrate;
> +static const unsigned int tickrate = 1012500;
> +
> +/* The TIMER_B block is used as system timer
> + * T2: Clocksource
> + * T1: Clockevent
> + * T0: PWM for LCD backlight
> + * T3,4: Could be used as additional clockevent devices
> + * Timer constraints:
> + * - WDT: Can't clear the irq directly, only by resetting the whole counter
> + * in the ISR, which means that IRQs will jitter
> + * - Timer_B: Can't reset the timer value, so at start, the first IRQ
> + * will happen at some random time.
> + */
> +#define CS_TIMER 2
> +#define CE_TIMER 1
Nit: removing the extra spaces between the define and the CS_TIMER...
might make it easier to grep for.
> +static void __iomem *cs_base;
> +static void __iomem *ce_base;
> +
> +static void tmrb_set_mode(enum clock_event_mode mode,
> + struct clock_event_device *dev)
> +{
> + switch (mode) {
> + case CLOCK_EVT_MODE_PERIODIC:
> + writel((tickrate / HZ), ce_base + SPMP8000_TMRB_LDR);
> + /* Configure as periodic, down counter, IEN, enable timer */
> + writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_IE |
> + (1 << SPMP8000_TMRB_CTR_M_SH),
> + ce_base + SPMP8000_TMRB_CTR);
> + break;
> + case CLOCK_EVT_MODE_ONESHOT:
> + BUG();
> + break;
This case can be folded into the CLOCK_EVT_MODE_RESUME case (and changed
to be a default case).
> + case CLOCK_EVT_MODE_SHUTDOWN:
> + case CLOCK_EVT_MODE_UNUSED:
> + /* Disable timer */
> + writel(0, ce_base + SPMP8000_TMRB_CTR);
> + break;
> + case CLOCK_EVT_MODE_RESUME:
> + BUG();
> + break;
> + }
> +}
> +
> +static struct clock_event_device tmrb1_clkevt = {
> + .name = "tmrb1",
> + .features = CLOCK_EVT_FEAT_PERIODIC,
> + .rating = 200,
> + .set_mode = tmrb_set_mode,
> +};
> +
> +static irqreturn_t tmrb1_isr(int irq, void *dev_id)
> +{
> + tmrb1_clkevt.event_handler(&tmrb1_clkevt);
> +
> + /* Clear IRQ */
> + writel(0, ce_base + SPMP8000_TMRB_ISR);
> +
> + return IRQ_HANDLED;
> +};
> +
> +static struct irqaction tmrb1_irq = {
> + .name = "tmrb1_irq",
> + .flags = IRQF_TIMER | IRQF_IRQPOLL,
> + .handler = tmrb1_isr,
> +};
> +
> +static void __init spmp8000_sys_timer_init(void)
> +{
> + struct device_node *np;
> + unsigned int irq;
> + struct clk *clk;
> + void *tmrb_base;
> +
> + np = of_find_compatible_node(NULL, NULL, "sunplus,spmp8000-timer");
> + if (!np)
> + panic("spmp8000: unable to find timer node in dtb\n");
> +
> + tmrb_base = of_iomap(np, 0);
> + if (!tmrb_base)
> + panic("spmp8000: unable to map timer cpu registers\n");
> +
> + irq = of_irq_to_resource(np, CE_TIMER, NULL);
> + if (irq == NO_IRQ)
> + panic("spmp8000: unable to get interrupts of timer\n");
> +
> + of_node_put(np);
> +
> + cs_base = tmrb_base + SPMP8000_TMRB(CS_TIMER);
> + ce_base = tmrb_base + SPMP8000_TMRB(CE_TIMER);
> +
> + clk = clk_get(NULL, "arm_apb");
> + if (IS_ERR_OR_NULL(clk))
NULL can actually be a valid clk cookie so this should just be
IS_ERR(clk).
> + panic("spmp8000: Can't get clock for timer device");
> +
> + clk_enable(clk);
Should probably check for success/failure here.
> + clkrate = clk_get_rate(clk);
> +
> + /* Clocksource */
> + /* Disable timer */
> + writel(0, cs_base + SPMP8000_TMRB_CTR);
> +
> + /* Reset counter value
> + * Not really possible unless setting end-1 LDR value and waiting
> + * until the counter reaches that */
> +
> + /* Prescale timer */
> + writel((clkrate / tickrate) - 1, cs_base + SPMP8000_TMRB_PSR);
> +
> + /* Register the clocksource */
> + clocksource_mmio_init(cs_base + SPMP8000_TMRB_VLR, "tmrb2",
> + tickrate, 200, 16, clocksource_mmio_readl_up);
> +
> + /* Configure as free running (0 - 0xFFFF), up counter, enable timer */
> + writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_UD,
> + cs_base + SPMP8000_TMRB_CTR);
> +
> + /* Clockevent */
> + setup_irq(irq, &tmrb1_irq);
> +
> + /* Disable timer */
> + writel(0, ce_base + SPMP8000_TMRB_CTR);
> +
> + /* Prescale timer */
> + writel((clkrate / tickrate) - 1, ce_base + SPMP8000_TMRB_PSR);
> +
> + clockevents_register_device(&tmrb1_clkevt);
> +}
> +
> +struct sys_timer spmp8000_sys_timer = {
> + .init = spmp8000_sys_timer_init,
> +};
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
@ 2011-10-09 17:25 ` Jamie Iles
2011-10-10 1:43 ` Linus Walleij
2011-10-13 9:53 ` Russell King - ARM Linux
2 siblings, 0 replies; 78+ messages in thread
From: Jamie Iles @ 2011-10-09 17:25 UTC (permalink / raw)
To: linux-arm-kernel
Hi Zoltan,
On Sun, Oct 09, 2011 at 06:36:12PM +0200, Zoltan Devai wrote:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> arch/arm/Kconfig | 16 ++++++++++++++++
> arch/arm/Makefile | 1 +
> 2 files changed, 17 insertions(+), 0 deletions(-)
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 9426e26..f34f10d 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -831,6 +831,22 @@ config ARCH_SHARK
> Support for the StrongARM based Digital DNARD machine, also known
> as "Shark" (<http://www.shark-linux.de/shark.html>).
>
> +config ARCH_SPMP8000
> + bool "Sunplus SPMP8000"
> + select CPU_ARM926T
> + select ARM_VIC
> + select GENERIC_IRQ_CHIP
> + select MULTI_IRQ_HANDLER
> + select CLKSRC_MMIO
> + select GENERIC_CLOCKEVENTS
> + select ARCH_WANT_OPTIONAL_GPIOLIB
> + select USE_OF
> + select CLKDEV_LOOKUP
> + select HAVE_PWM
> + select ARCH_HAS_CPUFREQ
I can't see anything using cpufreq yet so perhaps this can be removed
for now?
Jamie
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-09 16:36 ` [PATCH 4/9] ARM: SPMP8000: Add ADC driver Zoltan Devai
@ 2011-10-10 1:29 ` Linus Walleij
2011-10-10 9:42 ` Jonathan Cameron
0 siblings, 1 reply; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 1:29 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Zoltan Devai <zoss@devai.org>:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> ?arch/arm/mach-spmp8000/adc.c ? ? ? ? ? ? ? ? ? ? ?| ?465 +++++++++++++++++++++
> ?arch/arm/mach-spmp8000/include/mach/spmp8000adc.h | ? 29 ++
I think we stopped stuffing misc drivers under arch/arm/*
And stuffing them under drivers/misc/* won't be popular either.
IIO has some ADCs in drivers/staging/iio/adc
these seem all to be intended to be used from userspace.
There are a few in-kernel ADCs all over the kernel tree
for various specific purposes.
I don't know where we should go with this kind of stuff,
really :-/
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 5/9] ARM: SPMP8000: Add pinmux driver
2011-10-09 16:36 ` [PATCH 5/9] ARM: SPMP8000: Add pinmux driver Zoltan Devai
@ 2011-10-10 1:32 ` Linus Walleij
2011-10-10 8:01 ` Barry Song
0 siblings, 1 reply; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 1:32 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Zoltan Devai <zoss@devai.org>:
> ?arch/arm/mach-spmp8000/pinmux.c | ?131 +++++++++++++++++++++++++++++++++++++++
> ?1 files changed, 131 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-spmp8000/pinmux.c
I'm creating this new pin control and pin mux subsystem,
set for next merge window. Can you check it out and see
if it does what you need?
http://marc.info/?l=linux-kernel&m=131805699106465&w=2
Thanks,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS
2011-10-09 16:36 ` [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS Zoltan Devai
@ 2011-10-10 1:35 ` Linus Walleij
2011-10-10 13:59 ` Zoltan Devai
0 siblings, 1 reply; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 1:35 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Zoltan Devai <zoss@devai.org>:
> This is unneeded and causes an abort on the SPMP8000 platform.
>
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> ?arch/arm/common/vic.c | ? ?1 -
> ?1 files changed, 0 insertions(+), 1 deletions(-)
>
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index b22b83d..651c77d 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -274,7 +274,6 @@ static void __init vic_disable(void __iomem *base)
> ? ? ? ?writel(0, base + VIC_INT_SELECT);
> ? ? ? ?writel(0, base + VIC_INT_ENABLE);
> ? ? ? ?writel(~0, base + VIC_INT_ENABLE_CLEAR);
> - ? ? ? writel(0, base + VIC_IRQ_STATUS);
> ? ? ? ?writel(0, base + VIC_ITCR);
> ? ? ? ?writel(~0, base + VIC_INT_SOFT_CLEAR);
> ?}
Indeed.
This patch stands on its own, please put it into Russell's patch
tracker at http://www.arm.linux.org.uk/developer/patches/
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
2011-10-09 17:25 ` Jamie Iles
@ 2011-10-10 1:43 ` Linus Walleij
2011-10-13 9:53 ` Russell King - ARM Linux
2 siblings, 0 replies; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 1:43 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Zoltan Devai <zoss@devai.org>:
> +config ARCH_SPMP8000
> + ? ? ? bool "Sunplus SPMP8000"
> + ? ? ? select CPU_ARM926T
> + ? ? ? select ARM_VIC
It's quite common for ARM926EJ-S systems to have TCM,
if you don't know whether your system has it just try
select HAVE_TCM for fun and see if it is detected on boot.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 6/9] ARM: SPMP8000: Add pwm driver
2011-10-09 16:36 ` [PATCH 6/9] ARM: SPMP8000: Add pwm driver Zoltan Devai
@ 2011-10-10 1:50 ` Linus Walleij
2011-10-10 9:30 ` Sascha Hauer
0 siblings, 1 reply; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 1:50 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Zoltan Devai <zoss@devai.org>:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> ?arch/arm/mach-spmp8000/pwm.c | ?246 ++++++++++++++++++++++++++++++++++++++++++
> ?1 files changed, 246 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/mach-spmp8000/pwm.c
Also PWM should have its own subsystem, sadly that is an area
where discussions about the patches for generic PWM in
drivers/pwm/ by Sascha Hauer seem to have stalled recently. :-(
Those we have tend to live in drivers/misc/ and drivers/mfd/
which is not good.
Kudos to Sascha for trying to solve the mess, we need more
subsystems...
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 5/9] ARM: SPMP8000: Add pinmux driver
2011-10-10 1:32 ` Linus Walleij
@ 2011-10-10 8:01 ` Barry Song
2011-10-10 8:34 ` Linus Walleij
0 siblings, 1 reply; 78+ messages in thread
From: Barry Song @ 2011-10-10 8:01 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/10 Linus Walleij <linus.walleij@linaro.org>:
> 2011/10/9 Zoltan Devai <zoss@devai.org>:
>
>> ?arch/arm/mach-spmp8000/pinmux.c | ?131 +++++++++++++++++++++++++++++++++++++++
>> ?1 files changed, 131 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/mach-spmp8000/pinmux.c
>
> I'm creating this new pin control and pin mux subsystem,
> set for next merge window. Can you check it out and see
> if it does what you need?
yes. Zoltan, you do need to follow Linus W's new pinmux framework.
And Linus, can you help to take care prima2 pinmux driver v3 i sent
yesterday and make sure it is merged in the window too.
our lots of device drivers depend on it, so i'd like it is ready
before we upstream lots of other drivers.
>
> http://marc.info/?l=linux-kernel&m=131805699106465&w=2
>
> Thanks,
> Linus Walleij
-barry
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 5/9] ARM: SPMP8000: Add pinmux driver
2011-10-10 8:01 ` Barry Song
@ 2011-10-10 8:34 ` Linus Walleij
0 siblings, 0 replies; 78+ messages in thread
From: Linus Walleij @ 2011-10-10 8:34 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 10:01 AM, Barry Song <21cnbao@gmail.com> wrote:
> And Linus, can you help to take care prima2 pinmux driver v3 i sent
> yesterday and make sure it is merged in the window too.
> our lots of device drivers depend on it, so i'd like it is ready
> before we upstream lots of other drivers.
It is taken care of and queued for the merge window :-)
If it gets merged in the end is up to Torvalds.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board
2011-10-09 16:36 ` [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board Zoltan Devai
@ 2011-10-10 8:54 ` Jamie Iles
0 siblings, 0 replies; 78+ messages in thread
From: Jamie Iles @ 2011-10-10 8:54 UTC (permalink / raw)
To: linux-arm-kernel
Hi Zoltan,
Just minor comments again. Also, if you could cc all device tree stuff
to devicetree-discuss at lists.ozlabs.org then you'll get a wider audience
for these bits.
Jamie
On Sun, Oct 09, 2011 at 06:36:10PM +0200, Zoltan Devai wrote:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> arch/arm/boot/dts/spmp8000-letcool.dts | 163 ++++++++++++++++++++++++++++++
> arch/arm/boot/dts/spmp8000.dtsi | 169 ++++++++++++++++++++++++++++++++
> 2 files changed, 332 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/boot/dts/spmp8000-letcool.dts
> create mode 100644 arch/arm/boot/dts/spmp8000.dtsi
>
> diff --git a/arch/arm/boot/dts/spmp8000-letcool.dts b/arch/arm/boot/dts/spmp8000-letcool.dts
> new file mode 100644
> index 0000000..270f00e
> --- /dev/null
> +++ b/arch/arm/boot/dts/spmp8000-letcool.dts
> @@ -0,0 +1,163 @@
> +/dts-v1/;
> +/include/ "spmp8000.dtsi"
> +/ {
> + model = "Letcool N350JP handheld game console";
> + compatible = "gameware,letcool", "sunplus,spmp8000";
> +
> + memory {
> + reg = <0x00000000 0x02000000>;
> + };
> +
> + chosen {
> + bootargs = "console=tty0 mem=32M root=/dev/mmcblk0p1 console=ttyS0,115200 rootdelay=5 loglevel=8 earlyprintk";
It's preferred to keep bootargs in the bootloader if at all possible.
> + linux,stdout-path = &uart0;
> + };
> +
> + pwm-backlight {
> + compatible = "pwm-backlight";
> + reg = <0 0>; /* Hack to pass platform data as AUXDATA */
> + };
> +
> + plat {
> + plat-apb {
> + mmc at 92B0B000 {
> + cd-gpios = <&gpio0 9 0>;
> + };
> + };
> + };
> +
> + armapb {
> + gpio at 9000A000 {
> + polarity = <0>;
> + sticky = <0>;
> + direction = <0xFFFFFFFF>;
> + debounce-val = <100>;
> + debounce = <0xFFFFFFFF>;
> + };
> +
> + gpio at 9000A004 {
> + polarity = <0>;
> + sticky = <0>;
> + direction = <0xFFFFFFFF>;
> + debounce-val = <100>;
> + debounce = <0xFFFFFFFF>;
> + };
> + };
> +
> + gpio-keys {
> + compatible = "gpio-keys";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + autorepeat;
> +
> + up {
> + label = "D-Pad Up";
> + gpios = <&gpio0 0 0>;
> + linux,code = <103>; /* KEY_UP */
> + gpio-key,wakeup;
> + };
> +
> + right {
> + label = "D-Pad Right";
> + gpios = <&gpio0 1 0>;
> + linux,code = <106>; /* KEY_RIGHT */
> + gpio-key,wakeup;
> + };
> +
> + down {
> + label = "D-Pad Down";
> + gpios = <&gpio0 2 0>;
> + linux,code = <108>; /* KEY_DOWN */
> + gpio-key,wakeup;
> + };
> +
> + left {
> + label = "D-Pad Left";
> + gpios = <&gpio0 3 0>;
> + linux,code = <105>; /* KEY_LEFT */
> + gpio-key,wakeup;
> + };
> +
> + button-x {
> + label = "Button X";
> + gpios = <&gpio0 4 0>;
> + linux,code = <45>; /* KEY_X */
> + gpio-key,wakeup;
> + };
> +
> + button-a {
> + label = "Button A";
> + gpios = <&gpio0 5 0>;
> + linux,code = <30>; /* KEY_A */
> + gpio-key,wakeup;
> + };
> +
> + button-y {
> + label = "Button Y";
> + gpios = <&gpio0 6 0>;
> + linux,code = <21>; /* KEY_Y */
> + gpio-key,wakeup;
> + };
> +
> + button-b {
> + label = "Button B";
> + gpios = <&gpio0 7 0>;
> + linux,code = <48>; /* KEY_B */
> + gpio-key,wakeup;
> + };
> + };
> +
> + analog-keys {
> + compatible = "spmp8000-ak";
> +
> + channel-1 {
> + adc-channel = <1>;
> + idle-value = <0>;
> + tolerance = <10>;
> +
> + button-left {
> + adc-value = <0x00B0>;
> + linux,code = <0x110>; /* BTN_LEFT */
> + };
> +
> + button-right {
> + adc-value = <0xFEAB>;
> + linux,code = <0x111>; /* BTN_RIGHT */
> + };
> +
> + button-volup {
> + adc-value = <0x015E>;
> + linux,code = <115>; /* KEY_VOLUMEUP */
> + };
> +
> + button-voldown {
> + adc-value = <0xFF56>;
> + linux,code = <114>; /* KEY_VOLUMEDOWN */
> + };
> + };
> +
> + channel-3 {
> + adc-channel = <3>;
> + idle-value = <5>;
> + tolerance = <10>;
> +
> + button-select {
> + adc-value = <0x0113>;
> + linux,code = <0x13a>; /* BTN_SELECT */
> + };
> +
> + button-start {
> + adc-value = <0xFEF7>;
> + linux,code = <0x13b>; /* BTN_START */
> + };
> + };
> +
> + };
> +
> + snd-card {
> + compatible = "spmp8000-sndcard";
> + hp-detect-gpios = <&gpio0 8 0>;
> + spk-enable-gpios = <&gpio3 12 0>;
> + };
> +
> +};
> diff --git a/arch/arm/boot/dts/spmp8000.dtsi b/arch/arm/boot/dts/spmp8000.dtsi
> new file mode 100644
> index 0000000..74764b2c6
> --- /dev/null
> +++ b/arch/arm/boot/dts/spmp8000.dtsi
> @@ -0,0 +1,169 @@
> +/ {
> + compatible = "sunplus,spmp8000";
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + armapb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x90000000 0x90000000 0x10000>;
I'm not sure you need a ranges property like this as it isn't doing any
translation. I think it would be nicer to have ranges = <0 0x90000000
0x10000> and use bus local addresses for the child nodes.
> + timer at 90000000 {
> + compatible = "sunplus,spmp8000-timer";
> + reg = <0x90000000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <7 8 9>;
> + };
> +
> + pwm at 90000000 {
> + compatible = "sunplus,spmp8000-pwm";
> + reg = <0x90000000 0x1000>;
> + id = <0>;
This is probably a little too generic. sunplus,pwm-id ?
> + };
> +
> + gpio3: gpio at 90005070 {
> + compatible = "basic-mmio-gpio"; /* No DT binding yet */
I did start work on a binding
(http://lists.ozlabs.org/pipermail/devicetree-discuss/2011-August/007137.html)
but it hasn't moved along too far. Thinking about it a little more
though I'm not sure that the generic binding is quite the right approach
if we need to handle gpio's that can generate interrupts too though.
> + reg = <0x90005070 0xC>;
> + gpio-controller;
> + #gpio-cells = <2>;
> + };
> +
> + gpio0: gpio at 9000A000 {
> + compatible = "sunplus,spmp8000-gpio";
> + reg = <0x9000A000 0x1000>;
> + interrupt-parent = <&vic1>;
> + interrupts = <0>;
> + gpio-controller;
> + #gpio-cells = <2>;
> + bits = <16>;
sunplus,nr-gpios?
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> +
> + gpio1: gpio at 9000A004 {
> + compatible = "sunplus,spmp8000-gpio";
> + reg = <0x9000A004 0x1000>;
> + interrupt-parent = <&vic1>;
> + interrupts = <1>;
> + gpio-controller;
> + #gpio-cells = <2>;
> + bits = <32>;
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + };
> + };
> +
> + armahb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x90010000 0x90010000 0x20000>;
> +
> + vic0: interrupt-controller at 90010000 {
> + compatible = "arm,pl192";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + reg = <0x90010000 0x1000>;
> + };
> +
> + vic1: interrupt-controller at 900020000 {
> + compatible = "arm,pl192";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + reg = <0x90020000 0x1000>;
> + };
> + };
> +
> + plat {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x92000000 0x92000000 0x1000000>;
> +
> + plat-apb {
Why are there 2 levels of nesting here? Can't the child nodes of
plat-apb just be under plat?
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x92B00000 0x92B00000 0x10000>;
> +
> + dma at 92B00000 {
> + compatible = "sunplus,spmp8000-apbdma-c";
> + reg = <0x92B00000 0x1000>;
> + interrupt-parent = <&vic1>;
> + interrupts = <28 29 30 31>;
> + };
> +
> + uart0: uart-c0 at 92B04000 {
> + compatible = "ns16550a";
> + reg = <0x92B04000 0x1000>;
> + clock-frequency = <2076923>;
> + interrupt-parent = <&vic1>;
> + interrupts = <24>;
> + current-speed = <115200>;
> + reg-shift = <2>;
> + };
> +
> + mmc at 92B0B000 {
> + compatible = "sunplus,mmc";
> + reg = <0x92B0B000 0x1000>;
> + interrupt-parent = <&vic1>;
> + interrupts = <8>;
> + };
> + };
> + };
> +
> + axi {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x93000000 0x93000000 0x800000>;
> +
> + fb at 93000000 {
> + compatible = "sunplus,spmp8000-lcd";
> + reg = <0x93000000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <23>;
> + };
> +
> + axi-apb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0x93010000 0x93010000 0x10000>;
> +
> + dma at 93010000 {
> + compatible = "sunplus,spmp8000-apbdma-a";
> + reg = <0x93010000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <24 25 26 27>;
> + };
> +
> + i2s at 93012000 {
> + compatible = "sunplus,spmp8000-i2s-tx";
> + reg = <0x93012000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <13>;
> + };
> +
> + i2s at 9301D000 {
> + compatible = "sunplus,spmp8000-i2s-rx";
> + reg = <0x9301D000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <14>;
> + };
> +
> + adc at 9301F000 {
> + compatible = "sunplus,spmp8000-adc";
> + reg = <0x9301F000 0x20>;
> + interrupt-parent = <&vic1>;
> + interrupts = <27>;
> + };
> +
> + codec at 9301F020 {
> + compatible = "sunplus,spmp8000-codec";
> + reg = <0x9301F020 0x20>;
> + };
> + };
> + };
> +};
> --
> 1.7.4.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply [flat|nested] 78+ messages in thread
* Add support for the SPMP8000 SoC and Letcool board
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (8 preceding siblings ...)
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
@ 2011-10-10 8:55 ` Jamie Iles
2011-10-10 12:00 ` Zoltan Devai
2011-10-11 14:57 ` Arnd Bergmann
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
11 siblings, 1 reply; 78+ messages in thread
From: Jamie Iles @ 2011-10-10 8:55 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 09, 2011 at 06:36:03PM +0200, Zoltan Devai wrote:
> Hi,
>
> This series adds support for the Sunplus SPMP8000 SoC, an ARM926EJ-S based
> MCU, which is most commonly found in handheld game consoles and digital cams.
> Most of the work was done during GSoC 2011, with Greg KH as my mentor.
>
> The board I'm using for development is the Letcool N350JP handheld.
>
> The patches are based on Arnds for-next branch with Jamie Iles' vic-dt patches
> on top.
Excellent! Can I take that as a Tested-by from you for that series?
Jamie
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 6/9] ARM: SPMP8000: Add pwm driver
2011-10-10 1:50 ` Linus Walleij
@ 2011-10-10 9:30 ` Sascha Hauer
0 siblings, 0 replies; 78+ messages in thread
From: Sascha Hauer @ 2011-10-10 9:30 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 03:50:51AM +0200, Linus Walleij wrote:
> 2011/10/9 Zoltan Devai <zoss@devai.org>:
>
> > Signed-off-by: Zoltan Devai <zoss@devai.org>
> > ---
> > ?arch/arm/mach-spmp8000/pwm.c | ?246 ++++++++++++++++++++++++++++++++++++++++++
> > ?1 files changed, 246 insertions(+), 0 deletions(-)
> > ?create mode 100644 arch/arm/mach-spmp8000/pwm.c
>
> Also PWM should have its own subsystem, sadly that is an area
> where discussions about the patches for generic PWM in
> drivers/pwm/ by Sascha Hauer seem to have stalled recently. :-(
>
> Those we have tend to live in drivers/misc/ and drivers/mfd/
> which is not good.
>
> Kudos to Sascha for trying to solve the mess, we need more
> subsystems...
Thanks, I'll respin these patches when I find the time. In the mean
time if anyone wants to work on this my latest branch is here:
git://git.pengutronix.de/git/imx/linux-2.6.git pwmlib
It contains the pwm framework and converts most in tree drivers to
the new framework.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 1:29 ` Linus Walleij
@ 2011-10-10 9:42 ` Jonathan Cameron
2011-10-10 9:46 ` Jonathan Cameron
2011-10-10 10:00 ` Mark Brown
0 siblings, 2 replies; 78+ messages in thread
From: Jonathan Cameron @ 2011-10-10 9:42 UTC (permalink / raw)
To: linux-arm-kernel
On 10/10/11 02:29, Linus Walleij wrote:
> 2011/10/9 Zoltan Devai <zoss@devai.org>:
>
>> Signed-off-by: Zoltan Devai <zoss@devai.org>
>> ---
>> arch/arm/mach-spmp8000/adc.c | 465 +++++++++++++++++++++
>> arch/arm/mach-spmp8000/include/mach/spmp8000adc.h | 29 ++
>
> I think we stopped stuffing misc drivers under arch/arm/*
>
> And stuffing them under drivers/misc/* won't be popular either.
>
> IIO has some ADCs in drivers/staging/iio/adc
> these seem all to be intended to be used from userspace.
Yeah, we've had various discussions about adding support for
in kernel users. Its always fallen on the fact that no one
has had the time to write the code to allow it all to be
linked up. Right now it's a case of drivers providing their
own interfaces if they want to allow this.
Mark Brown has raised this issue before so I've cc'd him.
For reference of those not following the original thread (based
on a quick scan of the driver code in question).
Driver has two callback sets:
1) Touch panel reads (I guess going straight to an input driver)
(1 of these only). This is annoyingly tied up with the more general
adc registers.
2) General purpose adc callbacks.
Both are driven off an interrupt, but data ready
appears to manually driven (so software triggered sampling then data
ready signal when sampling is done for a single channel).
So what are these callbacks used for? Note they all run as
interrupt top halves...
Options at current time are:
mfd supporting input device and either hwmon or iio device.
A driver that hosts both a hwmon / iio and an input device.
Be brave (+ have a lot of time) and propose patches adding the relevant
tying together code to allow iio drivers to be queried in kernel.
It shouldn't be that bad actually if you solve the how to work
out which device / channel you want in a consistent way.
It really depends on what those general adc callbacks get used for.
>
> There are a few in-kernel ADCs all over the kernel tree
> for various specific purposes.
>
> I don't know where we should go with this kind of stuff,
> really :-/
>
> Yours,
> Linus Walleij
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 9:42 ` Jonathan Cameron
@ 2011-10-10 9:46 ` Jonathan Cameron
2011-10-10 10:00 ` Mark Brown
1 sibling, 0 replies; 78+ messages in thread
From: Jonathan Cameron @ 2011-10-10 9:46 UTC (permalink / raw)
To: linux-arm-kernel
On 10/10/11 10:42, Jonathan Cameron wrote:
> On 10/10/11 02:29, Linus Walleij wrote:
>> 2011/10/9 Zoltan Devai <zoss@devai.org>:
>>
>>> Signed-off-by: Zoltan Devai <zoss@devai.org>
>>> ---
>>> arch/arm/mach-spmp8000/adc.c | 465 +++++++++++++++++++++
>>> arch/arm/mach-spmp8000/include/mach/spmp8000adc.h | 29 ++
>>
>> I think we stopped stuffing misc drivers under arch/arm/*
>>
>> And stuffing them under drivers/misc/* won't be popular either.
>>
>> IIO has some ADCs in drivers/staging/iio/adc
>> these seem all to be intended to be used from userspace.
> Yeah, we've had various discussions about adding support for
> in kernel users. Its always fallen on the fact that no one
> has had the time to write the code to allow it all to be
> linked up. Right now it's a case of drivers providing their
> own interfaces if they want to allow this.
> Mark Brown has raised this issue before so I've cc'd him.
>
> For reference of those not following the original thread (based
> on a quick scan of the driver code in question).
>
> Driver has two callback sets:
>
> 1) Touch panel reads (I guess going straight to an input driver)
> (1 of these only). This is annoyingly tied up with the more general
> adc registers.
> 2) General purpose adc callbacks.
>
> Both are driven off an interrupt, but data ready
> appears to manually driven (so software triggered sampling then data
> ready signal when sampling is done for a single channel).
>
> So what are these callbacks used for? Note they all run as
> interrupt top halves...
>
> Options at current time are:
>
> mfd supporting input device and either hwmon or iio device.
>
> A driver that hosts both a hwmon / iio and an input device.
>
> Be brave (+ have a lot of time) and propose patches adding the relevant
> tying together code to allow iio drivers to be queried in kernel.
> It shouldn't be that bad actually if you solve the how to work
> out which device / channel you want in a consistent way.
>
> It really depends on what those general adc callbacks get used for.
Ah, just taken a look at your dts file.
Looks like some are used for 'analog-keys'. So input? If so this
should probably be an entirely input driver for now.
>
>>
>> There are a few in-kernel ADCs all over the kernel tree
>> for various specific purposes.
>>
>> I don't know where we should go with this kind of stuff,
>> really :-/
>>
>> Yours,
>> Linus Walleij
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 9:42 ` Jonathan Cameron
2011-10-10 9:46 ` Jonathan Cameron
@ 2011-10-10 10:00 ` Mark Brown
2011-10-10 11:42 ` Zoltan Devai
1 sibling, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-10 10:00 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 10:42:49AM +0100, Jonathan Cameron wrote:
> It really depends on what those general adc callbacks get used for.
If it's a general purpose ADC it's up to the board designer - you
sometimes see things like battery or supply monitoring but really it
could be any low volume analogue input.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-09 17:22 ` Jamie Iles
@ 2011-10-10 11:36 ` Zoltan Devai
2011-10-10 11:52 ` Jamie Iles
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-10 11:36 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/9 Jamie Iles <jamie@jamieiles.com>:
> A couple of minor comments inline but this looks really good!
Thanks for reviewing! Comments inline.
> On Sun, Oct 09, 2011 at 06:36:05PM +0200, Zoltan Devai wrote:
> [...]
>> diff --git a/arch/arm/mach-spmp8000/Makefile b/arch/arm/mach-spmp8000/Makefile
>> new file mode 100644
>> index 0000000..9d35cca
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/Makefile
>> @@ -0,0 +1,11 @@
>> +#
>> +# Makefile for the linux kernel.
>> +#
>
> Nit: I don't think this comment adds a great deal of value.
Yep, but this seemed like a common pattern :)
I can't imagine anything that would add value, so will just
skip the header.
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?:= core.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= timer.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= pinmux.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= clock.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= clkdev.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= board_letcool.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= adc.o
>> +obj-y ? ? ? ? ? ? ? ? ? ? ? ?+= pwm.o
>> diff --git a/arch/arm/mach-spmp8000/core.c
>> b/arch/arm/mach-spmp8000/core.c
>> new file mode 100644
>> index 0000000..ba05614
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/core.c
>> @@ -0,0 +1,103 @@
>> +/*
>> + * SPMP8000 machines core functions
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/init.h>
>> +#include <linux/io.h>
>> +#include <linux/of.h>
>> +#include <asm/mach/map.h>
>> +#include <asm/hardware/vic.h>
>> +#include <mach/hardware.h>
>> +#include <mach/scu.h>
>> +
>> +/* Static mappings:
>> + * SCU: timer needs clk support which is inited in init_early
>> + * UART: needed for earlyprintk
>> + */
>> +static struct map_desc io_desc[] __initdata = {
>> + ? ? {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_A_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_A_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_A_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_B_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_B_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_B_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_C_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_C_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_C_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> +#ifdef CONFIG_DEBUG_LL
>> + ? ? {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_UARTC0_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_UARTC0_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_UARTC0_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> +#endif
>> +};
>> +
>> +#define IO_PTR(x) ? ?((void __iomem *)IO_ADDRESS(x))
>
> Generally IO_ADDRESS returns a void __iomem pointer so it would be
> easier if you could have the cast in there (though it may need to be
> enclosed in #ifndef __ASSEMBLY__ conditionals).
Every instance I've seen returns an int, mainly because it's used for
the static mappings above.
So, if I make IO_ADDRESS return void __iomem, I'd have to make
a macro for casting it back to int, and we'd be where we started.
>> +/* Make the lookup of SCU base and clk enable registers easy for the clk
>> + * code, as they are not at the same offset in each controller */
>> +struct scu_reg_t scu_regs[3] = {
>> + ? ? { ? ? ? /* SCU_A */
>> + ? ? ? ? ? ? .base = IO_PTR(SPMP8000_SCU_A_BASE),
>> + ? ? ? ? ? ? .clken = IO_PTR(SPMP8000_SCU_A_BASE) + SCU_A_PERI_CLKEN,
>> + ? ? },
>> + ? ? { ? ? ? /* SCU_B */
>> + ? ? ? ? ? ? .base = IO_PTR(SPMP8000_SCU_B_BASE),
>> + ? ? ? ? ? ? .clken = IO_PTR(SPMP8000_SCU_B_BASE) + SCU_B_PERI_CLKEN,
>> + ? ? },
>> + ? ? { ? ? ? /* SCU_C */
>> + ? ? ? ? ? ? .base = IO_PTR(SPMP8000_SCU_C_BASE),
>> + ? ? ? ? ? ? .clken = IO_PTR(SPMP8000_SCU_C_BASE) + SCU_C_PERI_CLKEN,
>> + ? ? },
>> +};
>> +
>> +/* DMA controller names to be used for the filter
>> + * function of the DMA-Engine API. */
>> +char *spmp8000_dma_controller_names[] = {
>
> const char * const?
Sure.
>> + ? ? "93010000.dma", ? ? ? ? /* APBDMA_A */
>> + ? ? "92b00000.dma", ? ? ? ? /* APBDMA_C */
>> +};
>> +
>> +void __init spmp8000_map_io(void)
>> +{
>> + ? ? iotable_init(io_desc, ARRAY_SIZE(io_desc));
>> +}
>> +
>> +void __init spmp8000_init_irq(void)
>> +{
>> + ? ? struct device_node *np;
>> + ? ? int ret;
>> +
>> + ? ? np = of_find_compatible_node(NULL, NULL, "arm,pl192");
>> + ? ? if (!np)
>> + ? ? ? ? ? ? panic("Can't find VIC0 interrupt controller\n");
>> +
>> + ? ? ret = vic_of_init(np, NULL);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? panic("Can't init VIC0 interrupt controller\n");
>> +
>> + ? ? np = of_find_compatible_node(np, NULL, "arm,pl192");
>> + ? ? if (!np)
>> + ? ? ? ? ? ? panic("Can't find VIC1 interrupt controller\n");
>> +
>> + ? ? ret = vic_of_init(np, NULL);
>> + ? ? if (ret)
>> + ? ? ? ? ? ? panic("Can't init VIC1 interrupt controller\n");
>> +
>> + ? ? of_node_put(np);
>
> So with Rob Herring's of_irq_init patches you should be able to reduce
> this to:
>
> ? ? ? ?static const struct of_device_id spmp8000_vic_matches[] = {
> ? ? ? ? ? ? ? ?{ .compatible = "arm,pl192", .data = vic_of_init },
> ? ? ? ?};
>
> ? ? ? ?of_irq_init(spmp8000_vic_matches);
>
> and that will handle both VIC's and ordering.
Works like a charm, thanks for the hint.
>> +}
>> diff --git a/arch/arm/mach-spmp8000/include/mach/core.h b/arch/arm/mach-spmp8000/include/mach/core.h
>> new file mode 100644
>> index 0000000..fa1d522
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/core.h
>> @@ -0,0 +1,29 @@
>> +/*
>> + * SPMP8000 generic includes
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef __MACH_SPMP8000_GENERIC_H__
>> +#define __MACH_SPMP8000_GENERIC_H__
>> +
>> +/* core.c */
>> +extern void __init spmp8000_map_io(void);
>> +extern void __init spmp8000_init_irq(void);
>
> Nit: you don't need the __init attributes in the header files.
Copy-paste it is. Removed.
>> +extern struct sys_timer spmp8000_sys_timer;
>> +
>> +/* clkdev.c */
>> +extern void __init spmp8000_init_clkdev(void);
>> +extern void spmp8000_update_arm_freqs(void); /* For cpufreq driver */
>> +
>> +/* pinmux.c */
>> +extern void spmp8000_pinmux_pgc_set(int pc, unsigned int conf);
>> +extern unsigned int spmp8000_pinmux_pgc_get(int pc);
>> +extern void spmp8000_pinmux_pgs_set(unsigned int pg, unsigned int func);
>> +extern int spmp8000_pinmux_pgs_get(int pg);
>> +
>> +#endif /* __MACH_SPMP8000_GENERIC_H__ */
> [...]
>> diff --git a/arch/arm/mach-spmp8000/include/mach/dma.h b/arch/arm/mach-spmp8000/include/mach/dma.h
>> new file mode 100644
>> index 0000000..44bc9f2
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/dma.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * SPMP8000 dma.h
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +#include <linux/module.h>
>> +#include <linux/dmaengine.h>
>
> It may be worth splitting the DMA part out into a separate patch unless
> this really is required for basic functionality.
I'll split these out for v2.
>> +
>> +#ifndef __MACH_SPMP8000_DMA_H__
>> +#define __MACH_SPMP8000_DMA_H__
>> +
>> +enum spmp8000_dma_controller {
>> + ? ? SPMP8000_APBDMA_A ? ? ? = 0,
>> + ? ? SPMP8000_APBDMA_C,
>> +};
>> +
>> +extern char *spmp8000_dma_controller_names[];
>> +
>> +struct spmp8000_dma_params {
>> + ? ? char ? ? ? ? ? ? ? ? ? ? ? ? ? ?*dma_controller;
>> + ? ? dma_addr_t ? ? ? ? ? ? ? ? ? ? ?dma_address;
>> + ? ? enum dma_slave_buswidth ? ? ? ? dma_width;
>> + ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? maxburst;
>> +};
>
> dmaengine has dma_slave_config that could be used for this, but I don't
> see any of this file being used in this series so perhaps it's worth
> adding in after the core stuff has been merged?
Will split.
This struct is used by the i2s driver to pass info to the pcm driver on how
to set up the dma controller. Seems to be the way to do.
>> +
>> +/* Driver parameters */
>> +#define SPMP8000_APBDMA_MAX_PERIODS ?64
>> +
>> +static bool spmp8000_dma_filter(struct dma_chan *chan, const char *name)
>> +{
>> + ? ? int ret;
>> +
>> + ? ? ret = strcmp(dev_name(chan->device->dev), name);
>> +
>> + ? ? if (ret)
>> + ? ? ? ? ? ? return false;
>> +
>> + ? ? return true;
>
> I think you can reduce this function to just
>
> ? ? ? ?return !strcmp(dev_name(chan->device->dev), name);
>
> and the compiler will do the right thing with int->bool conversion.
Yeah, just debugging leftover.
>> diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h
>> b/arch/arm/mach-spmp8000/include/mach/gpio.h
>> new file mode 100644
>> index 0000000..3eafac2
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/gpio.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * SPMP8000 machines gpio support
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef __MACH_SPMP8000_GPIO_H__
>> +#define __MACH_SPMP8000_GPIO_H__
>> +
>> +#include <asm-generic/gpio.h>
>> +
>> +#define gpio_get_value ? ? ? ? ? ? ? __gpio_get_value
>> +#define gpio_set_value ? ? ? ? ? ? ? __gpio_set_value
>> +#define gpio_cansleep ? ? ? ? ? ? ? ?__gpio_cansleep
>> +#define gpio_to_irq ? ? ? ? ?__gpio_to_irq
>
> Russell has a patch (ARM: gpio: make trivial GPIOLIB implementation the
> default) in for-next that means you shouldn't need these definitions
> anymore.
Which tree and branch should I base my work on ?
I'm quite confused by the all the options, and it seems like
if I choose some devel-stable tree, then I don't get the new
features and my work is outdated from the beginning,
but for-next branches are quite diverged.
Is there a good strategy ?
>> diff --git a/arch/arm/mach-spmp8000/include/mach/irqs.h
>> b/arch/arm/mach-spmp8000/include/mach/irqs.h
>> new file mode 100644
>> index 0000000..7f305d3
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/irqs.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * SPMP8000 irqs.h
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef __MACH_SPMP8000_IRQS_H__
>> +#define __MACH_SPMP8000_IRQS_H__
>> +
>> +#define SPMP8000_HW_IRQS ? ? ? ? ? ? 64
>> +#define SPMP8000_GPIO_IRQS_START ? ? SPMP8000_HW_IRQS
>> +#define SPMP8000_GPIO_IRQS ? ? ? ? ? (16 + 32)
>> +#define SPMP8000_TOTAL_IRQS ? ? ? ? ?(SPMP8000_HW_IRQS + SPMP8000_GPIO_IRQS)
>> +
>> +#define NR_IRQS ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?SPMP8000_TOTAL_IRQS
>
> I think that if you use my VIC patches then you can actually define
> NR_IRQS to 0 as all IRQ descs are dynamically allocated (otherwise
> you'll be reserving a bunch of irq_descs that never get used).
OK. Tried with 0, works.
>> diff --git a/arch/arm/mach-spmp8000/include/mach/regs-timer.h
>> b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
>> new file mode 100644
>> index 0000000..90735df
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + * SPMP8000 timer support
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + *
>> + * These timer reg definitions are used by the timer and pwm drivers
>> + */
>
> If these definitions are only being used inside arch/arm/mach-spmp8000
> then I'd put the headers in there rather than the
> arch/arm/mach-spmp8000/include/mach subdir so that the visibility is
> restricted to the mach code.
OK.
Depends on the final place of the PWM driver.
>> +#ifndef __MACH_SPMP8000_REGS_TIMER_H__
>> +#define __MACH_SPMP8000_REGS_TIMER_H__
>> +
>> +#define SPMP8000_TMRB(tnum) ?(tnum * 0x20)
>> +#define SPMP8000_TMRB_CTR ? ?0x00
>> +#define SPMP8000_TMRB_CTR_TE BIT(0)
>> +#define SPMP8000_TMRB_CTR_IE BIT(1)
>> +#define SPMP8000_TMRB_CTR_OE BIT(2)
>> +#define SPMP8000_TMRB_CTR_PWMON ? ? ?BIT(3)
>> +#define SPMP8000_TMRB_CTR_UD BIT(4)
>> +#define SPMP8000_TMRB_CTR_UDS ? ? ? ?BIT(5)
>> +#define SPMP8000_TMRB_CTR_OM BIT(6)
>> +#define SPMP8000_TMRB_CTR_ES_SH ? ? ?8
>> +#define SPMP8000_TMRB_CTR_M_SH ? ? ? 10
>> +#define SPMP8000_TMRB_PSR ? ?0x04
>> +#define SPMP8000_TMRB_LDR ? ?0x08
>> +#define SPMP8000_TMRB_VLR ? ?0x08
>> +#define SPMP8000_TMRB_ISR ? ?0x0C
>> +#define SPMP8000_TMRB_CMP ? ?0x10
>> +
>> +#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
>> diff --git a/arch/arm/mach-spmp8000/include/mach/scu.h b/arch/arm/mach-spmp8000/include/mach/scu.h
>> new file mode 100644
>> index 0000000..e3a98d4
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/scu.h
>
> Same here as the timer regs stuff.
OK, this can definitely move.
>> @@ -0,0 +1,146 @@
>> +/*
>> + * SPMP8000 System Control Unit register definitions
>> + * SCUs are a random collection of reset, clock, gpio, pinmux, etc. controllers
>> + * so that these definitions are needed at several places.
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#include <linux/bitops.h>
>> +#include <mach/hardware.h>
>> +
>> +#ifndef __MACH_SPMP8000_SCU_H__
>> +#define __MACH_SPMP8000_SCU_H__
>> +
>> +/* Used by to the clock code to directly access the SCU base and clock
>> + * enabling registers, without looking up the according registers first.
>> + */
>> +struct scu_reg_t {
>
> Generally speaking _t isn't used for structs.
OK.
>> + ? ? void *base;
>> + ? ? void *clken;
>
> Shouldn't these be void __iomem *?
Yes.
>> +};
>> +
>> +extern struct scu_reg_t scu_regs[];
>> +
>> +#define REG_SCU_BASE(x) ? ? ? ? ? ? ?scu_regs[x].base
>> +#define REG_SCU_CLKEN(x) ? ? scu_regs[x].clken
>> +#define REG_SCU_A_ID ? ? ? ? 0
>> +#define REG_SCU_B_ID ? ? ? ? 1
>> +#define REG_SCU_C_ID ? ? ? ? 2
>> +#define REG_SCU_A(x) ? ? ? ? (scu_regs[REG_SCU_A_ID].base + x)
>> +#define REG_SCU_B(x) ? ? ? ? (scu_regs[REG_SCU_B_ID].base + x)
>> +#define REG_SCU_C(x) ? ? ? ? (scu_regs[REG_SCU_C_ID].base + x)
>
> macros that assume there is a variable in scope with a given name
> (scu_regs) are generally frowned upon as it's difficult to see what's
> going on and can be a little error prone.
Yes, this isn't really nice. Will work out another way.
>> diff --git a/arch/arm/mach-spmp8000/include/mach/system.h
>> b/arch/arm/mach-spmp8000/include/mach/system.h
>> new file mode 100644
>> index 0000000..be53ff3
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/system.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * SPMP8000 system.h
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef __MACH_SPMP8000_SYSTEM_H__
>> +#define __MACH_SPMP8000_SYSTEM_H__
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/io.h>
>> +
>> +#define SPMP8000_WDT_BASE ? ?0x90001000
>> +#define SPMP8000_WDT_SIZE ? ?0x1000
>> +
>> +#define SPMP8000_WDT_CTR ? ? 0x00
>> +#define SPMP8000_WDT_CTR_TE ?BIT(0)
>> +#define SPMP8000_WDT_CTR_RE ?BIT(3)
>> +
>> +static inline void arch_idle(void)
>> +{
>> + ? ? cpu_do_idle();
>> +}
>> +
>> +static inline void arch_reset(char mode, const char *cmd)
>> +{
>> + ? ? void *base;
>> +
>> + ? ? base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
>> + ? ? if (!base) {
>> + ? ? ? ? ? ? pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
>> + ? ? ? ? ? ? ? ? ? ? "Halt.");
>> + ? ? ? ? ? ? while (1);
>> + ? ? }
>
> It may be worth doing the ioremap earlier when the system is in a known
> good state with all functions available rather than at reset time.
Any suggestion where the best place would be ?
I can only think of either the timer init or the board init, but neither seemed
to be appropriate.
>> +
>> + ? ? /* Trigger a watchdog reset */
>> + ? ? writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
>> + ? ? ? ? ? ? ? ? ? ? base + SPMP8000_WDT_CTR);
>> +}
> [...]
>> diff --git a/arch/arm/mach-spmp8000/timer.c
>> b/arch/arm/mach-spmp8000/timer.c
>> new file mode 100644
>> index 0000000..7d5d0eb
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/timer.c
>> @@ -0,0 +1,160 @@
>> +/*
>> + * SPMP8000 machines timer functions
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/irq.h>
>> +#include <linux/io.h>
>> +#include <linux/err.h>
>> +#include <linux/bitops.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/clockchips.h>
>> +#include <linux/clk.h>
>> +#include <asm/mach/time.h>
>> +
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <mach/hardware.h>
>> +#include <mach/regs-timer.h>
>> +#include <mach/irqs.h>
>> +
>> +static unsigned long clkrate;
>> +static const unsigned int tickrate = 1012500;
>> +
>> +/* The TIMER_B block is used as system timer
>> + * T2: Clocksource
>> + * T1: Clockevent
>> + * T0: PWM for LCD backlight
>> + * T3,4: Could be used as additional clockevent devices
>> + * Timer constraints:
>> + * - WDT: Can't clear the irq directly, only by resetting the whole counter
>> + * ? in the ISR, which means that IRQs will jitter
>> + * - Timer_B: Can't reset the timer value, so at start, the first IRQ
>> + * ? will happen at some random time.
>> + */
>> +#define ? ? ? ? ? ? ?CS_TIMER ? ? ? ?2
>> +#define ? ? ? ? ? ? ?CE_TIMER ? ? ? ?1
>
> Nit: removing the extra spaces between the define and the CS_TIMER...
> might make it easier to grep for.
OK.
>> +static void __iomem *cs_base;
>> +static void __iomem *ce_base;
>> +
>> +static void tmrb_set_mode(enum clock_event_mode mode,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct clock_event_device *dev)
>> +{
>> + ? ? switch (mode) {
>> + ? ? case CLOCK_EVT_MODE_PERIODIC:
>> + ? ? ? ? ? ? writel((tickrate / HZ), ce_base + SPMP8000_TMRB_LDR);
>> + ? ? ? ? ? ? /* Configure as periodic, down counter, IEN, enable timer */
>> + ? ? ? ? ? ? writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_IE |
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? (1 << SPMP8000_TMRB_CTR_M_SH),
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ce_base + SPMP8000_TMRB_CTR);
>> + ? ? ? ? ? ? break;
>> + ? ? case CLOCK_EVT_MODE_ONESHOT:
>> + ? ? ? ? ? ? BUG();
>> + ? ? ? ? ? ? break;
>
> This case can be folded into the CLOCK_EVT_MODE_RESUME case (and changed
> to be a default case).
OK.
>> + ? ? case CLOCK_EVT_MODE_SHUTDOWN:
>> + ? ? case CLOCK_EVT_MODE_UNUSED:
>> + ? ? ? ? ? ? /* Disable timer */
>> + ? ? ? ? ? ? writel(0, ce_base + SPMP8000_TMRB_CTR);
>> + ? ? ? ? ? ? break;
>> + ? ? case CLOCK_EVT_MODE_RESUME:
>> + ? ? ? ? ? ? BUG();
>> + ? ? ? ? ? ? break;
>> + ? ? }
>> +}
>> +
>> +static struct clock_event_device tmrb1_clkevt = {
>> + ? ? .name ? ? ? ? ? = "tmrb1",
>> + ? ? .features ? ? ? = CLOCK_EVT_FEAT_PERIODIC,
>> + ? ? .rating ? ? ? ? = 200,
>> + ? ? .set_mode ? ? ? = tmrb_set_mode,
>> +};
>> +
>> +static irqreturn_t tmrb1_isr(int irq, void *dev_id)
>> +{
>> + ? ? tmrb1_clkevt.event_handler(&tmrb1_clkevt);
>> +
>> + ? ? /* Clear IRQ */
>> + ? ? writel(0, ce_base + SPMP8000_TMRB_ISR);
>> +
>> + ? ? return IRQ_HANDLED;
>> +};
>> +
>> +static struct irqaction tmrb1_irq = {
>> + ? ? .name ? ? ? ? ? = "tmrb1_irq",
>> + ? ? .flags ? ? ? ? ?= IRQF_TIMER | IRQF_IRQPOLL,
>> + ? ? .handler ? ? ? ?= tmrb1_isr,
>> +};
>> +
>> +static void __init spmp8000_sys_timer_init(void)
>> +{
>> + ? ? struct device_node *np;
>> + ? ? unsigned int irq;
>> + ? ? struct clk *clk;
>> + ? ? void *tmrb_base;
>> +
>> + ? ? np = of_find_compatible_node(NULL, NULL, "sunplus,spmp8000-timer");
>> + ? ? if (!np)
>> + ? ? ? ? ? ? panic("spmp8000: unable to find timer node in dtb\n");
>> +
>> + ? ? tmrb_base = of_iomap(np, 0);
>> + ? ? if (!tmrb_base)
>> + ? ? ? ? ? ? panic("spmp8000: unable to map timer cpu registers\n");
>> +
>> + ? ? irq = of_irq_to_resource(np, CE_TIMER, NULL);
>> + ? ? if (irq == NO_IRQ)
>> + ? ? ? ? ? ? panic("spmp8000: unable to get interrupts of timer\n");
>> +
>> + ? ? of_node_put(np);
>> +
>> + ? ? cs_base = tmrb_base + SPMP8000_TMRB(CS_TIMER);
>> + ? ? ce_base = tmrb_base + SPMP8000_TMRB(CE_TIMER);
>> +
>> + ? ? clk = clk_get(NULL, "arm_apb");
>> + ? ? if (IS_ERR_OR_NULL(clk))
>
> NULL can actually be a valid clk cookie so this should just be
> IS_ERR(clk).
OK.
>> + ? ? ? ? ? ? panic("spmp8000: Can't get clock for timer device");
>> +
>> + ? ? clk_enable(clk);
>
> Should probably check for success/failure here.
OK.
>> + ? ? clkrate = clk_get_rate(clk);
>> +
>> + ? ? /* Clocksource */
>> + ? ? /* Disable timer */
>> + ? ? writel(0, cs_base + SPMP8000_TMRB_CTR);
>> +
>> + ? ? /* Reset counter value
>> + ? ? ?* Not really possible unless setting end-1 LDR value and waiting
>> + ? ? ?* until the counter reaches that */
>> +
>> + ? ? /* Prescale timer */
>> + ? ? writel((clkrate / tickrate) - 1, cs_base + SPMP8000_TMRB_PSR);
>> +
>> + ? ? /* Register the clocksource */
>> + ? ? clocksource_mmio_init(cs_base + SPMP8000_TMRB_VLR, "tmrb2",
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? tickrate, 200, 16, clocksource_mmio_readl_up);
>> +
>> + ? ? /* Configure as free running (0 - 0xFFFF), up counter, enable timer */
>> + ? ? writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_UD,
>> + ? ? ? ? ? ? cs_base + SPMP8000_TMRB_CTR);
>> +
>> + ? ? /* Clockevent */
>> + ? ? setup_irq(irq, &tmrb1_irq);
>> +
>> + ? ? /* Disable timer */
>> + ? ? writel(0, ce_base + SPMP8000_TMRB_CTR);
>> +
>> + ? ? /* Prescale timer */
>> + ? ? writel((clkrate / tickrate) - 1, ce_base + SPMP8000_TMRB_PSR);
>> +
>> + ? ? clockevents_register_device(&tmrb1_clkevt);
>> +}
>> +
>> +struct sys_timer spmp8000_sys_timer = {
>> + ? ? .init ? ? ? ? ? = spmp8000_sys_timer_init,
>> +};
>
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 10:00 ` Mark Brown
@ 2011-10-10 11:42 ` Zoltan Devai
2011-10-10 11:44 ` Mark Brown
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-10 11:42 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/10 Mark Brown <broonie@opensource.wolfsonmicro.com>:
> On Mon, Oct 10, 2011 at 10:42:49AM +0100, Jonathan Cameron wrote:
>
>> It really depends on what those general adc callbacks get used for.
>
> If it's a general purpose ADC it's up to the board designer - you
> sometimes see things like battery or supply monitoring but really it
> could be any low volume analogue input.
It's really up to the board designer. In this case, all real-world
scenarios use the adc for analog-keys AND battery monitoring.
Jonathan, your analysis of the driver is completely correct:
Currently, only the not-yet-submitted analog-keys input driver uses
this, but I'd like to add battery monitoring shortly, so this has at
least two users.
Where should the adc driver go in this case ?
Zoltan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 11:42 ` Zoltan Devai
@ 2011-10-10 11:44 ` Mark Brown
2011-10-11 14:17 ` Arnd Bergmann
2011-10-13 9:47 ` Russell King - ARM Linux
0 siblings, 2 replies; 78+ messages in thread
From: Mark Brown @ 2011-10-10 11:44 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 01:42:30PM +0200, Zoltan Devai wrote:
> Where should the adc driver go in this case ?
At the minute it seems to me that arch/arm is as good a place as any
really - currently this code is getting dumped wherever the main device
is.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-10 11:36 ` Zoltan Devai
@ 2011-10-10 11:52 ` Jamie Iles
0 siblings, 0 replies; 78+ messages in thread
From: Jamie Iles @ 2011-10-10 11:52 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 01:36:09PM +0200, Zoltan Devai wrote:
> 2011/10/9 Jamie Iles <jamie@jamieiles.com>:
> > A couple of minor comments inline but this looks really good!
> Thanks for reviewing! Comments inline.
>
> > On Sun, Oct 09, 2011 at 06:36:05PM +0200, Zoltan Devai wrote:
[...]
> >> +#ifdef CONFIG_DEBUG_LL
> >> + ? ? {
> >> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_UARTC0_BASE),
> >> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_UARTC0_BASE),
> >> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_UARTC0_SIZE,
> >> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
> >> + ? ? },
> >> +#endif
> >> +};
> >> +
> >> +#define IO_PTR(x) ? ?((void __iomem *)IO_ADDRESS(x))
> >
> > Generally IO_ADDRESS returns a void __iomem pointer so it would be
> > easier if you could have the cast in there (though it may need to be
> > enclosed in #ifndef __ASSEMBLY__ conditionals).
> Every instance I've seen returns an int, mainly because it's used for
> the static mappings above.
> So, if I make IO_ADDRESS return void __iomem, I'd have to make
> a macro for casting it back to int, and we'd be where we started.
Yes, you're quite right!
[...]
> >> +
> >> +#ifndef __MACH_SPMP8000_DMA_H__
> >> +#define __MACH_SPMP8000_DMA_H__
> >> +
> >> +enum spmp8000_dma_controller {
> >> + ? ? SPMP8000_APBDMA_A ? ? ? = 0,
> >> + ? ? SPMP8000_APBDMA_C,
> >> +};
> >> +
> >> +extern char *spmp8000_dma_controller_names[];
> >> +
> >> +struct spmp8000_dma_params {
> >> + ? ? char ? ? ? ? ? ? ? ? ? ? ? ? ? ?*dma_controller;
> >> + ? ? dma_addr_t ? ? ? ? ? ? ? ? ? ? ?dma_address;
> >> + ? ? enum dma_slave_buswidth ? ? ? ? dma_width;
> >> + ? ? int ? ? ? ? ? ? ? ? ? ? ? ? ? ? maxburst;
> >> +};
> >
> > dmaengine has dma_slave_config that could be used for this, but I don't
> > see any of this file being used in this series so perhaps it's worth
> > adding in after the core stuff has been merged?
> Will split.
> This struct is used by the i2s driver to pass info to the pcm driver on how
> to set up the dma controller. Seems to be the way to do.
OK, so this is platform data for the i2s driver?
> Which tree and branch should I base my work on ?
> I'm quite confused by the all the options, and it seems like
> if I choose some devel-stable tree, then I don't get the new
> features and my work is outdated from the beginning,
> but for-next branches are quite diverged.
> Is there a good strategy ?
That's a tricky one. I have a similar problem, and rightly or wrongly I
generally put most of the stuff I can based of off an -rc tag from
Linus' tree then merge in the others during testing. As long as those
get merged first you don't need to do anything else, but it does get a
bit fiddly.
> >> diff --git a/arch/arm/mach-spmp8000/include/mach/system.h
> >> b/arch/arm/mach-spmp8000/include/mach/system.h
> >> new file mode 100644
> >> index 0000000..be53ff3
> >> --- /dev/null
> >> +++ b/arch/arm/mach-spmp8000/include/mach/system.h
> >> @@ -0,0 +1,45 @@
> >> +/*
> >> + * SPMP8000 system.h
> >> + *
> >> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> >> + *
> >> + * This file is licensed under the terms of the GNU General Public
> >> + * License version 2. This program is licensed "as is" without any
> >> + * warranty of any kind, whether express or implied.
> >> + */
> >> +
> >> +#ifndef __MACH_SPMP8000_SYSTEM_H__
> >> +#define __MACH_SPMP8000_SYSTEM_H__
> >> +
> >> +#include <linux/kernel.h>
> >> +#include <linux/io.h>
> >> +
> >> +#define SPMP8000_WDT_BASE ? ?0x90001000
> >> +#define SPMP8000_WDT_SIZE ? ?0x1000
> >> +
> >> +#define SPMP8000_WDT_CTR ? ? 0x00
> >> +#define SPMP8000_WDT_CTR_TE ?BIT(0)
> >> +#define SPMP8000_WDT_CTR_RE ?BIT(3)
> >> +
> >> +static inline void arch_idle(void)
> >> +{
> >> + ? ? cpu_do_idle();
> >> +}
> >> +
> >> +static inline void arch_reset(char mode, const char *cmd)
> >> +{
> >> + ? ? void *base;
> >> +
> >> + ? ? base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
> >> + ? ? if (!base) {
> >> + ? ? ? ? ? ? pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
> >> + ? ? ? ? ? ? ? ? ? ? "Halt.");
> >> + ? ? ? ? ? ? while (1);
> >> + ? ? }
> >
> > It may be worth doing the ioremap earlier when the system is in a known
> > good state with all functions available rather than at reset time.
> Any suggestion where the best place would be ?
> I can only think of either the timer init or the board init, but neither seemed
> to be appropriate.
Personally I think having a soc init function that does this sort of
stuff and gets called from the board init would be suitable for this
sort of thing. If the ioremap() fails you could always fall back to a
soft reset.
Jamie
^ permalink raw reply [flat|nested] 78+ messages in thread
* Add support for the SPMP8000 SoC and Letcool board
2011-10-10 8:55 ` Add support for the SPMP8000 SoC and Letcool board Jamie Iles
@ 2011-10-10 12:00 ` Zoltan Devai
2011-10-10 12:03 ` Jamie Iles
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-10 12:00 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/10 Jamie Iles <jamie@jamieiles.com>:
> On Sun, Oct 09, 2011 at 06:36:03PM +0200, Zoltan Devai wrote:
>> Hi,
>>
>> This series adds support for the Sunplus SPMP8000 SoC, an ARM926EJ-S based
>> MCU, which is most commonly found in handheld game consoles and digital cams.
>> Most of the work was done during GSoC 2011, with Greg KH as my mentor.
>>
>> The board I'm using for development is the Letcool N350JP handheld.
>>
>> The patches are based on Arnds for-next branch with Jamie Iles' vic-dt patches
>> on top.
>
> Excellent! ?Can I take that as a Tested-by from you for that series?
Yes, I've been using it without problems.
Do you need an explicit reply to that thread with the Tested-by ?
Z
^ permalink raw reply [flat|nested] 78+ messages in thread
* Add support for the SPMP8000 SoC and Letcool board
2011-10-10 12:00 ` Zoltan Devai
@ 2011-10-10 12:03 ` Jamie Iles
0 siblings, 0 replies; 78+ messages in thread
From: Jamie Iles @ 2011-10-10 12:03 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 02:00:40PM +0200, Zoltan Devai wrote:
> 2011/10/10 Jamie Iles <jamie@jamieiles.com>:
> > On Sun, Oct 09, 2011 at 06:36:03PM +0200, Zoltan Devai wrote:
> >> Hi,
> >>
> >> This series adds support for the Sunplus SPMP8000 SoC, an ARM926EJ-S based
> >> MCU, which is most commonly found in handheld game consoles and digital cams.
> >> Most of the work was done during GSoC 2011, with Greg KH as my mentor.
> >>
> >> The board I'm using for development is the Letcool N350JP handheld.
> >>
> >> The patches are based on Arnds for-next branch with Jamie Iles' vic-dt patches
> >> on top.
> >
> > Excellent! ?Can I take that as a Tested-by from you for that series?
> Yes, I've been using it without problems.
> Do you need an explicit reply to that thread with the Tested-by ?
No that's fine, I'll add it for the next posting/pull request.
Thanks,
Jamie
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS
2011-10-10 1:35 ` Linus Walleij
@ 2011-10-10 13:59 ` Zoltan Devai
0 siblings, 0 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-10 13:59 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/10 Linus Walleij <linus.walleij@linaro.org>:
> 2011/10/9 Zoltan Devai <zoss@devai.org>:
>
>> This is unneeded and causes an abort on the SPMP8000 platform.
>>
>> Signed-off-by: Zoltan Devai <zoss@devai.org>
>> ---
>> ?arch/arm/common/vic.c | ? ?1 -
>> ?1 files changed, 0 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
>> index b22b83d..651c77d 100644
>> --- a/arch/arm/common/vic.c
>> +++ b/arch/arm/common/vic.c
>> @@ -274,7 +274,6 @@ static void __init vic_disable(void __iomem *base)
>> ? ? ? ?writel(0, base + VIC_INT_SELECT);
>> ? ? ? ?writel(0, base + VIC_INT_ENABLE);
>> ? ? ? ?writel(~0, base + VIC_INT_ENABLE_CLEAR);
>> - ? ? ? writel(0, base + VIC_IRQ_STATUS);
>> ? ? ? ?writel(0, base + VIC_ITCR);
>> ? ? ? ?writel(~0, base + VIC_INT_SOFT_CLEAR);
>> ?}
>
> Indeed.
>
> This patch stands on its own, please put it into Russell's patch
> tracker at http://www.arm.linux.org.uk/developer/patches/
>
> Acked-by: Linus Walleij <linus.walleij@linaro.org>
Done, will exclude this from the next series.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] ARM: SPMP8000: Add support for the Letcool board
2011-10-09 16:36 ` [PATCH 8/9] ARM: SPMP8000: Add support for the " Zoltan Devai
@ 2011-10-11 14:09 ` Arnd Bergmann
2011-10-11 14:43 ` Zoltan Devai
2011-10-13 9:54 ` Russell King - ARM Linux
1 sibling, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 14:09 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 09 October 2011, Zoltan Devai wrote:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> arch/arm/mach-spmp8000/board_letcool.c | 154 ++++++++++++++++++++++
> arch/arm/mach-spmp8000/include/mach/spmp8000fb.h | 32 +++++
> 2 files changed, 186 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-spmp8000/board_letcool.c
> create mode 100644 arch/arm/mach-spmp8000/include/mach/spmp8000fb.h
Hi Zoltan,
We basically stopped doing board files for new platforms. Please get
rid of this and make sure that the spmp8000-letcool.dts describes
everything you need to get this board running. The DT_MACHINE_START
part should just be part of the core.c file and not mention the
board name, since its intended to apply to all boards with this
SOC.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 11:44 ` Mark Brown
@ 2011-10-11 14:17 ` Arnd Bergmann
2011-10-11 14:40 ` Mark Brown
2011-10-13 9:47 ` Russell King - ARM Linux
1 sibling, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 14:17 UTC (permalink / raw)
To: linux-arm-kernel
On Monday 10 October 2011, Mark Brown wrote:
> On Mon, Oct 10, 2011 at 01:42:30PM +0200, Zoltan Devai wrote:
>
> > Where should the adc driver go in this case ?
>
> At the minute it seems to me that arch/arm is as good a place as any
> really - currently this code is getting dumped wherever the main device
> is.
My feeling is that there is a general class of drivers involving
the gpio, pinmux, pwm, led, adc and dac: these are basically all
things you do with a single pin. Right now we have subsystems for
some of them, adding some others and don't have anything for adc
basides iio (which only partially fits here).
Since there is no externally visible interface for this kind of
adc driver, we can always fix it later, which helps a lot. How
about putting it into drivers/adc or drivers/misc/adc for now
and waiting for others to join it? We can then later make it a
proper subsystem along the lines of gpio and pwm and move
interfaces for input, hwmon and iio into the subsystem.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-11 14:17 ` Arnd Bergmann
@ 2011-10-11 14:40 ` Mark Brown
2011-10-11 15:24 ` Arnd Bergmann
0 siblings, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-11 14:40 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Oct 11, 2011 at 04:17:51PM +0200, Arnd Bergmann wrote:
> On Monday 10 October 2011, Mark Brown wrote:
> > At the minute it seems to me that arch/arm is as good a place as any
> > really - currently this code is getting dumped wherever the main device
> > is.
> My feeling is that there is a general class of drivers involving
> the gpio, pinmux, pwm, led, adc and dac: these are basically all
> things you do with a single pin. Right now we have subsystems for
> some of them, adding some others and don't have anything for adc
> basides iio (which only partially fits here).
We've been round this loop repeatedly before, trying to push all this
stuff into pins really doesn't map terribly well. For example, SoCs
will frequently have PWM controllers which are isolated IP blocks within
the device and may each have multiple mappings out of the device onto
pins. In the case of DACs, ADCs and PWM you definitely don't have a one
to one mapping with a single pin - they can be differential inputs and
outputs, or entirely internal to a device. Trying to push everything
into a single namespace just makes things confusing.
What we *do* have a pattern of is clk API type lookups based on a
device/name pair.
> Since there is no externally visible interface for this kind of
> adc driver, we can always fix it later, which helps a lot. How
> about putting it into drivers/adc or drivers/misc/adc for now
> and waiting for others to join it? We can then later make it a
> proper subsystem along the lines of gpio and pwm and move
> interfaces for input, hwmon and iio into the subsystem.
I'm not sure that IIO isn't the kernel subsystem we're looking for here
- as I keep saying when this comes up it's just representing bare DACs
and ADCs pretty directly which looks like a generic subsystem to me.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] ARM: SPMP8000: Add support for the Letcool board
2011-10-11 14:09 ` Arnd Bergmann
@ 2011-10-11 14:43 ` Zoltan Devai
2011-10-11 15:18 ` Arnd Bergmann
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-11 14:43 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/11 Arnd Bergmann <arnd@arndb.de>:
> On Sunday 09 October 2011, Zoltan Devai wrote:
>> Signed-off-by: Zoltan Devai <zoss@devai.org>
>> ---
>> ?arch/arm/mach-spmp8000/board_letcool.c ? ? ? ? ? | ?154 ++++++++++++++++++++++
>> ?arch/arm/mach-spmp8000/include/mach/spmp8000fb.h | ? 32 +++++
>> ?2 files changed, 186 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/mach-spmp8000/board_letcool.c
>> ?create mode 100644 arch/arm/mach-spmp8000/include/mach/spmp8000fb.h
>
> Hi Zoltan,
>
> We basically stopped doing board files for new platforms. Please get
> rid of this and make sure that the spmp8000-letcool.dts describes
> everything you need to get this board running. The DT_MACHINE_START
> part should just be part of the core.c file and not mention the
> board name, since its intended to apply to all boards with this
> SOC.
Hi,
The board file only contains platform data for drivers which don't handle DT.
Should I strip those off ?
Does that also mean that no fully working ARM board will be allowed into
mainline until all required drivers do DT ?
Zoltan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-09 16:36 ` [PATCH 2/9] ARM: SPMP8000: Add machine base files Zoltan Devai
2011-10-09 17:22 ` Jamie Iles
@ 2011-10-11 14:44 ` Arnd Bergmann
2011-10-16 14:10 ` Zoltan Devai
1 sibling, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 14:44 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 09 October 2011, Zoltan Devai wrote:
> +
> +/* Static mappings:
> + * SCU: timer needs clk support which is inited in init_early
> + * UART: needed for earlyprintk
> + */
> +static struct map_desc io_desc[] __initdata = {
> + {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_A_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_A_BASE),
> + .length = SPMP8000_SCU_A_SIZE,
> + .type = MT_DEVICE,
> + }, {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_B_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_B_BASE),
> + .length = SPMP8000_SCU_B_SIZE,
> + .type = MT_DEVICE,
> + }, {
> + .virtual = IO_ADDRESS(SPMP8000_SCU_C_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_SCU_C_BASE),
> + .length = SPMP8000_SCU_C_SIZE,
> + .type = MT_DEVICE,
> + },
With Nicolas Pitre's rework of the MMIO space handling, I think it
would be nice to just use a single area that spans all of the devices
so you can do an optimized ioremap and huge TLBs. Unfortunately
that series won't make it into 3.2, but if you just set up a large
area now, it will automatically work.
> +#ifdef CONFIG_DEBUG_LL
> + {
> + .virtual = IO_ADDRESS(SPMP8000_UARTC0_BASE),
> + .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
> + .length = SPMP8000_UARTC0_SIZE,
> + .type = MT_DEVICE,
> + },
> +#endif
> +};
>
And it would be nice to move this into a separate file that handles the
early debug code, as prima2 does.
> +#ifndef __MACH_SPMP8000_DMA_H__
> +#define __MACH_SPMP8000_DMA_H__
> +
> +enum spmp8000_dma_controller {
> + SPMP8000_APBDMA_A = 0,
> + SPMP8000_APBDMA_C,
> +};
> +
> +extern char *spmp8000_dma_controller_names[];
> +
> +struct spmp8000_dma_params {
> + char *dma_controller;
> + dma_addr_t dma_address;
> + enum dma_slave_buswidth dma_width;
> + int maxburst;
> +};
> +
> +/* Driver parameters */
> +#define SPMP8000_APBDMA_MAX_PERIODS 64
> +
> +static bool spmp8000_dma_filter(struct dma_chan *chan, const char *name)
> +{
> + int ret;
> +
> + ret = strcmp(dev_name(chan->device->dev), name);
> +
> + if (ret)
> + return false;
> +
> + return true;
> +}
> +
> +#endif /* __MACH_SPMP8000_DMA_H__ */
Please separate the dma controller out for now into a separate patch.
We really need to have proper device tree bindings so we can avoid the
silly filter functions and do something better. That needs some more
discussion and any help on the interface is very much appreciated.
> diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h b/arch/arm/mach-spmp8000/include/mach/gpio.h
> new file mode 100644
> +#ifndef __MACH_SPMP8000_GPIO_H__
> +#define __MACH_SPMP8000_GPIO_H__
> +
> +#include <asm-generic/gpio.h>
> +
> +#define gpio_get_value __gpio_get_value
> +#define gpio_set_value __gpio_set_value
> +#define gpio_cansleep __gpio_cansleep
> +#define gpio_to_irq __gpio_to_irq
> +
> +#endif /* __MACH_SPMP8000_GPIO_H__ */
I think this can become an empty file now, with Russell's latest cleanup
going into 3.2.
> +/* Vitual to physical translation of statically mapped space */
> +#define IO_ADDRESS(x) ((x) | 0xF0000000)
Better make this return a 'void __iomem *', e.g. by doing
#define IO_ADDRESS(x) (((x) & 0x0fffffff) + ((void __iomem *)0xf0000000)
> +/* Needed for the static mappings and uncompress.h */
> +#define SPMP8000_UARTC0_BASE 0x92B04000
> +#define SPMP8000_UARTC0_SIZE SZ_4K
> +#define SPMP8000_SCU_C_BASE 0x92005000
> +#define SPMP8000_SCU_C_SIZE SZ_4K
> +#define SPMP8000_SCU_A_BASE 0x93007000
> +#define SPMP8000_SCU_A_SIZE SZ_4K
> +#define SPMP8000_SCU_B_BASE 0x90005000
> +#define SPMP8000_SCU_B_SIZE SZ_4K
Do you need these all so early that you cannot get the location from the device
tree?
> +/* FIXME This should go away */
> +#define IO_SPACE_LIMIT 0
> +
> +#define __mem_pci(a) (a)
> +#define __io(a) __typesafe_io(a)
> +
I think you should better define __io() to NULL.
> +++ b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
> @@ -0,0 +1,32 @@
> +/*
> + * SPMP8000 timer support
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + *
> + * These timer reg definitions are used by the timer and pwm drivers
> + */
> +#ifndef __MACH_SPMP8000_REGS_TIMER_H__
> +#define __MACH_SPMP8000_REGS_TIMER_H__
> +
> +#define SPMP8000_TMRB(tnum) (tnum * 0x20)
> +#define SPMP8000_TMRB_CTR 0x00
> +#define SPMP8000_TMRB_CTR_TE BIT(0)
> +#define SPMP8000_TMRB_CTR_IE BIT(1)
> +#define SPMP8000_TMRB_CTR_OE BIT(2)
> +#define SPMP8000_TMRB_CTR_PWMON BIT(3)
> +#define SPMP8000_TMRB_CTR_UD BIT(4)
> +#define SPMP8000_TMRB_CTR_UDS BIT(5)
> +#define SPMP8000_TMRB_CTR_OM BIT(6)
> +#define SPMP8000_TMRB_CTR_ES_SH 8
> +#define SPMP8000_TMRB_CTR_M_SH 10
> +#define SPMP8000_TMRB_PSR 0x04
> +#define SPMP8000_TMRB_LDR 0x08
> +#define SPMP8000_TMRB_VLR 0x08
> +#define SPMP8000_TMRB_ISR 0x0C
> +#define SPMP8000_TMRB_CMP 0x10
> +
> +#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
No need for this header, just move the definitions into the timer driver.
> diff --git a/arch/arm/mach-spmp8000/include/mach/scu.h b/arch/arm/mach-spmp8000/include/mach/scu.h
> new file mode 100644
> index 0000000..e3a98d4
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/scu.h
> @@ -0,0 +1,146 @@
> +/*
> + * SPMP8000 System Control Unit register definitions
> + * SCUs are a random collection of reset, clock, gpio, pinmux, etc. controllers
> + * so that these definitions are needed at several places.
> +struct scu_reg_t {
> + void *base;
> + void *clken;
> +};
> +
> +extern struct scu_reg_t scu_regs[];
> +
> +#define REG_SCU_BASE(x) scu_regs[x].base
> +#define REG_SCU_CLKEN(x) scu_regs[x].clken
> +#define REG_SCU_A_ID 0
> +#define REG_SCU_B_ID 1
> +#define REG_SCU_C_ID 2
> +#define REG_SCU_A(x) (scu_regs[REG_SCU_A_ID].base + x)
> +#define REG_SCU_B(x) (scu_regs[REG_SCU_B_ID].base + x)
> +#define REG_SCU_C(x) (scu_regs[REG_SCU_C_ID].base + x)
I would prefer having this in core.c, so the base addresses can
remain private to that file instead of exporting them to
all of the kernel.
> +#define SCU_A_PERI_RST 0x00
> +#define SCU_A_PERI_CLKEN 0x04
> +#define SCU_A_PERI_DGCLKEN 0x0C
> +
> +#define SCU_A_APLL_CFG 0x44
> +#define APLL_CFG_P BIT(0)
> +#define APLL_CFG_S BIT(1)
> +#define APLL_CFG_F BIT(2)
> +#define APLL_CFG_E BIT(3)
The BIT() definition is really just mean for kernel-internal bitops,
not so much for device registers.
My recommended style of this is
#define APLL_CFG_P 0x00000001
#define APLL_CFG_S 0x00000002
#define APLL_CFG_F 0x00000004
#define APLL_CFG_E 0x00000008
> diff --git a/arch/arm/mach-spmp8000/include/mach/system.h b/arch/arm/mach-spmp8000/include/mach/system.h
> new file mode 100644
> index 0000000..be53ff3
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/include/mach/system.h
> @@ -0,0 +1,45 @@
> +/*
> + * SPMP8000 system.h
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#ifndef __MACH_SPMP8000_SYSTEM_H__
> +#define __MACH_SPMP8000_SYSTEM_H__
> +
> +#include <linux/kernel.h>
> +#include <linux/io.h>
> +
> +#define SPMP8000_WDT_BASE 0x90001000
> +#define SPMP8000_WDT_SIZE 0x1000
These have to be removed. For device drivers, you should normally
use of_iomap to get at the registers.
> +#define SPMP8000_WDT_CTR 0x00
> +#define SPMP8000_WDT_CTR_TE BIT(0)
> +#define SPMP8000_WDT_CTR_RE BIT(3)
> +
> +static inline void arch_idle(void)
> +{
> + cpu_do_idle();
> +}
> +
> +static inline void arch_reset(char mode, const char *cmd)
> +{
> + void *base;
> +
> + base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
> + if (!base) {
> + pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
> + "Halt.");
> + while (1);
> + }
> +
> + /* Trigger a watchdog reset */
> + writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
> + base + SPMP8000_WDT_CTR);
> +}
Using the watchdog for arch_reset is clever, but unfortunately not
too common otherwise, so you have to play tricks. I would try
locating the device and ioremapping it from core.c and then
export a function to set the register that is used both by
the arch_reset function and by the watchdog driver. The latter
can still bind to the platform_device, but it then doesn't have
to do an extra of_iomap.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* Add support for the SPMP8000 SoC and Letcool board
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
` (9 preceding siblings ...)
2011-10-10 8:55 ` Add support for the SPMP8000 SoC and Letcool board Jamie Iles
@ 2011-10-11 14:57 ` Arnd Bergmann
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
11 siblings, 0 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 14:57 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 09 October 2011, Zoltan Devai wrote:
> This series adds support for the Sunplus SPMP8000 SoC, an ARM926EJ-S based
> MCU, which is most commonly found in handheld game consoles and digital cams.
> Most of the work was done during GSoC 2011, with Greg KH as my mentor.
>
> The board I'm using for development is the Letcool N350JP handheld.
>
> The patches are based on Arnds for-next branch with Jamie Iles' vic-dt patches
> on top.
>
> No static platform devices are used, everything is inited from DT, with some
> hacks for drivers that don't have any bindings yet.
> (Documentation for own, custom bindings will follow in next version.)
>
> So far, these peripherals are supported, with drivers not submitted yet:
> gpio, fb, cpufreq, slave-dma, mmc, ASoC (i2s, codec, pcm, card).
>
> Reviews, instructions for mainlining it are very welcome.
Hi Zoltan,
Looks basically ok, but there are the usual smaller things I found that
are worth improving. I like very much seeing an ARM926 port done in the
new style, especially since these tend to be much simpler than the
cortex-a9 platforms that most people are working on these days. This
gives us the chance to experiment with a complete port without having
to do heaps of new device tree bindings etc. It will also be valuable
to have this when working on single-zimage patches for ARMv5.
I would however prefer to leave the port for linux-3.3 at this point,
since we are close to the merge window and there are a lot of details
for you to work on still.
In particular, I would hope that by the time of the 3.3 merge window
we will have a proper common clockdev layer that can simplify a
significant portion of your code.
As Linus Walleij mentioned already, it would be good to move the
device drivers out of the platform directory into subsystems
below drivers/ and I hope that by 3.3 that also includes the pinmux,
clkdev, and timer drivers, possibly also pwm and adc.
My hope is that in the long run, a relatively simple platform like
this can become a single core.c file plus the optional debug_ll
support, after all the header files are consolidated and the drivers
are moved out. You won't have to wait for that though: If the code
looks ok, we can merge it in whatever the closest is we get to
the ideal at the time.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] ARM: SPMP8000: Add support for the Letcool board
2011-10-11 14:43 ` Zoltan Devai
@ 2011-10-11 15:18 ` Arnd Bergmann
0 siblings, 0 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 15:18 UTC (permalink / raw)
To: linux-arm-kernel
On Tuesday 11 October 2011, Zoltan Devai wrote:
> >
> > Hi Zoltan,
> >
> > We basically stopped doing board files for new platforms. Please get
> > rid of this and make sure that the spmp8000-letcool.dts describes
> > everything you need to get this board running. The DT_MACHINE_START
> > part should just be part of the core.c file and not mention the
> > board name, since its intended to apply to all boards with this
> > SOC.
> Hi,
>
> The board file only contains platform data for drivers which don't handle DT.
> Should I strip those off ?
Well, ideally you should add support for DT probing to those drivers.
With all the new helpers we recently added, that should not require more
code than what you have in the board file that you lose in the process.
> Does that also mean that no fully working ARM board will be allowed into
> mainline until all required drivers do DT ?
Yes, sorry that this causes more work for you.
The overall strategy is more complex, it depends a lot on the state that
the platform is in:
1. For new platforms (prima2, zynq, picoxcell, highbank, spmp8000, ...),
there is a single machine description and all devices are probed through
the device tree. Board files are no longer allowed.
2a For actively maintained platforms (omap, pxa, msm, samsung, at91, imx,
...), the expectation is that the maintainers work on converting the
drivers to device tree probing, but they can still add the occasional
board file for important boards. Once all on board (not necessarily
on-chip) devices can be probed using device tree, new boards files are
not allowed any more, and existing board files should be removed
(either all at once or gradually as dts files get added).
2b After an existing platform has lost its board files, we also want
to remove the on-soc devices from platform files by moving them into
the device tree. The method is the same: you get to add new socs only
if you work on infrastructure to get rid of the code again and move
it into dts files. Once the infrastructure is there, the existing
soc descriptions should gradually go away.
3. For legacy platforms (rpc, sa1100, h720x, ...), I don't expect
anyone to realistically work on device tree conversion. If someone
sends a new board file, that would likely be accepted. Those platforms
are also simple enough that doing everything using board files is
not a signficant overhead.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-11 14:40 ` Mark Brown
@ 2011-10-11 15:24 ` Arnd Bergmann
2011-10-11 15:39 ` Jonathan Cameron
2011-10-12 14:42 ` Mark Brown
0 siblings, 2 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-11 15:24 UTC (permalink / raw)
To: linux-arm-kernel
On Tuesday 11 October 2011, Mark Brown wrote:
> On Tue, Oct 11, 2011 at 04:17:51PM +0200, Arnd Bergmann wrote:
> > On Monday 10 October 2011, Mark Brown wrote:
>
> > > At the minute it seems to me that arch/arm is as good a place as any
> > > really - currently this code is getting dumped wherever the main device
> > > is.
>
> > My feeling is that there is a general class of drivers involving
> > the gpio, pinmux, pwm, led, adc and dac: these are basically all
> > things you do with a single pin. Right now we have subsystems for
> > some of them, adding some others and don't have anything for adc
> > basides iio (which only partially fits here).
>
> We've been round this loop repeatedly before, trying to push all this
> stuff into pins really doesn't map terribly well. For example, SoCs
> will frequently have PWM controllers which are isolated IP blocks within
> the device and may each have multiple mappings out of the device onto
> pins. In the case of DACs, ADCs and PWM you definitely don't have a one
> to one mapping with a single pin - they can be differential inputs and
> outputs, or entirely internal to a device. Trying to push everything
> into a single namespace just makes things confusing.
I didn't mean to suggest that they should be the same subsystem, but
it would be nice to use similar in-kernel interfaces so that a driver
author doesn't have to learn about six different interfaces for
a new soc. If we add an adc subsystem, I would definitely recommend
looking at how the others work.
> > Since there is no externally visible interface for this kind of
> > adc driver, we can always fix it later, which helps a lot. How
> > about putting it into drivers/adc or drivers/misc/adc for now
> > and waiting for others to join it? We can then later make it a
> > proper subsystem along the lines of gpio and pwm and move
> > interfaces for input, hwmon and iio into the subsystem.
>
> I'm not sure that IIO isn't the kernel subsystem we're looking for here
> - as I keep saying when this comes up it's just representing bare DACs
> and ADCs pretty directly which looks like a generic subsystem to me.
Possible, yes. Until now, IIO is a subsystem for user-level access
not for kernel access though, so it's not the right place yet.
If we decide to let IIO handle all ADC input, do you think it would
also be the right place to do PWM output, rather than having a
separate subsystem for that?
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-11 15:24 ` Arnd Bergmann
@ 2011-10-11 15:39 ` Jonathan Cameron
2011-10-12 14:42 ` Mark Brown
1 sibling, 0 replies; 78+ messages in thread
From: Jonathan Cameron @ 2011-10-11 15:39 UTC (permalink / raw)
To: linux-arm-kernel
On 10/11/11 16:24, Arnd Bergmann wrote:
> On Tuesday 11 October 2011, Mark Brown wrote:
>> On Tue, Oct 11, 2011 at 04:17:51PM +0200, Arnd Bergmann wrote:
>>> On Monday 10 October 2011, Mark Brown wrote:
>>
>>>> At the minute it seems to me that arch/arm is as good a place as any
>>>> really - currently this code is getting dumped wherever the main device
>>>> is.
>>
>>> My feeling is that there is a general class of drivers involving
>>> the gpio, pinmux, pwm, led, adc and dac: these are basically all
>>> things you do with a single pin. Right now we have subsystems for
>>> some of them, adding some others and don't have anything for adc
>>> basides iio (which only partially fits here).
>>
>> We've been round this loop repeatedly before, trying to push all this
>> stuff into pins really doesn't map terribly well. For example, SoCs
>> will frequently have PWM controllers which are isolated IP blocks within
>> the device and may each have multiple mappings out of the device onto
>> pins. In the case of DACs, ADCs and PWM you definitely don't have a one
>> to one mapping with a single pin - they can be differential inputs and
>> outputs, or entirely internal to a device. Trying to push everything
>> into a single namespace just makes things confusing.
>
> I didn't mean to suggest that they should be the same subsystem, but
> it would be nice to use similar in-kernel interfaces so that a driver
> author doesn't have to learn about six different interfaces for
> a new soc. If we add an adc subsystem, I would definitely recommend
> looking at how the others work.
Yup, I'm reading the clk api stuff right now.
>
>>> Since there is no externally visible interface for this kind of
>>> adc driver, we can always fix it later, which helps a lot. How
>>> about putting it into drivers/adc or drivers/misc/adc for now
>>> and waiting for others to join it? We can then later make it a
>>> proper subsystem along the lines of gpio and pwm and move
>>> interfaces for input, hwmon and iio into the subsystem.
>>
>> I'm not sure that IIO isn't the kernel subsystem we're looking for here
>> - as I keep saying when this comes up it's just representing bare DACs
>> and ADCs pretty directly which looks like a generic subsystem to me.
>
> Possible, yes. Until now, IIO is a subsystem for user-level access
> not for kernel access though, so it's not the right place yet.
Technically proof of concept code for kernel access went out this morning
(sorry, didn't cc you as you hadn't entered this thread yet). It's
all of 10 lines of code right now. But yeah, its userspace focussed.
https://lkml.org/lkml/2011/10/11/141
Covers basic hwmon type usage (polled single channel read). I'm not nearly
as sure how to handle complex channel scans. There's a lot of infrastructure
involved in those.
> If we decide to let IIO handle all ADC input, do you think it would
> also be the right place to do PWM output, rather than having a
> separate subsystem for that?
That's one I've been avoiding talking about. The fuzzy region is between
DDS (direct digital synthesis - waveform generator) chips which we have
been taking in IIO so far. We don't actually handle these that well
at the moment. Our core channel registration code doesn't handle the
weird routing these can do - single underlying generator does several
synchronized waveforms.
Pwm is small compact and nice. Perhaps a similar shim to that I proposed
to hwmon alongside that patch earlier. So simple pwm only device sits
in pwm, but we have a general purpose driver sitting on IIO that can
provide pwm from an appropriate channel of a more complex device.
It would need hooks that aren't there at the moment and more of the
DDS control to become part of the IIO core.
We may ultimately want to hive off more of IIO into a layer sitting
at same level as other users. It's tricky to know where to make
such divisions though.
Jonathan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-11 15:24 ` Arnd Bergmann
2011-10-11 15:39 ` Jonathan Cameron
@ 2011-10-12 14:42 ` Mark Brown
2011-10-12 15:41 ` Jonathan Cameron
1 sibling, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-12 14:42 UTC (permalink / raw)
To: linux-arm-kernel
On Tue, Oct 11, 2011 at 05:24:47PM +0200, Arnd Bergmann wrote:
> On Tuesday 11 October 2011, Mark Brown wrote:
> > I'm not sure that IIO isn't the kernel subsystem we're looking for here
> > - as I keep saying when this comes up it's just representing bare DACs
> > and ADCs pretty directly which looks like a generic subsystem to me.
> Possible, yes. Until now, IIO is a subsystem for user-level access
> not for kernel access though, so it's not the right place yet.
> If we decide to let IIO handle all ADC input, do you think it would
> also be the right place to do PWM output, rather than having a
> separate subsystem for that?
Off the top of my head I'd expect PWM to be a separate thing which could
optionally synthesize stuff onto an IIO device (bitbanging the PWM
essentially). The specialized PWM stuff tends to be "output this steady
state for an indefinite period" type interface rather than "here's a
batch of samples, output them".
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-12 14:42 ` Mark Brown
@ 2011-10-12 15:41 ` Jonathan Cameron
0 siblings, 0 replies; 78+ messages in thread
From: Jonathan Cameron @ 2011-10-12 15:41 UTC (permalink / raw)
To: linux-arm-kernel
On 10/12/11 15:42, Mark Brown wrote:
> On Tue, Oct 11, 2011 at 05:24:47PM +0200, Arnd Bergmann wrote:
>> On Tuesday 11 October 2011, Mark Brown wrote:
>
>>> I'm not sure that IIO isn't the kernel subsystem we're looking for here
>>> - as I keep saying when this comes up it's just representing bare DACs
>>> and ADCs pretty directly which looks like a generic subsystem to me.
>
>> Possible, yes. Until now, IIO is a subsystem for user-level access
>> not for kernel access though, so it's not the right place yet.
>> If we decide to let IIO handle all ADC input, do you think it would
>> also be the right place to do PWM output, rather than having a
>> separate subsystem for that?
>
> Off the top of my head I'd expect PWM to be a separate thing which could
> optionally synthesize stuff onto an IIO device (bitbanging the PWM
> essentially). The specialized PWM stuff tends to be "output this steady
> state for an indefinite period" type interface rather than "here's a
> batch of samples, output them".
Same can be true of dds chips, with the addition that they often have
gpio type switching between a set of predefined frequencies (FM basically).
+ weird waveform choices sometimes.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/9] ARM: SPMP8000: Add clk support
2011-10-09 16:36 ` [PATCH 3/9] ARM: SPMP8000: Add clk support Zoltan Devai
@ 2011-10-13 9:38 ` Russell King - ARM Linux
2011-10-16 14:16 ` Zoltan Devai
0 siblings, 1 reply; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-13 9:38 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 09, 2011 at 06:36:06PM +0200, Zoltan Devai wrote:
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
> arch/arm/mach-spmp8000/clkdev.c | 586 +++++++++++++++++++++++++++
> arch/arm/mach-spmp8000/clock.c | 155 +++++++
> arch/arm/mach-spmp8000/include/mach/clock.h | 37 ++
> 3 files changed, 778 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-spmp8000/clkdev.c
> create mode 100644 arch/arm/mach-spmp8000/clock.c
> create mode 100644 arch/arm/mach-spmp8000/include/mach/clock.h
>
> diff --git a/arch/arm/mach-spmp8000/clkdev.c b/arch/arm/mach-spmp8000/clkdev.c
> new file mode 100644
> index 0000000..c492d20
> --- /dev/null
> +++ b/arch/arm/mach-spmp8000/clkdev.c
> @@ -0,0 +1,586 @@
> +/*
> + * SPMP8000 machines clock support
> + *
> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +#include <linux/spinlock.h>
> +#include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <mach/clock.h>
> +#include <mach/scu.h>
I find the use of 'scu' for something which isn't the SMP Coherence Unit
rather confusing - and I suspect you will too if/when spmp8000 has SMP
support.
> +static int divider_set_clock(struct clk *clk, int on)
> +{
> + u32 divider;
> +
> + if (!(clk->flags & CLK_DIVIDER_WITH_ENABLE))
> + return -EINVAL;
> +
> + divider = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
> + if (on)
> + divider |= DIVIDER_ENABLE_BIT;
> + else
> + divider = 0;
> + writel(divider, REG_SCU_BASE(clk->scu) + clk->dividerreg);
When you enable, you preserve the other bits in the register. When you
disable, you zero the whole register. That looks rather odd - either
you want to preserve the other bits or you don't.
> +
> + return 0;
> +}
> +
> +static void divider_enable_clock(struct clk *clk)
> +{
> + divider_set_clock(clk, 1);
> +}
> +
> +static void divider_disable_clock(struct clk *clk)
> +{
> + divider_set_clock(clk, 0);
> +}
afaics, this is the only place divider_set_clock() is called from - which
returns an int which is never checked. Is there any point to it
returning an int?
> +
> +static unsigned long divider_get_rate(struct clk *clk)
> +{
> + u32 divider;
> + unsigned long parent_rate = clk_get_rate(clk->parent);
> +
> + if (!parent_rate) {
> + clk->rate = 0;
> + return clk->rate;
> + }
> +
> + divider = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
> + if ((clk->flags & CLK_DIVIDER_WITH_ENABLE) &&
> + !(divider & DIVIDER_ENABLE_BIT)) {
> + clk->rate = 0UL;
> + return clk->rate;
You really should return the rate which you're going to get when the
clock is enabled here, not zero because it happens to be disabled at
the current point in time.
> + }
> +
> + clk->rate = parent_rate / ((divider & clk->divmask) + 1);
> +
> + return clk->rate;
> +}
> +
> +static int divider_set_rate(struct clk *clk, unsigned long rate)
> +{
> + unsigned long parent_rate = clk_get_rate(clk->parent);
> + u32 divider, divider_old;
> +
> + if (unlikely(!parent_rate || rate > parent_rate)) {
> + clk->rate = 0;
> + pr_debug("parent rate not sufficient\n");
> + return -EINVAL;
> + }
You should set to the maximum (parent rate) in that case.
> +
> + divider = (parent_rate / rate) - 1;
> +
> + if (divider > clk->divmask) {
> + pr_debug("input clock too high\n");
> + return -EINVAL;
> + };
Set to the minimum rate here. The trailing ';' is not required.
> +
> + divider_old = readl(REG_SCU_BASE(clk->scu) + clk->dividerreg);
> + writel(0, REG_SCU_BASE(clk->scu) + clk->dividerreg);
> + writel(divider, REG_SCU_BASE(clk->scu) + clk->dividerreg);
> +
> + /* Re-enable clock if it was enabled before */
> + if (divider_old & DIVIDER_ENABLE_BIT)
> + writel(divider | DIVIDER_ENABLE_BIT,
> + REG_SCU_BASE(clk->scu) + clk->dividerreg);
> +
> + clk->rate = parent_rate / (divider + 1);
> +
> + return 0;
> +}
...
> +static void __clk_disable(struct clk *clk)
> +{
> + BUG_ON(clk->refcount == 0);
> +
> + if (!(--clk->refcount) && clk->disable) {
> + clk->disable(clk);
> + if (clk->parent)
> + __clk_disable(clk->parent);
> + }
> +}
What if the clock has a parent but no disable function?
> +
> +static int __clk_enable(struct clk *clk)
> +{
> + int ret = 0;
> +
> + if (clk->refcount++ == 0 && clk->enable) {
> + if (clk->parent)
> + ret = __clk_enable(clk->parent);
> + if (ret)
> + return ret;
> + else
> + clk->enable(clk);
What if the clock has a parent but no enable function?
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-10 11:44 ` Mark Brown
2011-10-11 14:17 ` Arnd Bergmann
@ 2011-10-13 9:47 ` Russell King - ARM Linux
2011-10-13 11:09 ` Linus Walleij
2011-10-13 11:35 ` Mark Brown
1 sibling, 2 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-13 9:47 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
> On Mon, Oct 10, 2011 at 01:42:30PM +0200, Zoltan Devai wrote:
>
> > Where should the adc driver go in this case ?
>
> At the minute it seems to me that arch/arm is as good a place as any
> really - currently this code is getting dumped wherever the main device
> is.
No it isn't - we want drivers out of arch/arm (it's already been a topic
of flame for Linus, so it's something that we should try _really_ hard
to avoid.)
As this is clearly a device driver (it has a device driver struct, it
relies upon a struct device, etc) then it needs to live outside of
arch/arm/ - and I think Arnd's suggestion of drivers/adc is probably
the right place for it to move to (even though its probably the first
to create the directory.) More stuff can come along in the future,
and then its all together to start creating a common API in there.
The other thing I'd say is that things like the callback definitions
and driver data should not be in some arch/arm/ include file - if
it's private to the ADC, it should go in drivers/adc too. If not,
then somewhere in include/linux (maybe include/linux/adc) is a better
place.
What we *do* need to avoid is having the spmp8000 ADC callback function
data structure, the foo ADC callback function data structure, the bar
ADC callback function data structure and so forth. We need to think
*NOW* about defining a common ADC callback structure so that we don't
spawn a new problem which'll take effort to solve.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
2011-10-09 17:25 ` Jamie Iles
2011-10-10 1:43 ` Linus Walleij
@ 2011-10-13 9:53 ` Russell King - ARM Linux
2 siblings, 0 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-13 9:53 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 09, 2011 at 06:36:12PM +0200, Zoltan Devai wrote:
> +config ARCH_SPMP8000
> + bool "Sunplus SPMP8000"
> + select CPU_ARM926T
> + select ARM_VIC
> + select GENERIC_IRQ_CHIP
> + select MULTI_IRQ_HANDLER
> + select CLKSRC_MMIO
> + select GENERIC_CLOCKEVENTS
> + select ARCH_WANT_OPTIONAL_GPIOLIB
> + select USE_OF
> + select CLKDEV_LOOKUP
> + select HAVE_PWM
> + select ARCH_HAS_CPUFREQ
Please arrange these select statements in alphabetical order - it helps
avoid the 'add to the end' conflict problem.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 8/9] ARM: SPMP8000: Add support for the Letcool board
2011-10-09 16:36 ` [PATCH 8/9] ARM: SPMP8000: Add support for the " Zoltan Devai
2011-10-11 14:09 ` Arnd Bergmann
@ 2011-10-13 9:54 ` Russell King - ARM Linux
1 sibling, 0 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-13 9:54 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 09, 2011 at 06:36:11PM +0200, Zoltan Devai wrote:
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm_backlight.h>
> +#include <linux/input.h>
> +#include <linux/basic_mmio_gpio.h>
> +#include <linux/gpio_keys.h>
> +#include <linux/clk.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <asm/hardware/vic.h>
> +#include <asm/mach/arch.h>
> +#include <asm/mach-types.h>
> +
> +#include <mach/core.h>
> +#include <mach/gpio.h>
In addition to Arnd's comments - please use linux/gpio.h rather than
mach/gpio.h or asm/gpio.h throughout your patches. This helps to make
them future-proof.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 9:47 ` Russell King - ARM Linux
@ 2011-10-13 11:09 ` Linus Walleij
2011-10-13 11:35 ` Jonathan Cameron
2011-10-13 11:35 ` Mark Brown
1 sibling, 1 reply; 78+ messages in thread
From: Linus Walleij @ 2011-10-13 11:09 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 11:47 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
>> On Mon, Oct 10, 2011 at 01:42:30PM +0200, Zoltan Devai wrote:
>>
>> > Where should the adc driver go in this case ?
>>
>> At the minute it seems to me that arch/arm is as good a place as any
>> really - currently this code is getting dumped wherever the main device
>> is.
>
> No it isn't - we want drivers out of arch/arm (it's already been a topic
> of flame for Linus, so it's something that we should try _really_ hard
> to avoid.)
Amen to that.
> As this is clearly a device driver (it has a device driver struct, it
> relies upon a struct device, etc) then it needs to live outside of
> arch/arm/ - and I think Arnd's suggestion of drivers/adc is probably
> the right place for it to move to (even though its probably the first
> to create the directory.) ?More stuff can come along in the future,
> and then its all together to start creating a common API in there.
That sort of suggest that the drivers/staging/iio/adc is in
trouble now. It will have an in-kernel competitor for similar
stuff.
Having drivers/adc and drivers/iio/adc compete about
taking drivers on preference as to whether they were intended
for userspace or kernelspace does not seem like a good
thing.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 9:47 ` Russell King - ARM Linux
2011-10-13 11:09 ` Linus Walleij
@ 2011-10-13 11:35 ` Mark Brown
2011-10-13 12:17 ` Russell King - ARM Linux
1 sibling, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-13 11:35 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 10:47:17AM +0100, Russell King - ARM Linux wrote:
> On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
> > At the minute it seems to me that arch/arm is as good a place as any
> > really - currently this code is getting dumped wherever the main device
> > is.
> No it isn't - we want drivers out of arch/arm (it's already been a topic
> of flame for Linus, so it's something that we should try _really_ hard
> to avoid.)
I said it was as good a place as any, I didn't say it was a good place.
Currently we don't have a good place for this code but just dumping the
code somewhere else isn't really helping anything either unless there's
some meaningful subsytem (or at least effort towards a subsystem) to
look after it, it's bookkeeping.
> As this is clearly a device driver (it has a device driver struct, it
> relies upon a struct device, etc) then it needs to live outside of
> arch/arm/ - and I think Arnd's suggestion of drivers/adc is probably
> the right place for it to move to (even though its probably the first
> to create the directory.) More stuff can come along in the future,
> and then its all together to start creating a common API in there.
Creating drivers/adc just seems like a sucky idea. We've already got at
least one ongoing effort at creating a general purpose ADC/DAC interface
in the form of the IIO subsystem (which is currently mostly targeted at
higher volume devices and userspace only but the abstractions needed
aren't terribly different depending on the data volumes) and does have
the rather substantial advantage that there's people actually trying to
make a subsystem. On the other hand it's in staging for now so it'd
create pain trying to merge the in-kernel clients that go along with
these devices which doesn't seem constructive.
There's also the fact that ADCs and DACs are pretty much the same thing
to software with the data line driven from the opposite end of the link
sO if we've got a subsystem for ADCs only it seems clear we're doing
something wrong.
> What we *do* need to avoid is having the spmp8000 ADC callback function
> data structure, the foo ADC callback function data structure, the bar
> ADC callback function data structure and so forth. We need to think
> *NOW* about defining a common ADC callback structure so that we don't
> spawn a new problem which'll take effort to solve.
The cat's already well out of the bag on that one, we've got a bunch of
these things in tree already - the Cragganmore system I've got sitting
here on my desk has three auxiliary ADCs I'm aware of, all of which are
supported in mainline, and they're far from the only ones.
I think we should just carry on as we are while the IIO work proceeds,
either we'll decide that that's the way forward and we can then kick all
the ADCs into there or we'll get fed up, decide that's never going to
work then go and can do something else.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 11:09 ` Linus Walleij
@ 2011-10-13 11:35 ` Jonathan Cameron
0 siblings, 0 replies; 78+ messages in thread
From: Jonathan Cameron @ 2011-10-13 11:35 UTC (permalink / raw)
To: linux-arm-kernel
On 10/13/11 12:09, Linus Walleij wrote:
> On Thu, Oct 13, 2011 at 11:47 AM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
>> On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
>>> On Mon, Oct 10, 2011 at 01:42:30PM +0200, Zoltan Devai wrote:
>>>
>>>> Where should the adc driver go in this case ?
>>>
>>> At the minute it seems to me that arch/arm is as good a place as any
>>> really - currently this code is getting dumped wherever the main device
>>> is.
>>
>> No it isn't - we want drivers out of arch/arm (it's already been a topic
>> of flame for Linus, so it's something that we should try _really_ hard
>> to avoid.)
>
> Amen to that.
>
>> As this is clearly a device driver (it has a device driver struct, it
>> relies upon a struct device, etc) then it needs to live outside of
>> arch/arm/ - and I think Arnd's suggestion of drivers/adc is probably
>> the right place for it to move to (even though its probably the first
>> to create the directory.) More stuff can come along in the future,
>> and then its all together to start creating a common API in there.
>
> That sort of suggest that the drivers/staging/iio/adc is in
> trouble now. It will have an in-kernel competitor for similar
> stuff.
>
> Having drivers/adc and drivers/iio/adc compete about
> taking drivers on preference as to whether they were intended
> for userspace or kernelspace does not seem like a good
> thing.
The problem with a straight adc directory is the fact that many of
these devices are combined input and output. The also tend to
have numerous things that to a casual don't look like ADC's
(light sensors etc). We only did the grouping in IIO for the
sake of not having a huge flat directory. Many of the drivers
overlap between the different categories.
>
>>From a quick review of the IIO ADC subsystem I cannot really
> find a big problem with it other than it brings the entire IIO
> subsystem along, including the userspace interfaces I guess.
>
> The circumstances seem to suggest that drivers/iio/adc should
> be moved down to drivers/adc without the rest of the iio
> stuff, with a in-kernel API only and then have iio use that
> (this is probably true for some more drivers in IIO like
> dac, accel, addac, gyro...).
>
> So the concept of IIO stuff would change from the
> userspace-first centric view to the kernelspace-first
> centric, with optional userspace interfaces in the form
> of IIO.
>
> I'm not sure about what Jonathan thinks about that
> though.
That wouldn't be too hard to do. It's just a case of breaking
iio_register_device function in two. Right now (with the in kernel
RFC) on top. The only thing needed for in kernel access is that the
configured struct iio_dev gets added to the list of available devices.
I think we need to maintain the form of struct iio_chan_spec
(or whatever does the same job) with the intent of it directly mapping
to userspace interfaces (keeps things clean and makes sure there is enough
information to actually use the channel for anything).
The key thing is the unified specification of channel capabilities
and the ability to read them. We have one way of doing that which
has developed against a 'lot' of drivers.
The nasty corner is optimized reading of channel scans. They tend to
be irrelevant for memory mapped device but are vital for many devices
on low bandwidth buses. Right now we leave that entirely to the
individual drivers (they push this data out rather than it being
pulled from the core like everything else). It may be possible to
flip this around with out too much pain, but I'm not sure.
The other nasty bits are:
* hardware buffering
* triggered capture control - we really care about this for IIO
and I don't think anyone else does. Could maybe get away with using
device tree or similar to specify defaults for this and not provide
any means of changing it for devices other than those with full IIO
userspace in place.
As you can imagine I'm a little wary of sending IIO through another
refactoring right now (proposal to move the core out of staging is
scheduled for my next free afternoon!). So in principal in favour
of this approach but in practice not sure I'll be in a position
to do it (need to eat and my funding source is about to run out -
awaiting decision on more).
So my personal preference would be to add the relevant access functions
etc to IIO as is. Two models:
1) Pull from drivers - (give me reading now).
Done - we need to nick the clkdev mapping approach to join everything
up and play a few tricks to get a unique consistent name.
2) Push from triggered capture - (here is a reading).
Easiest option from our point of view is to provide this as a 'buffer'
implementation. Normally we'd notify userspace of new data, here we
notify in kernel users (or just push it into their callbacks).
Post that we start to make IIO userspace interfaces optional.
It gives a progression towards what you are suggesting and doesn't
hold us up in staging for another long cycle.
There are exceptions. I'd argue any element that is really built for
say hwmon or input ought to register directly with those subsytems.
That includes the touchscreen element of the adc that started this
conversation. No point in adding overhead and generality to a non
general element.
Sorry for quick reply, mad day.
Jonathan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 11:35 ` Mark Brown
@ 2011-10-13 12:17 ` Russell King - ARM Linux
2011-10-13 14:19 ` Arnd Bergmann
2011-10-13 14:38 ` Mark Brown
0 siblings, 2 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-13 12:17 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 12:35:06PM +0100, Mark Brown wrote:
> On Thu, Oct 13, 2011 at 10:47:17AM +0100, Russell King - ARM Linux wrote:
> > On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
>
> > > At the minute it seems to me that arch/arm is as good a place as any
> > > really - currently this code is getting dumped wherever the main device
> > > is.
>
> > No it isn't - we want drivers out of arch/arm (it's already been a topic
> > of flame for Linus, so it's something that we should try _really_ hard
> > to avoid.)
>
> I said it was as good a place as any, I didn't say it was a good place.
I'm saying it is a *BAD* place. I'm saying that we've been flamed over
this several times before. We need to change our behaviour RIGHT NOW,
not continue on ignoring the problem, and demonstrating to Linus that
we don't take his concerns seriously.
If we can't find a place for it that's outside of arch/arm, then it
doesn't go in.
> I think we should just carry on as we are while the IIO work proceeds,
> either we'll decide that that's the way forward and we can then kick all
> the ADCs into there or we'll get fed up, decide that's never going to
> work then go and can do something else.
You mean like other stuff which is already in the kernel gets fixed?
It doesn't get fixed. We persist with per-driver private data structures
which multiply all over the place.
Look at what happened with MTD and the flash_platform_data structure.
That got ignored and instead people just continued merrily creating their
own private crap time and time again.
We can not continue like this. We can not continue to be soo permissive.
I'm now saying a big NO to this - I don't care that the "cat is already
out of the bag" - that's a defeatest attitude. I'm saying no *now* so
that there _is_ some kind of movement towards fixing this problem. I
don't care whether that means it shares an existing ADC drivers callback
data structures or what - I just don't want to see yet another driver
private data structure being created for NO REASON what so ever.
Or maybe you'd like to be on the receiving end of another Linus flame?
Some people would like to avoid such things - maybe you feed off them,
that's your decision. I personally am on the side of the folk who'd
like to avoid being on the receiving end of the next Linus flame.
So. No new drivers in arch/arm. And I'm going to be saying no to any
new per-driver data structures in mach/*.h for stuff which should be
generic which haven't been justified for why they need to be different
from someone elses.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 12:17 ` Russell King - ARM Linux
@ 2011-10-13 14:19 ` Arnd Bergmann
2011-10-13 14:27 ` Mark Brown
2011-10-13 14:38 ` Mark Brown
1 sibling, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-13 14:19 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 13 October 2011, Russell King - ARM Linux wrote:
> On Thu, Oct 13, 2011 at 12:35:06PM +0100, Mark Brown wrote:
> > On Thu, Oct 13, 2011 at 10:47:17AM +0100, Russell King - ARM Linux wrote:
> > > On Mon, Oct 10, 2011 at 12:44:08PM +0100, Mark Brown wrote:
> >
> > > > At the minute it seems to me that arch/arm is as good a place as any
> > > > really - currently this code is getting dumped wherever the main device
> > > > is.
> >
> > > No it isn't - we want drivers out of arch/arm (it's already been a topic
> > > of flame for Linus, so it's something that we should try really hard
> > > to avoid.)
> >
> > I said it was as good a place as any, I didn't say it was a good place.
>
> I'm saying it is a BAD place. I'm saying that we've been flamed over
> this several times before. We need to change our behaviour RIGHT NOW,
> not continue on ignoring the problem, and demonstrating to Linus that
> we don't take his concerns seriously.
>
> If we can't find a place for it that's outside of arch/arm, then it
> doesn't go in.
How about deferring the decision for now and putting it into
drivers/staging/adc, with a single TODO item listing "Work out proper
API"? After all, the reason this driver doesn't fit anywhere is that
there is no established subsystem for it, at least not outside of
staging.
AFAICT, the driver is not essential for spmp8000 systems, but you
would want to have it there in practice. It makes little sense to
put the driver into drivers/adc and then later change the interface
fundamentally again if we decide to go with drivers/iio/adc providing
the common abstraction lation.
Of course, if the spmp8000 adc driver gets put into staging, all its
dependencies (input, battery) also have to go there because no
regular driver must link against interfaces provided by a staging
driver.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 14:19 ` Arnd Bergmann
@ 2011-10-13 14:27 ` Mark Brown
0 siblings, 0 replies; 78+ messages in thread
From: Mark Brown @ 2011-10-13 14:27 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 04:19:39PM +0200, Arnd Bergmann wrote:
> Of course, if the spmp8000 adc driver gets put into staging, all its
> dependencies (input, battery) also have to go there because no
> regular driver must link against interfaces provided by a staging
> driver.
Yes, that's the big problem with this - it blocks the actual drivers.
Putting it in drivers/misc would be another option that sidesteps that.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 12:17 ` Russell King - ARM Linux
2011-10-13 14:19 ` Arnd Bergmann
@ 2011-10-13 14:38 ` Mark Brown
2011-10-13 14:56 ` Arnd Bergmann
1 sibling, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-13 14:38 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 01:17:45PM +0100, Russell King - ARM Linux wrote:
> On Thu, Oct 13, 2011 at 12:35:06PM +0100, Mark Brown wrote:
> > I said it was as good a place as any, I didn't say it was a good place.
> I'm saying it is a *BAD* place. I'm saying that we've been flamed over
> this several times before. We need to change our behaviour RIGHT NOW,
> not continue on ignoring the problem, and demonstrating to Linus that
> we don't take his concerns seriously.
I think we're agreeing here...
> > I think we should just carry on as we are while the IIO work proceeds,
> > either we'll decide that that's the way forward and we can then kick all
> > the ADCs into there or we'll get fed up, decide that's never going to
> > work then go and can do something else.
> You mean like other stuff which is already in the kernel gets fixed?
> It doesn't get fixed. We persist with per-driver private data structures
> which multiply all over the place.
> Look at what happened with MTD and the flash_platform_data structure.
> That got ignored and instead people just continued merrily creating their
> own private crap time and time again.
The situation here is a bit different; there's people working on
handling these devices already but we can't point people at it as
something they can use yet. As soon as we've got something to point
people at we should absolutely be going and actively pushing them
towards it but right now we don't have that option.
> We can not continue like this. We can not continue to be soo permissive.
> I'm now saying a big NO to this - I don't care that the "cat is already
> out of the bag" - that's a defeatest attitude. I'm saying no *now* so
> that there _is_ some kind of movement towards fixing this problem. I
Half the problem that's being pointed out is that there is already
movement towards a solution for these devices, it's just not quite at
the point where it can be used for this class of devices yet. The point
with the existing drivers being there is that this isn't a new driver
setting a precedent, if we had chosen to merge the driver we'd simply be
taking a decision to avoid creating churn that disrupts the existing
work.
> don't care whether that means it shares an existing ADC drivers callback
> data structures or what - I just don't want to see yet another driver
> private data structure being created for NO REASON what so ever.
Well, what do we do then? I guess so long as it's outside arch/arm you
don't mind too much.
> Or maybe you'd like to be on the receiving end of another Linus flame?
> Some people would like to avoid such things - maybe you feed off them,
> that's your decision. I personally am on the side of the folk who'd
> like to avoid being on the receiving end of the next Linus flame.
On the other hand we also don't want to overreact and we don't want to
irritate people by just putting stuff into a different directory without
actually improving it. The goal isn't to troll Linus, the goal is to be
pragmatic about what we're actually achieving. It's similar to the
decision that was taken to allow platforms to proceed without the
generic clk API or device tree bindings for the clk API.
> So. No new drivers in arch/arm. And I'm going to be saying no to any
> new per-driver data structures in mach/*.h for stuff which should be
> generic which haven't been justified for why they need to be different
> from someone elses.
The driver specific data structures should probably just be moving to
include/linux/platform_data which is the approved location for that sort
of thing.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 14:38 ` Mark Brown
@ 2011-10-13 14:56 ` Arnd Bergmann
2011-10-13 16:25 ` Mark Brown
0 siblings, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-13 14:56 UTC (permalink / raw)
To: linux-arm-kernel
On Thursday 13 October 2011, Mark Brown wrote:
> > So. No new drivers in arch/arm. And I'm going to be saying no to any
> > new per-driver data structures in mach/*.h for stuff which should be
> > generic which haven't been justified for why they need to be different
> > from someone elses.
>
> The driver specific data structures should probably just be moving to
> include/linux/platform_data which is the approved location for that sort
> of thing.
Note that we also need someone to watch over that and say no to silly
platform_data definitions being put in there, e.g. using wildly different
ways of expressing the same things in almost-identical drivers, or
using function pointers where a simple data structure is enough.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 4/9] ARM: SPMP8000: Add ADC driver
2011-10-13 14:56 ` Arnd Bergmann
@ 2011-10-13 16:25 ` Mark Brown
0 siblings, 0 replies; 78+ messages in thread
From: Mark Brown @ 2011-10-13 16:25 UTC (permalink / raw)
To: linux-arm-kernel
On Thu, Oct 13, 2011 at 04:56:56PM +0200, Arnd Bergmann wrote:
> On Thursday 13 October 2011, Mark Brown wrote:
> > The driver specific data structures should probably just be moving to
> > include/linux/platform_data which is the approved location for that sort
> > of thing.
> Note that we also need someone to watch over that and say no to silly
> platform_data definitions being put in there, e.g. using wildly different
> ways of expressing the same things in almost-identical drivers, or
> using function pointers where a simple data structure is enough.
Yeah, I'm not sure I entirely understand the plan with it though even
without any structure it doesn't make much difference (in that
everything is being reviewed by the subsystem maintainers just as it was
before we dumped the files in a single directory). I'm tempted to say
the device tree folks should be looking at it as an awful lot of what
they're doing is exactly the same thing.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-11 14:44 ` Arnd Bergmann
@ 2011-10-16 14:10 ` Zoltan Devai
2011-10-16 15:57 ` Russell King - ARM Linux
2011-10-16 20:59 ` Arnd Bergmann
0 siblings, 2 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-16 14:10 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/11 Arnd Bergmann <arnd@arndb.de>:
> On Sunday 09 October 2011, Zoltan Devai wrote:
>> +
>> +/* Static mappings:
>> + * SCU: timer needs clk support which is inited in init_early
>> + * UART: needed for earlyprintk
>> + */
>> +static struct map_desc io_desc[] __initdata = {
>> + ? ? {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_A_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_A_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_A_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_B_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_B_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_B_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? }, {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_SCU_C_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_SCU_C_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_SCU_C_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>
> With Nicolas Pitre's rework of the MMIO space handling, I think it
> would be nice to just use a single area that spans all of the devices
> so you can do an optimized ioremap and huge TLBs. Unfortunately
> that series won't make it into 3.2, but if you just set up a large
> area now, it will automatically work.
What do you mean by 'all of the devices' ?
These three, or all MMIO peripherals ?
These are at addresses 0x90005000, 0x92005000 and 0x93007000.
So either a 50 or 256 MB area, but both seem like a waste of
virtual memory space.
>> +#ifdef CONFIG_DEBUG_LL
>> + ? ? {
>> + ? ? ? ? ? ? .virtual ? ? ? ?= IO_ADDRESS(SPMP8000_UARTC0_BASE),
>> + ? ? ? ? ? ? .pfn ? ? ? ? ? ?= __phys_to_pfn(SPMP8000_UARTC0_BASE),
>> + ? ? ? ? ? ? .length ? ? ? ? = SPMP8000_UARTC0_SIZE,
>> + ? ? ? ? ? ? .type ? ? ? ? ? = MT_DEVICE,
>> + ? ? },
>> +#endif
>> +};
>>
> And it would be nice to move this into a separate file that handles the
> early debug code, as prima2 does.
Prima2 doesn't have other static mappings. In my case, that would
mean a separate map_desc table in lluart.c and an
#ifdef CONFIG_DEBUG_LL in the map_io call.
Is it worth it ?
BTW, the static mappings are only needed to be able to set up the
clk stuff in init_early. That in turn is only needed for the timer code to
determinate its input clock.
If I would hard-code the timer clock rate in its driver (the bootloader is
very unlikely to change), then I could init the clk driver from
machine_init and get rid of these mappings.
How about that ?
BTW2,
shouldn't the timer driver also go to drivers/clocksource ?
>> +#ifndef __MACH_SPMP8000_DMA_H__
>> +#define __MACH_SPMP8000_DMA_H__
>> +
>> +enum spmp8000_dma_controller {
>> + ? ? SPMP8000_APBDMA_A ? ? ? = 0,
>> + ? ? SPMP8000_APBDMA_C,
>> +};
...
> Please separate the dma controller out for now into a separate patch.
> We really need to have proper device tree bindings so we can avoid the
> silly filter functions and do something better. That needs some more
> discussion and any help on the interface is very much appreciated.
OK
>> diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h b/arch/arm/mach-spmp8000/include/mach/gpio.h
>> new file mode 100644
>
>> +#ifndef __MACH_SPMP8000_GPIO_H__
>> +#define __MACH_SPMP8000_GPIO_H__
>> +
>> +#include <asm-generic/gpio.h>
>> +
>> +#define gpio_get_value ? ? ? ? ? ? ? __gpio_get_value
>> +#define gpio_set_value ? ? ? ? ? ? ? __gpio_set_value
>> +#define gpio_cansleep ? ? ? ? ? ? ? ?__gpio_cansleep
>> +#define gpio_to_irq ? ? ? ? ?__gpio_to_irq
>> +
>> +#endif /* __MACH_SPMP8000_GPIO_H__ */
>
> I think this can become an empty file now, with Russell's latest cleanup
> going into 3.2.
I didn't find that in either your or Russell's tree, where should I look
for it ?
>> +/* Vitual to physical translation of statically mapped space */
>> +#define IO_ADDRESS(x) ? ? ? ? ? ? ? ?((x) | 0xF0000000)
>
> Better make this return a 'void __iomem *', e.g. by doing
>
> #define IO_ADDRESS(x) ? (((x) & 0x0fffffff) + ((void __iomem *)0xf0000000)
This is used by map_desc, so it needs to return an int.
I use IO_PTR for the pointer version, but maybe the naming is misleading.
>> +/* Needed for the static mappings and uncompress.h */
>> +#define SPMP8000_UARTC0_BASE 0x92B04000
>> +#define SPMP8000_UARTC0_SIZE SZ_4K
>> +#define SPMP8000_SCU_C_BASE ?0x92005000
>> +#define SPMP8000_SCU_C_SIZE ?SZ_4K
>> +#define SPMP8000_SCU_A_BASE ?0x93007000
>> +#define SPMP8000_SCU_A_SIZE ?SZ_4K
>> +#define SPMP8000_SCU_B_BASE ?0x90005000
>> +#define SPMP8000_SCU_B_SIZE ?SZ_4K
>
> Do you need these all so early that you cannot get the location from the device
> tree?
See the reason above
>> +/* FIXME This should go away */
>> +#define IO_SPACE_LIMIT ?0
>> +
>> +#define __mem_pci(a) ? ?(a)
>> +#define __io(a) ? ? ? ? __typesafe_io(a)
>> +
>
> I think you should better define __io() to NULL.
OK
>> +++ b/arch/arm/mach-spmp8000/include/mach/regs-timer.h
>> @@ -0,0 +1,32 @@
>> +/*
>> + * SPMP8000 timer support
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + *
>> + * These timer reg definitions are used by the timer and pwm drivers
>> + */
>> +#ifndef __MACH_SPMP8000_REGS_TIMER_H__
>> +#define __MACH_SPMP8000_REGS_TIMER_H__
>> +
>> +#define SPMP8000_TMRB(tnum) ?(tnum * 0x20)
>> +#define SPMP8000_TMRB_CTR ? ?0x00
>> +#define SPMP8000_TMRB_CTR_TE BIT(0)
>> +#define SPMP8000_TMRB_CTR_IE BIT(1)
>> +#define SPMP8000_TMRB_CTR_OE BIT(2)
>> +#define SPMP8000_TMRB_CTR_PWMON ? ? ?BIT(3)
>> +#define SPMP8000_TMRB_CTR_UD BIT(4)
>> +#define SPMP8000_TMRB_CTR_UDS ? ? ? ?BIT(5)
>> +#define SPMP8000_TMRB_CTR_OM BIT(6)
>> +#define SPMP8000_TMRB_CTR_ES_SH ? ? ?8
>> +#define SPMP8000_TMRB_CTR_M_SH ? ? ? 10
>> +#define SPMP8000_TMRB_PSR ? ?0x04
>> +#define SPMP8000_TMRB_LDR ? ?0x08
>> +#define SPMP8000_TMRB_VLR ? ?0x08
>> +#define SPMP8000_TMRB_ISR ? ?0x0C
>> +#define SPMP8000_TMRB_CMP ? ?0x10
>> +
>> +#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
>
> No need for this header, just move the definitions into the timer driver.
It's also used by the pwm driver (pwm is just a timer with a HW output pin)
as the header indicates. Not a lots of lines, so I can include it in both
if you think that's more appropriate.
>> diff --git a/arch/arm/mach-spmp8000/include/mach/scu.h b/arch/arm/mach-spmp8000/include/mach/scu.h
>> new file mode 100644
>> index 0000000..e3a98d4
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/scu.h
>> @@ -0,0 +1,146 @@
>> +/*
>> + * SPMP8000 System Control Unit register definitions
>> + * SCUs are a random collection of reset, clock, gpio, pinmux, etc. controllers
>> + * so that these definitions are needed at several places.
>
>> +struct scu_reg_t {
>> + ? ? void *base;
>> + ? ? void *clken;
>> +};
>> +
>> +extern struct scu_reg_t scu_regs[];
>> +
>> +#define REG_SCU_BASE(x) ? ? ? ? ? ? ?scu_regs[x].base
>> +#define REG_SCU_CLKEN(x) ? ? scu_regs[x].clken
>> +#define REG_SCU_A_ID ? ? ? ? 0
>> +#define REG_SCU_B_ID ? ? ? ? 1
>> +#define REG_SCU_C_ID ? ? ? ? 2
>> +#define REG_SCU_A(x) ? ? ? ? (scu_regs[REG_SCU_A_ID].base + x)
>> +#define REG_SCU_B(x) ? ? ? ? (scu_regs[REG_SCU_B_ID].base + x)
>> +#define REG_SCU_C(x) ? ? ? ? (scu_regs[REG_SCU_C_ID].base + x)
>
> I would prefer having ?this in core.c, so the base addresses can
> remain private to that file instead of exporting them to
> all of the kernel.
I'll get rid of these macros altogether, they're not really nice.
>> +#define SCU_A_PERI_RST ? ? ? ? ? ? ? 0x00
>> +#define SCU_A_PERI_CLKEN ? ? 0x04
>> +#define SCU_A_PERI_DGCLKEN ? 0x0C
>> +
>> +#define SCU_A_APLL_CFG ? ? ? ? ? ? ? 0x44
>> +#define APLL_CFG_P ? ? ? ? ? BIT(0)
>> +#define APLL_CFG_S ? ? ? ? ? BIT(1)
>> +#define APLL_CFG_F ? ? ? ? ? BIT(2)
>> +#define APLL_CFG_E ? ? ? ? ? BIT(3)
>
> The BIT() definition is really just mean for kernel-internal bitops,
> not so much for device registers.
>
> My recommended style of this is
>
> #define APLL_CFG_P ? ? ? ? ? ? ?0x00000001
> #define APLL_CFG_S ? ? ? ? ? ? ?0x00000002
> #define APLL_CFG_F ? ? ? ? ? ? ?0x00000004
> #define APLL_CFG_E ? ? ? ? ? ? ?0x00000008
Are you sure about this ?
I recall reading a recommendation to use BIT() as its less
error-prone, easier matched with the datasheet and properly typed.
Also:
kernel$ grep -R " BIT(" drivers/ | wc -l
2186
>> diff --git a/arch/arm/mach-spmp8000/include/mach/system.h b/arch/arm/mach-spmp8000/include/mach/system.h
>> new file mode 100644
>> index 0000000..be53ff3
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/include/mach/system.h
>> @@ -0,0 +1,45 @@
>> +/*
>> + * SPMP8000 system.h
>> + *
>> + * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
>> + *
>> + * This file is licensed under the terms of the GNU General Public
>> + * License version 2. This program is licensed "as is" without any
>> + * warranty of any kind, whether express or implied.
>> + */
>> +
>> +#ifndef __MACH_SPMP8000_SYSTEM_H__
>> +#define __MACH_SPMP8000_SYSTEM_H__
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/io.h>
>> +
>> +#define SPMP8000_WDT_BASE ? ?0x90001000
>> +#define SPMP8000_WDT_SIZE ? ?0x1000
>
> These have to be removed. For device drivers, you should normally
> use of_iomap to get at the registers.
>
>> +#define SPMP8000_WDT_CTR ? ? 0x00
>> +#define SPMP8000_WDT_CTR_TE ?BIT(0)
>> +#define SPMP8000_WDT_CTR_RE ?BIT(3)
>> +
>> +static inline void arch_idle(void)
>> +{
>> + ? ? cpu_do_idle();
>> +}
>> +
>> +static inline void arch_reset(char mode, const char *cmd)
>> +{
>> + ? ? void *base;
>> +
>> + ? ? base = ioremap(SPMP8000_WDT_BASE, SPMP8000_WDT_SIZE);
>> + ? ? if (!base) {
>> + ? ? ? ? ? ? pr_err("spmp8000: Can't ioremap watchdog regs for reset. "
>> + ? ? ? ? ? ? ? ? ? ? "Halt.");
>> + ? ? ? ? ? ? while (1);
>> + ? ? }
>> +
>> + ? ? /* Trigger a watchdog reset */
>> + ? ? writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
>> + ? ? ? ? ? ? ? ? ? ? base + SPMP8000_WDT_CTR);
>> +}
>
> Using the watchdog for arch_reset is clever, but unfortunately not
> too common otherwise, so you have to play tricks. I would try
> locating the device and ioremapping it from core.c and then
> export a function to set the register that is used both by
> the arch_reset function and by the watchdog driver. The latter
> can still bind to the platform_device, but it then doesn't have
> to do an extra of_iomap.
OK
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/9] ARM: SPMP8000: Add clk support
2011-10-13 9:38 ` Russell King - ARM Linux
@ 2011-10-16 14:16 ` Zoltan Devai
2011-10-17 12:15 ` Mark Brown
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-16 14:16 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/13 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Sun, Oct 09, 2011 at 06:36:06PM +0200, Zoltan Devai wrote:
>> --- /dev/null
>> +++ b/arch/arm/mach-spmp8000/clkdev.c
...
>> +#include <mach/scu.h>
>
> I find the use of 'scu' for something which isn't the SMP Coherence Unit
> rather confusing - and I suspect you will too if/when spmp8000 has SMP
> support.
Well, Sunplus decided to name these devices 'SCU', which are a collection
of reset, clock, debug, pinmux and gpio stuff.
The datasheet doesn't even tell what SCU stands for, but I'd prefer to keep
the naming to be in sync with the documentation.
I'll fix the issues pointed out by your other comments in the next version.
Thanks,
Zoltan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-16 14:10 ` Zoltan Devai
@ 2011-10-16 15:57 ` Russell King - ARM Linux
2011-10-16 20:59 ` Arnd Bergmann
1 sibling, 0 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-16 15:57 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 16, 2011 at 04:10:34PM +0200, Zoltan Devai wrote:
> 2011/10/11 Arnd Bergmann <arnd@arndb.de>:
> > I think this can become an empty file now, with Russell's latest cleanup
> > going into 3.2.
> I didn't find that in either your or Russell's tree, where should I look
> for it ?
It's definitely there - this is how asm/gpio.h is changed:
diff --git a/arch/arm/include/asm/gpio.h b/arch/arm/include/asm/gpio.h
index 166a7a3..11ad0bf 100644
--- a/arch/arm/include/asm/gpio.h
+++ b/arch/arm/include/asm/gpio.h
@@ -4,4 +4,23 @@
/* not all ARM platforms necessarily support this API ... */
#include <mach/gpio.h>
+#ifndef __ARM_GPIOLIB_COMPLEX
+/* Note: this may rely upon the value of ARCH_NR_GPIOS set in mach/gpio.h */
+#include <asm-generic/gpio.h>
+
+/* The trivial gpiolib dispatchers */
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep __gpio_cansleep
+#endif
+
+/*
+ * Provide a default gpio_to_irq() which should satisfy every case.
+ * However, some platforms want to do this differently, so allow them
+ * to override it.
+ */
+#ifndef gpio_to_irq
+#define gpio_to_irq __gpio_to_irq
+#endif
+
#endif /* _ARCH_ARM_GPIO_H */
So, for the case where everything goes through gpiolib and there's no
platform accelerators for SoC GPIOs, there's no need to have anything
in mach/gpio.h. If a platform does want to do something special, it
needs to define __ARM_GPIOLIB_COMPLEX.
> >> +/* Vitual to physical translation of statically mapped space */
> >> +#define IO_ADDRESS(x) ? ? ? ? ? ? ? ?((x) | 0xF0000000)
> >
> > Better make this return a 'void __iomem *', e.g. by doing
> >
> > #define IO_ADDRESS(x) ? (((x) & 0x0fffffff) + ((void __iomem *)0xf0000000)
> This is used by map_desc, so it needs to return an int.
> I use IO_PTR for the pointer version, but maybe the naming is misleading.
Much preferred to have macros returning virtual addresses as a pointer,
and then have the map_desc stuff cast. This means if you end up using
IO_ADDRESS() with readl() etc, then you're going to be correct no matter
what.
> >> +/* FIXME This should go away */
> >> +#define IO_SPACE_LIMIT ?0
> >> +
> >> +#define __mem_pci(a) ? ?(a)
> >> +#define __io(a) ? ? ? ? __typesafe_io(a)
> >> +
> >
> > I think you should better define __io() to NULL.
> OK
Or if you don't have any PCI/ISA IO, don't define __io at all, which
means inb() et.al. will be undefined (note: the 8250 driver still wants
these.) Also select NO_IOPORT as well in the config if you don't support
PCI/ISA IO.
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-16 20:59 ` Arnd Bergmann
@ 2011-10-16 20:52 ` Jean-Christophe PLAGNIOL-VILLARD
2011-10-17 11:44 ` Arnd Bergmann
0 siblings, 1 reply; 78+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2011-10-16 20:52 UTC (permalink / raw)
To: linux-arm-kernel
On 22:59 Sun 16 Oct , Arnd Bergmann wrote:
> On Sunday 16 October 2011, Zoltan Devai wrote:
> > 2011/10/11 Arnd Bergmann <arnd@arndb.de>:
> > > On Sunday 09 October 2011, Zoltan Devai wrote:
> > >> +
> > >> +/* Static mappings:
> > >> + * SCU: timer needs clk support which is inited in init_early
> > >> + * UART: needed for earlyprintk
> > >> + */
> > >> +static struct map_desc io_desc[] __initdata = {
> > >> + {
> > >> + .virtual = IO_ADDRESS(SPMP8000_SCU_A_BASE),
> > >> + .pfn = __phys_to_pfn(SPMP8000_SCU_A_BASE),
> > >> + .length = SPMP8000_SCU_A_SIZE,
> > >> + .type = MT_DEVICE,
> > >> + }, {
> > >> + .virtual = IO_ADDRESS(SPMP8000_SCU_B_BASE),
> > >> + .pfn = __phys_to_pfn(SPMP8000_SCU_B_BASE),
> > >> + .length = SPMP8000_SCU_B_SIZE,
> > >> + .type = MT_DEVICE,
> > >> + }, {
> > >> + .virtual = IO_ADDRESS(SPMP8000_SCU_C_BASE),
> > >> + .pfn = __phys_to_pfn(SPMP8000_SCU_C_BASE),
> > >> + .length = SPMP8000_SCU_C_SIZE,
> > >> + .type = MT_DEVICE,
> > >> + },
> > >
> > > With Nicolas Pitre's rework of the MMIO space handling, I think it
> > > would be nice to just use a single area that spans all of the devices
> > > so you can do an optimized ioremap and huge TLBs. Unfortunately
> > > that series won't make it into 3.2, but if you just set up a large
> > > area now, it will automatically work.
> > What do you mean by 'all of the devices' ?
> > These three, or all MMIO peripherals ?
> > These are at addresses 0x90005000, 0x92005000 and 0x93007000.
> > So either a 50 or 256 MB area, but both seem like a waste of
> > virtual memory space.
>
> I was thinking of mapping everything that your IO_ADDRESS macro covers,
> which should be something like 240 MB starting at 0x90000000/0xf0000000.
> On most ARM9 platforms, virtual memory is not really contraint at all
> because there is not all that much physical memory. Also, you currently
> reserve the entire 0xf0000000 segment for MMIO ranges, so I would
> expect that you can keep doing that after the cleanup.
>
> > >> +#ifdef CONFIG_DEBUG_LL
> > >> + {
> > >> + .virtual = IO_ADDRESS(SPMP8000_UARTC0_BASE),
> > >> + .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
> > >> + .length = SPMP8000_UARTC0_SIZE,
> > >> + .type = MT_DEVICE,
> > >> + },
> > >> +#endif
> > >> +};
> > >>
> > > And it would be nice to move this into a separate file that handles the
> > > early debug code, as prima2 does.
> > Prima2 doesn't have other static mappings. In my case, that would
> > mean a separate map_desc table in lluart.c and an
> > #ifdef CONFIG_DEBUG_LL in the map_io call.
> > Is it worth it ?
>
> Yes, it's worth it. Don't do the #ifdef in the map_io call though, do
> it in the header file that declares the function prototype.
>
> > BTW, the static mappings are only needed to be able to set up the
> > clk stuff in init_early. That in turn is only needed for the timer code to
> > determinate its input clock.
> > If I would hard-code the timer clock rate in its driver (the bootloader is
> > very unlikely to change), then I could init the clk driver from
> > machine_init and get rid of these mappings.
> > How about that ?
>
> Maybe you can just pass the clock rate in the device tree then. If the boot
> loader changes it, it can still pass the correct rate and you don't
> need the early mappings for functional reasons any more.
please don't update the DT from the bootloader, I'll recommand you to limit
your bootloader to just update the strict minimun (same as ATAG) and touch
noting else
Best Regards,
J.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-16 14:10 ` Zoltan Devai
2011-10-16 15:57 ` Russell King - ARM Linux
@ 2011-10-16 20:59 ` Arnd Bergmann
2011-10-16 20:52 ` Jean-Christophe PLAGNIOL-VILLARD
1 sibling, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-16 20:59 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 16 October 2011, Zoltan Devai wrote:
> 2011/10/11 Arnd Bergmann <arnd@arndb.de>:
> > On Sunday 09 October 2011, Zoltan Devai wrote:
> >> +
> >> +/* Static mappings:
> >> + * SCU: timer needs clk support which is inited in init_early
> >> + * UART: needed for earlyprintk
> >> + */
> >> +static struct map_desc io_desc[] __initdata = {
> >> + {
> >> + .virtual = IO_ADDRESS(SPMP8000_SCU_A_BASE),
> >> + .pfn = __phys_to_pfn(SPMP8000_SCU_A_BASE),
> >> + .length = SPMP8000_SCU_A_SIZE,
> >> + .type = MT_DEVICE,
> >> + }, {
> >> + .virtual = IO_ADDRESS(SPMP8000_SCU_B_BASE),
> >> + .pfn = __phys_to_pfn(SPMP8000_SCU_B_BASE),
> >> + .length = SPMP8000_SCU_B_SIZE,
> >> + .type = MT_DEVICE,
> >> + }, {
> >> + .virtual = IO_ADDRESS(SPMP8000_SCU_C_BASE),
> >> + .pfn = __phys_to_pfn(SPMP8000_SCU_C_BASE),
> >> + .length = SPMP8000_SCU_C_SIZE,
> >> + .type = MT_DEVICE,
> >> + },
> >
> > With Nicolas Pitre's rework of the MMIO space handling, I think it
> > would be nice to just use a single area that spans all of the devices
> > so you can do an optimized ioremap and huge TLBs. Unfortunately
> > that series won't make it into 3.2, but if you just set up a large
> > area now, it will automatically work.
> What do you mean by 'all of the devices' ?
> These three, or all MMIO peripherals ?
> These are at addresses 0x90005000, 0x92005000 and 0x93007000.
> So either a 50 or 256 MB area, but both seem like a waste of
> virtual memory space.
I was thinking of mapping everything that your IO_ADDRESS macro covers,
which should be something like 240 MB starting at 0x90000000/0xf0000000.
On most ARM9 platforms, virtual memory is not really contraint at all
because there is not all that much physical memory. Also, you currently
reserve the entire 0xf0000000 segment for MMIO ranges, so I would
expect that you can keep doing that after the cleanup.
> >> +#ifdef CONFIG_DEBUG_LL
> >> + {
> >> + .virtual = IO_ADDRESS(SPMP8000_UARTC0_BASE),
> >> + .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
> >> + .length = SPMP8000_UARTC0_SIZE,
> >> + .type = MT_DEVICE,
> >> + },
> >> +#endif
> >> +};
> >>
> > And it would be nice to move this into a separate file that handles the
> > early debug code, as prima2 does.
> Prima2 doesn't have other static mappings. In my case, that would
> mean a separate map_desc table in lluart.c and an
> #ifdef CONFIG_DEBUG_LL in the map_io call.
> Is it worth it ?
Yes, it's worth it. Don't do the #ifdef in the map_io call though, do
it in the header file that declares the function prototype.
> BTW, the static mappings are only needed to be able to set up the
> clk stuff in init_early. That in turn is only needed for the timer code to
> determinate its input clock.
> If I would hard-code the timer clock rate in its driver (the bootloader is
> very unlikely to change), then I could init the clk driver from
> machine_init and get rid of these mappings.
> How about that ?
Maybe you can just pass the clock rate in the device tree then. If the boot
loader changes it, it can still pass the correct rate and you don't
need the early mappings for functional reasons any more.
> BTW2,
> shouldn't the timer driver also go to drivers/clocksource ?
Yes, good point. Please move it there.
> >> +#ifndef __MACH_SPMP8000_REGS_TIMER_H__
> >> +#define __MACH_SPMP8000_REGS_TIMER_H__
> >> +
> >> +#define SPMP8000_TMRB(tnum) (tnum * 0x20)
> >> +#define SPMP8000_TMRB_CTR 0x00
> >> +#define SPMP8000_TMRB_CTR_TE BIT(0)
> >> +#define SPMP8000_TMRB_CTR_IE BIT(1)
> >> +#define SPMP8000_TMRB_CTR_OE BIT(2)
> >> +#define SPMP8000_TMRB_CTR_PWMON BIT(3)
> >> +#define SPMP8000_TMRB_CTR_UD BIT(4)
> >> +#define SPMP8000_TMRB_CTR_UDS BIT(5)
> >> +#define SPMP8000_TMRB_CTR_OM BIT(6)
> >> +#define SPMP8000_TMRB_CTR_ES_SH 8
> >> +#define SPMP8000_TMRB_CTR_M_SH 10
> >> +#define SPMP8000_TMRB_PSR 0x04
> >> +#define SPMP8000_TMRB_LDR 0x08
> >> +#define SPMP8000_TMRB_VLR 0x08
> >> +#define SPMP8000_TMRB_ISR 0x0C
> >> +#define SPMP8000_TMRB_CMP 0x10
> >> +
> >> +#endif /* __MACH_SPMP8000_REGS_TIMER_H__ */
> >
> > No need for this header, just move the definitions into the timer driver.
> It's also used by the pwm driver (pwm is just a timer with a HW output pin)
> as the header indicates. Not a lots of lines, so I can include it in both
> if you think that's more appropriate.
Normally you need to have proper locking around register accesses when
a piece of hardware is used by two drivers. My feeling is that the
abstraction should be on a higher level because of this, either exporting
functions from the timer driver that are used by the pwm driver, or
having one low-level mfd driver exporting simple functions that are used by
both of them.
> > The BIT() definition is really just mean for kernel-internal bitops,
> > not so much for device registers.
> >
> > My recommended style of this is
> >
> > #define APLL_CFG_P 0x00000001
> > #define APLL_CFG_S 0x00000002
> > #define APLL_CFG_F 0x00000004
> > #define APLL_CFG_E 0x00000008
> Are you sure about this ?
> I recall reading a recommendation to use BIT() as its less
> error-prone, easier matched with the datasheet and properly typed.
> Also:
> kernel$ grep -R " BIT(" drivers/ | wc -l
> 2186
Fair enough. My preference is still the other way (maybe with an added 'ul'
for type safety), but that may be mostly because I got bitten too much by
IBM hardware specifications numbering the bits in the opposite way.
Just decide for yourself here.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 2/9] ARM: SPMP8000: Add machine base files
2011-10-16 20:52 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2011-10-17 11:44 ` Arnd Bergmann
0 siblings, 0 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-17 11:44 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 16 October 2011, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 22:59 Sun 16 Oct , Arnd Bergmann wrote:
> > On Sunday 16 October 2011, Zoltan Devai wrote:
> >> BTW, the static mappings are only needed to be able to set up the
> >> clk stuff in init_early. That in turn is only needed for the timer code to
> >> determinate its input clock.
> >> If I would hard-code the timer clock rate in its driver (the bootloader is
> >> very unlikely to change), then I could init the clk driver from
> >> machine_init and get rid of these mappings.
> >> How about that ?
> >
> > Maybe you can just pass the clock rate in the device tree then. If the boot
> > loader changes it, it can still pass the correct rate and you don't
> > need the early mappings for functional reasons any more.
>
> please don't update the DT from the bootloader, I'll recommand you to limit
> your bootloader to just update the strict minimun (same as ATAG) and touch
> noting else
Why? Do you think it's better to hardcode it and have no way to update it?
Note that the more likely scenario even with clock rate in the device tree
would be that the value is hardcoded in the board's file and would not
be touched by the boot loader. Only if the boot loader actually changes
the physical clock rate (which Zoltan described as very unlikely), it
would also have to go the full length and update the device tree as well.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/9] ARM: SPMP8000: Add clk support
2011-10-16 14:16 ` Zoltan Devai
@ 2011-10-17 12:15 ` Mark Brown
2011-10-18 10:18 ` Russell King - ARM Linux
0 siblings, 1 reply; 78+ messages in thread
From: Mark Brown @ 2011-10-17 12:15 UTC (permalink / raw)
To: linux-arm-kernel
On Sun, Oct 16, 2011 at 04:16:45PM +0200, Zoltan Devai wrote:
> 2011/10/13 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> > I find the use of 'scu' for something which isn't the SMP Coherence Unit
> > rather confusing - and I suspect you will too if/when spmp8000 has SMP
> > support.
> Well, Sunplus decided to name these devices 'SCU', which are a collection
> of reset, clock, debug, pinmux and gpio stuff.
> The datasheet doesn't even tell what SCU stands for, but I'd prefer to keep
> the naming to be in sync with the documentation.
System Control Unit. It's a fairly common name to use for the core
system glue logic.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH 3/9] ARM: SPMP8000: Add clk support
2011-10-17 12:15 ` Mark Brown
@ 2011-10-18 10:18 ` Russell King - ARM Linux
0 siblings, 0 replies; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-18 10:18 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Oct 17, 2011 at 01:15:48PM +0100, Mark Brown wrote:
> On Sun, Oct 16, 2011 at 04:16:45PM +0200, Zoltan Devai wrote:
> > 2011/10/13 Russell King - ARM Linux <linux@arm.linux.org.uk>:
>
> > > I find the use of 'scu' for something which isn't the SMP Coherence Unit
Sorry, that should've been 'snoop control unit' to give its proper
terminology.
> > > rather confusing - and I suspect you will too if/when spmp8000 has SMP
> > > support.
>
> > Well, Sunplus decided to name these devices 'SCU', which are a collection
> > of reset, clock, debug, pinmux and gpio stuff.
> > The datasheet doesn't even tell what SCU stands for, but I'd prefer to keep
> > the naming to be in sync with the documentation.
>
> System Control Unit. It's a fairly common name to use for the core
> system glue logic.
So, what do we do about this confusing overloading of a TLA ? It's
already had me searching through these patches for some reference
to SMP stuff and wondering if its differing SMP implementation.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
@ 2011-10-19 16:01 ` Zoltan Devai
2011-10-19 19:15 ` Arnd Bergmann
2011-10-19 16:01 ` [PATCH v2 2/5] ARM: SPMP8000: Add clk support Zoltan Devai
` (3 subsequent siblings)
4 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-19 16:01 UTC (permalink / raw)
To: linux-arm-kernel
Files needed for the basic machine support of SPMP8000
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/Makefile | 4 +
arch/arm/mach-spmp8000/Makefile.boot | 1 +
arch/arm/mach-spmp8000/core.c | 79 +++++++++++++++++++++
arch/arm/mach-spmp8000/core.h | 27 +++++++
arch/arm/mach-spmp8000/include/mach/debug-macro.S | 19 +++++
arch/arm/mach-spmp8000/include/mach/entry-macro.S | 14 ++++
arch/arm/mach-spmp8000/include/mach/gpio.h | 1 +
arch/arm/mach-spmp8000/include/mach/hardware.h | 25 +++++++
arch/arm/mach-spmp8000/include/mach/io.h | 17 +++++
arch/arm/mach-spmp8000/include/mach/irqs.h | 21 ++++++
arch/arm/mach-spmp8000/include/mach/memory.h | 1 +
arch/arm/mach-spmp8000/include/mach/system.h | 43 +++++++++++
arch/arm/mach-spmp8000/include/mach/timex.h | 17 +++++
arch/arm/mach-spmp8000/include/mach/uncompress.h | 37 ++++++++++
arch/arm/mach-spmp8000/include/mach/vmalloc.h | 16 ++++
arch/arm/mach-spmp8000/lluart.c | 24 ++++++
16 files changed, 346 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/Makefile
create mode 100644 arch/arm/mach-spmp8000/Makefile.boot
create mode 100644 arch/arm/mach-spmp8000/core.c
create mode 100644 arch/arm/mach-spmp8000/core.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/debug-macro.S
create mode 100644 arch/arm/mach-spmp8000/include/mach/entry-macro.S
create mode 100644 arch/arm/mach-spmp8000/include/mach/gpio.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/hardware.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/io.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/irqs.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/memory.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/system.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/timex.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/uncompress.h
create mode 100644 arch/arm/mach-spmp8000/include/mach/vmalloc.h
create mode 100644 arch/arm/mach-spmp8000/lluart.c
diff --git a/arch/arm/mach-spmp8000/Makefile b/arch/arm/mach-spmp8000/Makefile
new file mode 100644
index 0000000..15e0238
--- /dev/null
+++ b/arch/arm/mach-spmp8000/Makefile
@@ -0,0 +1,4 @@
+obj-y := core.o
+obj-y += clkdev.o
+obj-y += clock.o
+obj-$(CONFIG_DEBUG_LL) += lluart.o
diff --git a/arch/arm/mach-spmp8000/Makefile.boot b/arch/arm/mach-spmp8000/Makefile.boot
new file mode 100644
index 0000000..dae9661
--- /dev/null
+++ b/arch/arm/mach-spmp8000/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y := 0x00008000
diff --git a/arch/arm/mach-spmp8000/core.c b/arch/arm/mach-spmp8000/core.c
new file mode 100644
index 0000000..15a2111
--- /dev/null
+++ b/arch/arm/mach-spmp8000/core.c
@@ -0,0 +1,79 @@
+/*
+ * SPMP8000 machines core functions
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/hardware/vic.h>
+#include "core.h"
+
+void __iomem *spmp8000_wdt_base;
+EXPORT_SYMBOL(spmp8000_wdt_base);
+
+static void spmp8000_wdt_init(void)
+{
+ struct device_node *np;
+
+ np = of_find_compatible_node(NULL, NULL, "sunplus,spmp8000-wdt");
+ if (!np) {
+ pr_err("spmp8000: unable to find watchdog node in dtb\n");
+ return;
+ }
+
+ spmp8000_wdt_base = of_iomap(np, 0);
+ if (!spmp8000_wdt_base)
+ pr_err("spmp8000: unable to map watchdog registers\n");
+}
+
+static const struct of_device_id spmp8000_vic_matches[] = {
+ { .compatible = "arm,pl192", .data = vic_of_init },
+ { /* Sentinel */ },
+};
+
+void __init spmp8000_init_irq(void)
+{
+ of_irq_init(spmp8000_vic_matches);
+}
+
+static const char *letcool_dt_match[] __initconst = {
+ "gameware,letcool",
+ NULL,
+};
+
+static void __init letcool_dt_init(void)
+{
+ spmp8000_init_clkdev();
+
+ /* Create platform devices */
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ /* Setup WDT reg base to be used by the WDT driver and arch_reset */
+ spmp8000_wdt_init();
+}
+
+struct sys_timer spmp8000_sys_timer = {
+ .init = spmp8000_sys_timer_init,
+};
+
+DT_MACHINE_START(SPMP8000, "SPMP8000")
+ .map_io = spmp8000_map_lluart,
+ .init_irq = spmp8000_init_irq,
+ .handle_irq = vic_handle_irq,
+ .nr_irqs = SPMP8000_TOTAL_IRQS,
+ .init_machine = letcool_dt_init,
+ .timer = &spmp8000_sys_timer,
+ .dt_compat = letcool_dt_match,
+MACHINE_END
diff --git a/arch/arm/mach-spmp8000/core.h b/arch/arm/mach-spmp8000/core.h
new file mode 100644
index 0000000..1e84a49
--- /dev/null
+++ b/arch/arm/mach-spmp8000/core.h
@@ -0,0 +1,27 @@
+/*
+ * SPMP8000 generic includes
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_CORE_H__
+#define __MACH_SPMP8000_CORE_H__
+
+/* drivers/clksrc/spmp8000_tmrb.c */
+extern void spmp8000_sys_timer_init(void);
+
+/* clkdev.c */
+extern void spmp8000_init_clkdev(void);
+
+/* lluart.c */
+#ifdef CONFIG_DEBUG_LL
+extern void spmp8000_map_lluart(void);
+#else
+#define spmp8000_map_lluart NULL
+#endif
+
+#endif /* __MACH_SPMP8000_CORE_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/debug-macro.S b/arch/arm/mach-spmp8000/include/mach/debug-macro.S
new file mode 100644
index 0000000..698c37e
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/debug-macro.S
@@ -0,0 +1,19 @@
+/*
+ * SPMP8000 debug-macro.S
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+ .macro addruart, rp, rv
+ mov \rp, #0x92000000
+ add \rp, #0x00B00000
+ add \rp, #0x00004000
+ orr \rv, \rp, #0xF0000000
+ .endm
+
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
diff --git a/arch/arm/mach-spmp8000/include/mach/entry-macro.S b/arch/arm/mach-spmp8000/include/mach/entry-macro.S
new file mode 100644
index 0000000..3d26088
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/entry-macro.S
@@ -0,0 +1,14 @@
+/*
+ * SPMP8000 entry-macro.S
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+ .macro disable_fiq
+ .endm
+
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
diff --git a/arch/arm/mach-spmp8000/include/mach/gpio.h b/arch/arm/mach-spmp8000/include/mach/gpio.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/gpio.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/arch/arm/mach-spmp8000/include/mach/hardware.h b/arch/arm/mach-spmp8000/include/mach/hardware.h
new file mode 100644
index 0000000..bf65e47
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/hardware.h
@@ -0,0 +1,25 @@
+/*
+ * SPMP8000 hardware.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_HARDWARE_H__
+#define __MACH_SPMP8000_HARDWARE_H__
+
+/* Used by WDT driver and arch_reset */
+extern void *spmp8000_wdt_base;
+
+/* Physical to virtual translation of static mappings */
+#define SPMP8000_P2V(x) ((x) | 0xF0000000)
+#define IO_ADDRESS(x) ((void __iomem *)SPMP8000_P2V(x))
+
+/* Needed by lluart.c and uncompress.h */
+#define SPMP8000_UARTC0_BASE 0x92B04000
+#define SPMP8000_UARTC0_SIZE SZ_4K
+
+#endif /* __MACH_SPMP8000_HARDWARE_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/io.h b/arch/arm/mach-spmp8000/include/mach/io.h
new file mode 100644
index 0000000..464b78c
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/io.h
@@ -0,0 +1,17 @@
+/*
+ * SPMP8000 io.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_IO_H__
+#define __MACH_SPMP8000_IO_H__
+
+#define __mem_pci(a) (a)
+#define __io(a) NULL /* Only for 8250 UART driver */
+
+#endif /* __MACH_SPMP8000_IO_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/irqs.h b/arch/arm/mach-spmp8000/include/mach/irqs.h
new file mode 100644
index 0000000..7becde7
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/irqs.h
@@ -0,0 +1,21 @@
+/*
+ * SPMP8000 irqs.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_IRQS_H__
+#define __MACH_SPMP8000_IRQS_H__
+
+#define SPMP8000_HW_IRQS 64
+#define SPMP8000_GPIO_IRQS_START SPMP8000_HW_IRQS
+#define SPMP8000_GPIO_IRQS (16 + 32)
+#define SPMP8000_TOTAL_IRQS (SPMP8000_HW_IRQS + SPMP8000_GPIO_IRQS)
+
+#define NR_IRQS 0
+
+#endif /* __MACH_SPMP8000_IRQS_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/memory.h b/arch/arm/mach-spmp8000/include/mach/memory.h
new file mode 100644
index 0000000..40a8c17
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/memory.h
@@ -0,0 +1 @@
+/* empty */
diff --git a/arch/arm/mach-spmp8000/include/mach/system.h b/arch/arm/mach-spmp8000/include/mach/system.h
new file mode 100644
index 0000000..3c2ab5e
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/system.h
@@ -0,0 +1,43 @@
+/*
+ * SPMP8000 system.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_SYSTEM_H__
+#define __MACH_SPMP8000_SYSTEM_H__
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <mach/hardware.h>
+
+#define SPMP8000_WDT_CTR 0x00
+#define SPMP8000_WDT_CTR_TE BIT(0)
+#define SPMP8000_WDT_CTR_RE BIT(3)
+#define SPMP8000_WDT_VLR 0x0C
+
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+ if (!spmp8000_wdt_base) {
+ pr_err("spmp8000: arch_reset: Watchdog not initialized\n");
+ return;
+ }
+
+ /* Make sure WDT is enabled */
+ writel(SPMP8000_WDT_CTR_RE | SPMP8000_WDT_CTR_TE,
+ spmp8000_wdt_base + SPMP8000_WDT_CTR);
+
+ /* Force reset by writing invalid value to reload register */
+ writel(0, spmp8000_wdt_base + SPMP8000_WDT_VLR);
+}
+
+#endif /* __MACH_SPMP8000_SYSTEM_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/timex.h b/arch/arm/mach-spmp8000/include/mach/timex.h
new file mode 100644
index 0000000..795deff
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/timex.h
@@ -0,0 +1,17 @@
+/*
+ * SPMP8000 timex.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_TIMEX_H__
+#define __MACH_SPMP8000_TIMEX_H__
+
+/* TODO this should go away */
+#define CLOCK_TICK_RATE (50 * HZ)
+
+#endif /* __MACH_SPMP8000_TIMEX_H__ */
diff --git a/arch/arm/mach-spmp8000/include/mach/uncompress.h b/arch/arm/mach-spmp8000/include/mach/uncompress.h
new file mode 100644
index 0000000..105778b
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/uncompress.h
@@ -0,0 +1,37 @@
+/*
+ * SPMP8000 uncompress.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * Based on the mach-kirkwood implementation
+ *
+ * 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/serial_reg.h>
+#include <mach/hardware.h>
+
+#define SERIAL_BASE ((volatile unsigned char *)SPMP8000_UARTC0_BASE)
+
+static void putc(const char c)
+{
+ volatile unsigned char *base = SERIAL_BASE;
+ int i;
+
+ for (i = 0; i < 0x1000; i++) {
+ if (base[UART_LSR << 2] & UART_LSR_THRE)
+ break;
+ barrier();
+ }
+
+ base[UART_TX << 2] = c;
+}
+
+static void flush(void)
+{
+}
+
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
diff --git a/arch/arm/mach-spmp8000/include/mach/vmalloc.h b/arch/arm/mach-spmp8000/include/mach/vmalloc.h
new file mode 100644
index 0000000..ff40d1c
--- /dev/null
+++ b/arch/arm/mach-spmp8000/include/mach/vmalloc.h
@@ -0,0 +1,16 @@
+/*
+ * SPMP8000 vmalloc.h
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __MACH_SPMP8000_VMALLOC_H__
+#define __MACH_SPMP8000_VMALLOC_H__
+
+#define VMALLOC_END 0xF0000000UL
+
+#endif /* __MACH_SPMP8000_VMALLOC_H__ */
diff --git a/arch/arm/mach-spmp8000/lluart.c b/arch/arm/mach-spmp8000/lluart.c
new file mode 100644
index 0000000..4b90514
--- /dev/null
+++ b/arch/arm/mach-spmp8000/lluart.c
@@ -0,0 +1,24 @@
+/*
+ * Static memory mapping for DEBUG_LL
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <mach/hardware.h>
+
+void __init spmp8000_map_lluart(void)
+{
+ struct map_desc spmp8000_lluart_map = {
+ .virtual = SPMP8000_P2V(SPMP8000_UARTC0_BASE),
+ .pfn = __phys_to_pfn(SPMP8000_UARTC0_BASE),
+ .length = SPMP8000_UARTC0_SIZE,
+ .type = MT_DEVICE,
+ };
+
+ iotable_init(&spmp8000_lluart_map, 1);
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH v2 2/5] ARM: SPMP8000: Add clk support
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
2011-10-19 16:01 ` [PATCH v2 1/5] ARM: SPMP8000: Add machine base files Zoltan Devai
@ 2011-10-19 16:01 ` Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 3/5] ARM: SPMP8000: Add clocksource and clockevent drivers Zoltan Devai
` (2 subsequent siblings)
4 siblings, 0 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-19 16:01 UTC (permalink / raw)
To: linux-arm-kernel
Add support for the clk API
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/mach-spmp8000/clkdev.c | 611 +++++++++++++++++++++++++++++++++++++++
arch/arm/mach-spmp8000/clock.c | 149 ++++++++++
arch/arm/mach-spmp8000/clock.h | 32 ++
3 files changed, 792 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-spmp8000/clkdev.c
create mode 100644 arch/arm/mach-spmp8000/clock.c
create mode 100644 arch/arm/mach-spmp8000/clock.h
diff --git a/arch/arm/mach-spmp8000/clkdev.c b/arch/arm/mach-spmp8000/clkdev.c
new file mode 100644
index 0000000..470ce1a
--- /dev/null
+++ b/arch/arm/mach-spmp8000/clkdev.c
@@ -0,0 +1,611 @@
+/*
+ * SPMP8000 machines clock support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#include "clock.h"
+
+/* System Control Unit registers */
+#define SCU_A_PERI_CLKEN 0x04
+
+#define SCU_A_APLL_CFG 0x44
+#define APLL_CFG_P BIT(0)
+#define APLL_CFG_S BIT(1)
+#define APLL_CFG_F BIT(2)
+#define APLL_CFG_E BIT(3)
+#define APLL_CFG_AS_MASK 0x3F0
+#define APLL_CFG_AS_SHIFT 4
+#define APLL_CFG_AS_MAGIC 0x12
+#define APLL_CFG_C BIT(10)
+#define APLL_CFG_R BIT(11)
+#define APLL_CFG_DAR_SHIFT 16
+#define APLL_CFG_DAR_MASK (7 << APLL_CFG_DAR_SHIFT)
+#define APLL_CFG_DS BIT(19)
+#define APLL_CFG_ADR_SHIFT 24
+#define APLL_CFG_ADR_MASK (7 << APLL_CFG_ADR_SHIFT)
+#define APLL_CFG_AS BIT(27)
+
+#define SCU_A_LCD_CLK_CFG 0x80
+#define LCD_CLK_CFG_RATIO_MASK 0xFF
+#define LCD_CLK_CFG_EN BIT(8)
+#define SCU_A_CSI_CLK_CFG 0x84
+#define CSI_CLK_CFG_RATIO_MASK 0xFF
+#define CSI_CLK_CFG_EN BIT(8)
+#define SCU_A_I2S_BCK_CFG 0x90
+#define I2S_BCK_CFG_RATIO_MASK 0xFF
+#define I2S_BCK_CFG_EN BIT(8)
+#define SCU_A_UART_CFG 0x94
+#define UART_CFG_RATIO_MASK 0xFF
+#define UART_CFG_EN BIT(8)
+#define DIVIDER_ENABLE_BIT BIT(8)
+
+#define SCU_B_PERI_CLKEN 0x20
+#define SCU_B_UPDATE_ARM_RATIO 0x28
+
+#define SCU_B_SPLL_CFG 0x04
+#define SPLL_CFG_R_MASK 3
+#define SPLL_CFG_R_SHIFT 0
+#define SPLL_CFG_F_MASK 0xFC
+#define SPLL_CFG_F_SHIFT 2
+#define SPLL_CFG_BS BIT(8)
+#define SPLL_CFG_OD BIT(9)
+#define SPLL_CFG_BP BIT(10)
+#define SPLL_CFG_PD BIT(11)
+#define SPLL_CFG_CSEL_MASK (BIT(13) | BIT(12))
+#define SPLL_CFG_CSEL_SHIFT 12
+#define SPLL_CFG_ASEL_MASK (BIT(15) | BIT(14))
+#define SPLL_CFG_ASEL_SHIFT 14
+#define SPLL_CFG_SE BIT(17)
+#define SPLL_CFG_XE BIT(18)
+#define SPLL_CFG_AE BIT(19)
+#define SPLL_CFG_XR BIT(20)
+#define SPLL_CFG_PL BIT(31)
+
+#define SCU_B_ARM_RATIO 0xD0
+#define SCU_B_ARM_AHB_RATIO 0xD4
+#define SCU_B_ARM_APB_RATIO 0xD8
+#define SCU_B_SYS_CNT_EN 0xDC
+#define SYS_CNT_EN_SYS BIT(0)
+#define SYS_CNT_EN_SYS_RT BIT(1)
+#define SYS_CNT_EN_SYS_AHB BIT(2)
+#define SYS_CNT_EN_SYS_APB BIT(3)
+#define SYS_CNT_EN_SYS_CHECK BIT(31)
+
+#define SCU_C_PERI_CLKEN 0x04
+
+#define SCU_C_UPDATE_SYS_RATIO 0x28
+#define SCU_C_SYS_RATIO 0x100
+#define SCU_C_SYS_RT_RATIO 0x104
+#define SCU_C_SYS_AHB_RATIO 0x108
+#define SCU_C_SYS_APB_RATIO 0x10C
+#define SCU_C_CEVA_RATIO 0x110
+#define SCU_C_CEVA_AHB_RATIO 0x114
+#define SCU_C_CEVA_APB_RATIO 0x118
+#define SCU_C_CEVA_CNT_EN 0x11C
+#define CEVA_CNT_EN_CEVA BIT(0)
+#define CEVA_CNT_EN_CEVA_AHB BIT(1)
+#define CEVA_CNT_EN_CEVA_APB BIT(2)
+#define CEVA_CNT_EN_CEVA_CHECK BIT(31)
+
+/* The SoC doesn't support anything else, no need to make these machine
+ * configurable.
+ */
+#define XTAL_FREQ 27000000UL
+#define XTAL_32K_FREQ 32768UL
+#define APLL_48K_FREQ 73728000UL
+#define APLL_44K_FREQ 67737600UL
+
+static void __iomem *scu_a_base;
+static void __iomem *scu_b_base;
+static void __iomem *scu_c_base;
+
+static unsigned long spll_get_rate(struct clk *clk)
+{
+ unsigned int f, r, od;
+ unsigned long osc;
+ u32 cfg;
+
+ cfg = readl(scu_b_base + SCU_B_SPLL_CFG);
+ osc = XTAL_FREQ;
+
+ f = (cfg & SPLL_CFG_F_MASK) >> SPLL_CFG_F_SHIFT;
+ r = (cfg & SPLL_CFG_R_MASK) >> SPLL_CFG_R_SHIFT;
+ od = !!(cfg & SPLL_CFG_OD);
+ clk->rate = (osc * (f + 1) * 2) / ((r + 1) * (od + 1));
+
+ return clk->rate;
+}
+
+static unsigned long pll_mux_get_rate(int ratesel, struct clk *clk)
+{
+ int pll_rate;
+
+ switch (ratesel) {
+ case 0:
+ clk->rate = XTAL_FREQ;
+ break;
+ case 1:
+ clk->rate = XTAL_32K_FREQ;
+ break;
+ case 2:
+ pll_rate = clk_get_rate(clk->parent);
+ clk->rate = pll_rate / 2;
+ break;
+ case 3:
+ pll_rate = clk_get_rate(clk->parent);
+ clk->rate = pll_rate / 3;
+ break;
+ }
+
+ return clk->rate;
+}
+
+static unsigned long ref_arm_get_rate(struct clk *clk)
+{
+ int ratesel;
+ u32 spll_cfg;
+
+ spll_cfg = readl(scu_b_base + SCU_B_SPLL_CFG);
+ ratesel = (spll_cfg & SPLL_CFG_ASEL_MASK) >> SPLL_CFG_ASEL_SHIFT;
+ return pll_mux_get_rate(ratesel, clk);
+}
+
+static unsigned long ref_ceva_get_rate(struct clk *clk)
+{
+ int ratesel;
+ u32 spll_cfg;
+
+ spll_cfg = readl(scu_b_base + SCU_B_SPLL_CFG);
+ ratesel = (spll_cfg & SPLL_CFG_CSEL_MASK) >> SPLL_CFG_CSEL_SHIFT;
+ return pll_mux_get_rate(ratesel, clk);
+}
+
+static unsigned long apll_get_rate(void)
+{
+ u32 cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+
+ if ((cfg & APLL_CFG_R) || (~cfg & (APLL_CFG_P | APLL_CFG_E)) ||
+ (((cfg & APLL_CFG_AS_MASK) >> APLL_CFG_AS_SHIFT)
+ != APLL_CFG_AS_MAGIC)) {
+ return 0;
+ }
+
+ /* Not dealing with the input oscillator frequency as the settings
+ * for non-27Mhz are unknown, and all platforms use that anyway */
+ if (cfg & APLL_CFG_S)
+ return APLL_44K_FREQ;
+ else
+ return APLL_48K_FREQ;
+}
+
+static void apll_enable(struct clk *clk)
+{
+ u32 cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+
+ /* Store new config with reset, then disable reset */
+ cfg |= APLL_CFG_R;
+ cfg |= APLL_CFG_E | APLL_CFG_P | APLL_CFG_F;
+ cfg |= APLL_CFG_AS_MAGIC << APLL_CFG_AS_SHIFT;
+
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+
+ cfg &= ~APLL_CFG_R;
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+}
+
+static void apll_disable(struct clk *clk)
+{
+ u32 cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+
+ cfg &= ~APLL_CFG_P;
+ cfg |= APLL_CFG_E;
+
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+}
+
+static int apll_set_rate(unsigned long rate)
+{
+ u32 cfg;
+
+ cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+
+ switch (rate) {
+ case 67737600:
+ cfg |= APLL_CFG_S;
+ break;
+ case 73728000:
+ cfg &= ~APLL_CFG_S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+
+ return 0;
+}
+
+static void i2s_mck_switch(u32 mask, int enable)
+{
+ u32 cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+ if (enable)
+ cfg &= ~mask;
+ else
+ cfg |= mask;
+
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+}
+
+static void i2stx_mck_enable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_DS, 1);
+}
+
+static void i2stx_mck_disable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_DS, 0);
+}
+
+static void i2srx_mck_enable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_AS, 1);
+}
+
+static void i2srx_mck_disable(struct clk *clk)
+{
+ i2s_mck_switch(APLL_CFG_AS, 0);
+}
+
+static const int apll_dividers[7] = {
+ 3, 6, 9, 12, 18, 24, 32,
+};
+
+static unsigned long i2s_mck_get_rate(struct clk *clk, u32 msk, u32 sh)
+{
+ unsigned long apll_rate = apll_get_rate();
+ u32 cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+ int divider;
+
+ divider = (cfg & msk) >> sh;
+
+ if (divider == ARRAY_SIZE(apll_dividers))
+ return 0;
+
+ divider = apll_dividers[divider];
+
+ return apll_rate / divider;
+}
+
+static unsigned long i2stx_mck_get_rate(struct clk *clk)
+{
+ return i2s_mck_get_rate(clk, APLL_CFG_DAR_MASK, APLL_CFG_DAR_SHIFT);
+}
+
+static unsigned long i2srx_mck_get_rate(struct clk *clk)
+{
+ return i2s_mck_get_rate(clk, APLL_CFG_ADR_MASK, APLL_CFG_ADR_SHIFT);
+}
+
+static int i2s_mck_set_rate(struct clk *clk, unsigned long rate,
+ u32 msk, u32 sh)
+{
+ int i = ARRAY_SIZE(apll_dividers) - 1;
+ unsigned long apll_rate;
+ int divider = -1;
+ u32 cfg;
+
+ /* Set up APLL */
+ if (rate % 8000)
+ apll_rate = APLL_44K_FREQ;
+ else
+ apll_rate = APLL_48K_FREQ;
+
+ apll_set_rate(apll_rate);
+
+ cfg = readl(scu_a_base + SCU_A_APLL_CFG);
+
+ /* Get the biggest possible divider for MCK */
+ while (i >= 0) {
+ if (apll_rate / apll_dividers[i] == rate) {
+ divider = apll_dividers[i];
+ break;
+ }
+
+ i--;
+ }
+
+ if (divider < 0)
+ return -EINVAL;
+
+ cfg &= ~msk;
+ cfg |= (i << sh);
+
+ writel(cfg, scu_a_base + SCU_A_APLL_CFG);
+
+ return 0;
+}
+
+static int i2stx_mck_set_rate(struct clk *clk, unsigned long rate)
+{
+ return i2s_mck_set_rate(clk, rate,
+ APLL_CFG_DAR_MASK, APLL_CFG_DAR_SHIFT);
+}
+
+static int i2srx_mck_set_rate(struct clk *clk, unsigned long rate)
+{
+ return i2s_mck_set_rate(clk, rate,
+ APLL_CFG_ADR_MASK, APLL_CFG_ADR_SHIFT);
+}
+
+static void divider_set_clock(struct clk *clk, int on)
+{
+ u32 divider;
+
+ divider = readl(clk->scu_base + clk->scu_divreg);
+ if (on)
+ divider |= DIVIDER_ENABLE_BIT;
+ else
+ divider &= ~DIVIDER_ENABLE_BIT;
+ writel(divider, clk->scu_base + clk->scu_divreg);
+}
+
+static void divider_enable_clock(struct clk *clk)
+{
+ divider_set_clock(clk, 1);
+}
+
+static void divider_disable_clock(struct clk *clk)
+{
+ divider_set_clock(clk, 0);
+}
+
+static unsigned long divider_get_rate(struct clk *clk)
+{
+ u32 divider;
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+
+ if (!parent_rate) {
+ clk->rate = 0;
+ return clk->rate;
+ }
+
+ divider = readl(clk->scu_base + clk->scu_divreg);
+ clk->rate = parent_rate / ((divider & clk->divmask) + 1);
+
+ return clk->rate;
+}
+
+static int divider_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 divider, divider_old;
+ unsigned long parent_rate = clk_get_rate(clk->parent);
+
+ if (unlikely(!parent_rate || rate > parent_rate)) {
+ clk->rate = parent_rate;
+ pr_debug("spmp8000: clk: parent rate < requested rate\n");
+ return 0;
+ }
+
+ divider = (parent_rate / rate) - 1;
+
+ if (divider > clk->divmask) {
+ pr_debug("spmp8000: clk: input clock / requested > max div\n");
+ divider = clk->divmask;
+ }
+
+ divider_old = readl(clk->scu_base + clk->scu_divreg);
+
+ /* Order of writes is important: 0 -> divider value -> enable bit */
+ writel(0, clk->scu_base + clk->scu_divreg);
+ writel(divider, clk->scu_base + clk->scu_divreg);
+
+ /* Re-enable clock if it was enabled before */
+ if (divider_old & DIVIDER_ENABLE_BIT)
+ writel(divider | DIVIDER_ENABLE_BIT,
+ clk->scu_base + clk->scu_divreg);
+
+ clk->rate = parent_rate / (divider + 1);
+
+ return 0;
+}
+static void periph_enable_clock(struct clk *clk)
+{
+ u32 scu_reg = readl(clk->scu_base + clk->scu_clkreg);
+
+ scu_reg |= (1 << clk->clkreg_off);
+
+ writel(scu_reg, clk->scu_base + clk->scu_clkreg);
+}
+
+static void periph_disable_clock(struct clk *clk)
+{
+ u32 scu_reg = readl(clk->scu_base + clk->scu_clkreg);
+
+ scu_reg &= ~(1 << clk->clkreg_off);
+
+ writel(scu_reg, clk->scu_base + clk->scu_clkreg);
+}
+
+void spmp8000_update_arm_freqs(void)
+{
+ writel(7, scu_b_base + SCU_B_UPDATE_ARM_RATIO);
+}
+EXPORT_SYMBOL(spmp8000_update_arm_freqs);
+
+static struct clk clk_spll = {
+ .get_rate = spll_get_rate,
+};
+
+static struct clk clk_ref_arm = {
+ .parent = &clk_spll,
+ .get_rate = ref_arm_get_rate,
+};
+
+static struct clk clk_ref_ceva = {
+ .parent = &clk_spll,
+ .get_rate = ref_ceva_get_rate,
+};
+
+static struct clk clk_apll = {
+ .name = "clk_apll",
+ .enable = apll_enable,
+ .disable = apll_disable,
+};
+
+static struct clk clk_i2stx_mck = {
+ .name = "clk_i2stx_mck",
+ .parent = &clk_apll,
+ .enable = i2stx_mck_enable,
+ .disable = i2stx_mck_disable,
+ .get_rate = i2stx_mck_get_rate,
+ .set_rate = i2stx_mck_set_rate,
+};
+
+static struct clk clk_i2srx_mck = {
+ .name = "clk_i2srx_mck",
+ .parent = &clk_apll,
+ .enable = i2srx_mck_enable,
+ .disable = i2srx_mck_disable,
+ .get_rate = i2srx_mck_get_rate,
+ .set_rate = i2srx_mck_set_rate,
+};
+
+#define SYS_CLK_DIV(__name, __parent, __scu_base, __divreg) \
+static struct clk __name = { \
+ .name = #__name, \
+ .parent = __parent, \
+ .scu_base = __scu_base, \
+ .scu_divreg = __divreg, \
+ .divmask = 0x3F, \
+ .get_rate = ÷r_get_rate, \
+ .set_rate = ÷r_set_rate, \
+}
+
+SYS_CLK_DIV(clk_arm, &clk_ref_arm, &scu_b_base, SCU_B_ARM_RATIO);
+SYS_CLK_DIV(clk_arm_ahb, &clk_arm, &scu_b_base, SCU_B_ARM_AHB_RATIO);
+SYS_CLK_DIV(clk_arm_apb, &clk_arm_ahb, &scu_b_base, SCU_B_ARM_APB_RATIO);
+SYS_CLK_DIV(clk_ceva, &clk_ref_ceva, &scu_c_base, SCU_C_CEVA_RATIO);
+SYS_CLK_DIV(clk_ceva_ahb, &clk_ceva, &scu_c_base, SCU_C_CEVA_AHB_RATIO);
+SYS_CLK_DIV(clk_ceva_apb, &clk_ceva_ahb, &scu_c_base, SCU_C_CEVA_APB_RATIO);
+SYS_CLK_DIV(clk_sys, &clk_ref_ceva, &scu_c_base, SCU_C_SYS_RATIO);
+SYS_CLK_DIV(clk_sys_ahb, &clk_sys, &scu_c_base, SCU_C_SYS_AHB_RATIO);
+SYS_CLK_DIV(clk_sys_apb, &clk_sys_ahb, &scu_c_base, SCU_C_SYS_APB_RATIO);
+
+#define SYS_CLK_DIV_EN(__name, __parent, __scu_base, __divreg) \
+static struct clk __name = { \
+ .name = #__name, \
+ .parent = __parent, \
+ .scu_base = __scu_base, \
+ .scu_divreg = __divreg, \
+ .divmask = 0xFF, \
+ .enable = ÷r_enable_clock, \
+ .disable = ÷r_disable_clock, \
+ .get_rate = ÷r_get_rate, \
+ .set_rate = ÷r_set_rate, \
+}
+
+SYS_CLK_DIV_EN(clk_uart, &clk_ref_ceva, &scu_a_base, SCU_A_UART_CFG);
+SYS_CLK_DIV_EN(clk_lcd, &clk_ref_ceva, &scu_a_base, SCU_A_LCD_CLK_CFG);
+SYS_CLK_DIV_EN(clk_i2srx_bck, &clk_i2srx_mck, &scu_a_base, SCU_A_I2S_BCK_CFG);
+SYS_CLK_DIV_EN(clk_i2stx_bck, &clk_i2stx_mck, &scu_a_base, SCU_A_I2S_BCK_CFG);
+
+/* Peripherals */
+#define PERIPH_CLK(__name, __parent, __scu_base, __clkreg_off) \
+static struct clk __name = { \
+ .name = #__name, \
+ .parent = __parent, \
+ .scu_base = __scu_base, \
+ .clkreg_off = __clkreg_off, \
+ .enable = periph_enable_clock, \
+ .disable = periph_disable_clock, \
+}
+
+PERIPH_CLK(clk_rt_abt, &clk_sys, &scu_a_base, 21);
+/* Make the parent rt_abt to auto-enable it when enabling the lcdc clock */
+PERIPH_CLK(clk_lcd_ctrl, &clk_rt_abt, &scu_a_base, 1);
+PERIPH_CLK(clk_apbdma_a, &clk_rt_abt, &scu_a_base, 9);
+PERIPH_CLK(clk_apll_ctrl, &clk_sys_ahb, &scu_a_base, 14);
+PERIPH_CLK(clk_i2stx_ctrl, &clk_apbdma_a, &scu_a_base, 17);
+PERIPH_CLK(clk_i2srx_ctrl, &clk_apbdma_a, &scu_a_base, 18);
+PERIPH_CLK(clk_saacc, &clk_sys_apb, &scu_a_base, 19);
+
+PERIPH_CLK(clk_tmrb, &clk_arm_apb, &scu_b_base, 9);
+PERIPH_CLK(clk_apbdma_c, &clk_sys_apb, &scu_c_base, 7);
+PERIPH_CLK(clk_sd0, &clk_sys_apb, &scu_c_base, 18);
+
+static struct clk_lookup lookups[] = {
+ CLKDEV_INIT(NULL, "arm", &clk_arm),
+ CLKDEV_INIT(NULL, "arm_ahb", &clk_arm_ahb),
+ CLKDEV_INIT(NULL, "arm_apb", &clk_arm_apb),
+ CLKDEV_INIT(NULL, "ceva", &clk_ceva),
+ CLKDEV_INIT(NULL, "ceva_ahb", &clk_ceva_ahb),
+ CLKDEV_INIT(NULL, "ceva_apb", &clk_ceva_apb),
+ CLKDEV_INIT(NULL, "sys", &clk_sys),
+ CLKDEV_INIT(NULL, "sys_ahb", &clk_sys_ahb),
+ CLKDEV_INIT(NULL, "sys_apb", &clk_sys_apb),
+ CLKDEV_INIT(NULL, "lcd", &clk_lcd),
+ CLKDEV_INIT(NULL, "apbdma_a", &clk_apbdma_a),
+ CLKDEV_INIT(NULL, "saacc", &clk_saacc),
+ CLKDEV_INIT(NULL, "i2stx_mck", &clk_i2stx_mck),
+ CLKDEV_INIT(NULL, "i2srx_mck", &clk_i2srx_mck),
+ CLKDEV_INIT(NULL, "i2stx_bck", &clk_i2stx_bck),
+ CLKDEV_INIT(NULL, "i2srx_bck", &clk_i2srx_bck),
+ CLKDEV_INIT("uart.0", NULL, &clk_uart),
+ CLKDEV_INIT("uart.1", NULL, &clk_uart),
+ CLKDEV_INIT("uart.2", NULL, &clk_uart),
+ CLKDEV_INIT("93000000.fb", NULL, &clk_lcd_ctrl),
+ CLKDEV_INIT("90000000.pwm", NULL, &clk_tmrb),
+ CLKDEV_INIT("92b00000.dma", NULL, &clk_apbdma_c),
+ CLKDEV_INIT("92b0b000.mmc", NULL, &clk_sd0),
+ CLKDEV_INIT("93010000.dma", NULL, &clk_apbdma_a),
+ CLKDEV_INIT("93012000.i2s", NULL, &clk_i2stx_ctrl),
+ CLKDEV_INIT("9301d000.i2s", NULL, &clk_i2srx_ctrl),
+};
+
+void __init *spmp8000_map_scu(const char *compatible)
+{
+ struct device_node *np;
+ void __iomem *addr;
+
+ np = of_find_compatible_node(NULL, NULL, compatible);
+ if (!np)
+ panic("spmp8000: unable to find %s node in dtb\n",
+ compatible);
+
+ addr = of_iomap(np, 0);
+ if (!addr)
+ panic("spmp8000: unable to map %s registers\n",
+ compatible);
+
+ return addr;
+}
+
+void __init spmp8000_init_clkdev(void)
+{
+ scu_a_base = spmp8000_map_scu("sunplus,spmp8000-scua");
+ scu_b_base = spmp8000_map_scu("sunplus,spmp8000-scub");
+ scu_c_base = spmp8000_map_scu("sunplus,spmp8000-scuc");
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ /* Enable the apll control registers here, as the according clock
+ * isn't exported, but used by the mck/bck clocks. If we wouldn't
+ * enable it here, the freq of the pll couldn't be set up before
+ * enabling one of its child clocks.
+ * The PLL clock itself will be auto-enabled on demand by them.
+ */
+ clk_enable(&clk_apll_ctrl);
+}
diff --git a/arch/arm/mach-spmp8000/clock.c b/arch/arm/mach-spmp8000/clock.c
new file mode 100644
index 0000000..d3b95ec
--- /dev/null
+++ b/arch/arm/mach-spmp8000/clock.c
@@ -0,0 +1,149 @@
+/*
+ * Usual clk API boilerplate
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#include "clock.h"
+
+static DEFINE_MUTEX(clocks_mutex);
+
+static void __clk_disable(struct clk *clk)
+{
+ BUG_ON(clk->refcount == 0);
+
+ if (!(--clk->refcount)) {
+ if (clk->disable)
+ clk->disable(clk);
+ if (clk->parent)
+ __clk_disable(clk->parent);
+ }
+}
+
+static int __clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (clk->refcount++ == 0) {
+ if (clk->parent)
+ ret = __clk_enable(clk->parent);
+ if (ret)
+ return ret;
+ else if (clk->enable)
+ clk->enable(clk);
+ }
+
+ return 0;
+}
+
+int clk_enable(struct clk *clk)
+{
+ int ret = 0;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return -EINVAL;
+
+ mutex_lock(&clocks_mutex);
+ ret = __clk_enable(clk);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return;
+
+ mutex_lock(&clocks_mutex);
+ __clk_disable(clk);
+ mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL_GPL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return 0UL;
+
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
+ return clk_get_rate(clk->parent);
+}
+EXPORT_SYMBOL_GPL(clk_get_rate);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return 0;
+ if (unlikely(!clk->round_rate))
+ return 0;
+
+ return clk->round_rate(clk, rate);
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ int ret = -EINVAL;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return ret;
+
+ if (unlikely(!clk->set_rate || !rate))
+ return ret;
+
+ mutex_lock(&clocks_mutex);
+ ret = clk->set_rate(clk, rate);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk *old;
+ int ret = -EINVAL;
+
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return ret;
+ if (unlikely(!clk->set_parent || !parent))
+ return ret;
+
+ mutex_lock(&clocks_mutex);
+ old = clk->parent;
+ if (clk->refcount)
+ __clk_enable(parent);
+ ret = clk->set_parent(clk, parent);
+ if (ret)
+ old = parent;
+ if (clk->refcount)
+ __clk_disable(old);
+ mutex_unlock(&clocks_mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ if (unlikely(IS_ERR_OR_NULL(clk)))
+ return NULL;
+
+ return clk->parent;
+}
+EXPORT_SYMBOL_GPL(clk_get_parent);
diff --git a/arch/arm/mach-spmp8000/clock.h b/arch/arm/mach-spmp8000/clock.h
new file mode 100644
index 0000000..d20759a
--- /dev/null
+++ b/arch/arm/mach-spmp8000/clock.h
@@ -0,0 +1,32 @@
+/*
+ * SPMP8000 machines clock support
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#ifndef __MACH_SPMP8000_CLOCK_H__
+#define __MACH_SPMP8000_CLOCK_H__
+
+struct clk {
+ char *name;
+ unsigned long rate;
+ unsigned int id;
+ unsigned int refcount;
+ void __iomem *scu_base;
+ int scu_clkreg;
+ unsigned int clkreg_off;
+ int scu_divreg;
+ int divmask;
+ struct clk *parent;
+ unsigned long (*get_rate)(struct clk *clk);
+ unsigned long (*round_rate) (struct clk *, u32);
+ int (*set_rate) (struct clk *, unsigned long);
+ int (*set_parent) (struct clk *clk, struct clk *parent);
+ void (*enable) (struct clk *);
+ void (*disable) (struct clk *);
+};
+
+#endif /* __MACH_SPMP8000_CLOCK_H__ */
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH v2 3/5] ARM: SPMP8000: Add clocksource and clockevent drivers
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
2011-10-19 16:01 ` [PATCH v2 1/5] ARM: SPMP8000: Add machine base files Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 2/5] ARM: SPMP8000: Add clk support Zoltan Devai
@ 2011-10-19 16:01 ` Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 5/5] ARM: SPMP8000: Add Kconfig and Makefile entries Zoltan Devai
4 siblings, 0 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-19 16:01 UTC (permalink / raw)
To: linux-arm-kernel
This adds a clocksource and clockevent for the SPMP8000 machine.
Cc: John Stultz <johnstul@us.ibm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
drivers/clocksource/Makefile | 3 +-
drivers/clocksource/spmp8000_tmrb.c | 159 +++++++++++++++++++++++++++++++++++
2 files changed, 161 insertions(+), 1 deletions(-)
create mode 100644 drivers/clocksource/spmp8000_tmrb.c
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 8d81a1d..adb575e 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
-obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
\ No newline at end of file
+obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
+obj-$(CONFIG_ARCH_SPMP8000) += spmp8000_tmrb.o
diff --git a/drivers/clocksource/spmp8000_tmrb.c b/drivers/clocksource/spmp8000_tmrb.c
new file mode 100644
index 0000000..8c0f042
--- /dev/null
+++ b/drivers/clocksource/spmp8000_tmrb.c
@@ -0,0 +1,159 @@
+/*
+ * SPMP8000 machines timer functions
+ *
+ * Copyright (C) 2011 Zoltan Devai <zoss@devai.org>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <asm/mach/time.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+/* Timer constraints:
+ * - WDT: Can't clear the irq directly, only by resetting the whole counter
+ * in the ISR, which means that IRQs will jitter
+ * - Timer_B: Can't reset the timer value, so at start, the first IRQ
+ * will happen at some random time.
+ */
+#define SPMP8000_TMRB(tnum) (tnum * 0x20)
+#define SPMP8000_TMRB_CTR 0x00
+#define SPMP8000_TMRB_CTR_TE BIT(0)
+#define SPMP8000_TMRB_CTR_IE BIT(1)
+#define SPMP8000_TMRB_CTR_OE BIT(2)
+#define SPMP8000_TMRB_CTR_PWMON BIT(3)
+#define SPMP8000_TMRB_CTR_UD BIT(4)
+#define SPMP8000_TMRB_CTR_UDS BIT(5)
+#define SPMP8000_TMRB_CTR_OM BIT(6)
+#define SPMP8000_TMRB_CTR_ES_SH 8
+#define SPMP8000_TMRB_CTR_M_SH 10
+#define SPMP8000_TMRB_PSR 0x04
+#define SPMP8000_TMRB_LDR 0x08
+#define SPMP8000_TMRB_VLR 0x08
+#define SPMP8000_TMRB_ISR 0x0C
+#define SPMP8000_TMRB_CMP 0x10
+
+static unsigned long clkrate;
+static const unsigned int tickrate = 1012500;
+
+#define CS_TIMER 2
+#define CE_TIMER 1
+static void __iomem *cs_base;
+static void __iomem *ce_base;
+
+static void tmrb_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *dev)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ writel((tickrate / HZ), ce_base + SPMP8000_TMRB_LDR);
+ /* Configure as periodic, down counter, IEN, enable timer */
+ writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_IE |
+ (1 << SPMP8000_TMRB_CTR_M_SH),
+ ce_base + SPMP8000_TMRB_CTR);
+ break;
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_UNUSED:
+ /* Disable timer */
+ writel(0, ce_base + SPMP8000_TMRB_CTR);
+ break;
+ default:
+ BUG();
+ break;
+ }
+}
+
+static struct clock_event_device tmrb1_clkevt = {
+ .name = "tmrb1",
+ .features = CLOCK_EVT_FEAT_PERIODIC,
+ .rating = 200,
+ .set_mode = tmrb_set_mode,
+};
+
+static irqreturn_t tmrb1_isr(int irq, void *dev_id)
+{
+ tmrb1_clkevt.event_handler(&tmrb1_clkevt);
+
+ /* Clear IRQ */
+ writel(0, ce_base + SPMP8000_TMRB_ISR);
+
+ return IRQ_HANDLED;
+};
+
+static struct irqaction tmrb1_irq = {
+ .name = "tmrb1_irq",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = tmrb1_isr,
+};
+
+void __init spmp8000_sys_timer_init(void)
+{
+ struct device_node *np;
+ unsigned int irq;
+ void *tmrb_base;
+ const __be32 *prop;
+
+ np = of_find_compatible_node(NULL, NULL, "sunplus,spmp8000-timer");
+ if (!np)
+ panic("spmp8000: unable to find timer node in dtb\n");
+
+ tmrb_base = of_iomap(np, 0);
+ if (!tmrb_base)
+ panic("spmp8000: unable to map timer cpu registers\n");
+
+ irq = of_irq_to_resource(np, CE_TIMER, NULL);
+ if (irq == NO_IRQ)
+ panic("spmp8000: unable to get interrupts of timer\n");
+
+ prop = of_get_property(np, "clock-freq", NULL);
+ if (!prop)
+ panic("spmp8000: Can't get boot clock rate of timer\n");
+ clkrate = be32_to_cpup(prop);
+
+ of_node_put(np);
+
+ cs_base = tmrb_base + SPMP8000_TMRB(CS_TIMER);
+ ce_base = tmrb_base + SPMP8000_TMRB(CE_TIMER);
+
+ /* Clocksource */
+ /* Disable timer */
+ writel(0, cs_base + SPMP8000_TMRB_CTR);
+
+ /* Reset counter value
+ * Not really possible unless setting end-1 LDR value and waiting
+ * until the counter reaches that */
+
+ /* Prescale timer */
+ writel((clkrate / tickrate) - 1, cs_base + SPMP8000_TMRB_PSR);
+
+ /* Register the clocksource */
+ clocksource_mmio_init(cs_base + SPMP8000_TMRB_VLR, "tmrb2",
+ tickrate, 200, 16, clocksource_mmio_readl_up);
+
+ /* Configure as free running (0 - 0xFFFF), up counter, enable timer */
+ writel(SPMP8000_TMRB_CTR_TE | SPMP8000_TMRB_CTR_UD,
+ cs_base + SPMP8000_TMRB_CTR);
+
+ /* Clockevent */
+ setup_irq(irq, &tmrb1_irq);
+
+ /* Disable timer */
+ writel(0, ce_base + SPMP8000_TMRB_CTR);
+
+ /* Prescale timer */
+ writel((clkrate / tickrate) - 1, ce_base + SPMP8000_TMRB_PSR);
+
+ clockevents_register_device(&tmrb1_clkevt);
+}
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
` (2 preceding siblings ...)
2011-10-19 16:01 ` [PATCH v2 3/5] ARM: SPMP8000: Add clocksource and clockevent drivers Zoltan Devai
@ 2011-10-19 16:01 ` Zoltan Devai
2011-10-24 12:47 ` Rob Herring
2011-10-19 16:01 ` [PATCH v2 5/5] ARM: SPMP8000: Add Kconfig and Makefile entries Zoltan Devai
4 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-19 16:01 UTC (permalink / raw)
To: linux-arm-kernel
This adds the DT description of the SPMP8000 SoC, the Letcool
N350JP board and documentation of required bindings
Cc: Grant Likely <grant.likely@secretlab.ca>
CC: devicetree-discuss at lists.ozlabs.org
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
Documentation/devicetree/bindings/arm/spmp8000.txt | 25 +++++
arch/arm/boot/dts/spmp8000-letcool.dts | 20 ++++
arch/arm/boot/dts/spmp8000.dtsi | 93 ++++++++++++++++++++
3 files changed, 138 insertions(+), 0 deletions(-)
create mode 100644 Documentation/devicetree/bindings/arm/spmp8000.txt
create mode 100644 arch/arm/boot/dts/spmp8000-letcool.dts
create mode 100644 arch/arm/boot/dts/spmp8000.dtsi
diff --git a/Documentation/devicetree/bindings/arm/spmp8000.txt b/Documentation/devicetree/bindings/arm/spmp8000.txt
new file mode 100644
index 0000000..c392b09
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/spmp8000.txt
@@ -0,0 +1,25 @@
+Sunplus SPMP8000 device tree bindings
+=====================================
+
+Required root node properties:
+ - compatible:
+ - "gameware,letcool" : Letcool N350JO handheld game console board
+ - "sunplus,spmp8000" : A board based on the SPMP8000 SoC
+
+Timer required properties:
+ - compatible = "sunplus,spmp8000-timer"
+ - interrupt-parent : The interrupt controller node this timer belongs to
+ - interrupts : IRQs of the timer
+ - clock-freq : The frequency in HZ of the timer.
+ - reg : The register bank for the timer.
+
+Watchdog required properties:
+ - compatible = "sunplus,spmp8000-watchdof"
+ - interrupt-parent : The interrupt controller node this timer belongs to
+ - interrupts : IRQs of the watchdog
+ - reg : The register bank for the watchdog controller
+
+SCU required properties:
+ - compatible: "sunplus,spmp8000-scua" or "sunplus,spmp8000-scuab" or
+ "sunplus,spmp8000-scuc"
+ - reg: The register bank of the System Control Unit
diff --git a/arch/arm/boot/dts/spmp8000-letcool.dts b/arch/arm/boot/dts/spmp8000-letcool.dts
new file mode 100644
index 0000000..424f2aa
--- /dev/null
+++ b/arch/arm/boot/dts/spmp8000-letcool.dts
@@ -0,0 +1,20 @@
+/dts-v1/;
+/include/ "spmp8000.dtsi"
+/ {
+ model = "Letcool N350JP handheld game console";
+ compatible = "gameware,letcool", "sunplus,spmp8000";
+
+ memory {
+ reg = <0x00000000 0x02000000>;
+ };
+
+ chosen {
+ linux,stdout-path = &uart0;
+ };
+
+ armapb {
+ timer at 90000000 {
+ clock-freq = <15187500>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/spmp8000.dtsi b/arch/arm/boot/dts/spmp8000.dtsi
new file mode 100644
index 0000000..15b25fa
--- /dev/null
+++ b/arch/arm/boot/dts/spmp8000.dtsi
@@ -0,0 +1,93 @@
+/ {
+ compatible = "sunplus,spmp8000";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ armapb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x90000000 0x10000>;
+
+ timer at 90000000 {
+ compatible = "sunplus,spmp8000-timer";
+ reg = <0x0 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <7 8 9>;
+ };
+
+ watchdog at 90001000 {
+ compatible = "sunplus,spmp8000-wdt";
+ reg = <0x1000 0x1000>;
+ interrupt-parent = <&vic0>;
+ interrupts = <10 11 12>;
+ };
+
+ scu-b at 90005000 {
+ compatible = "sunplus,spmp8000-scub";
+ reg = <0x5000 0x1000>;
+ };
+ };
+
+ armahb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x90010000 0x20000>;
+
+ vic0: interrupt-controller at 90010000 {
+ compatible = "arm,pl192";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x0 0x1000>;
+ };
+
+ vic1: interrupt-controller at 900020000 {
+ compatible = "arm,pl192";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ reg = <0x10000 0x1000>;
+ };
+ };
+
+ plat {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x92000000 0x1000000>;
+
+ scu-c at 92005000 {
+ compatible = "sunplus,spmp8000-scuc";
+ reg = <0x5000 0x1000>;
+ };
+
+ plat-apb {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xB00000 0x10000>;
+
+ uart0: uart-c0 at 92B04000 {
+ compatible = "ns16550a";
+ reg = <0x4000 0x1000>;
+ clock-frequency = <2076923>;
+ interrupt-parent = <&vic1>;
+ interrupts = <24>;
+ current-speed = <115200>;
+ reg-shift = <2>;
+ };
+ };
+ };
+
+ axi {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x93000000 0x20000>;
+
+ scu-a at 93007000 {
+ compatible = "sunplus,spmp8000-scua";
+ reg = <0x7000 0x1000>;
+ };
+ };
+};
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH v2 5/5] ARM: SPMP8000: Add Kconfig and Makefile entries
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
` (3 preceding siblings ...)
2011-10-19 16:01 ` [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions Zoltan Devai
@ 2011-10-19 16:01 ` Zoltan Devai
4 siblings, 0 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-19 16:01 UTC (permalink / raw)
To: linux-arm-kernel
This adds the necessary Kconfig and Makefile entries to build
the SPMP8000 machine
Signed-off-by: Zoltan Devai <zoss@devai.org>
---
arch/arm/Kconfig | 16 ++++++++++++++++
arch/arm/Makefile | 1 +
2 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9426e26..bfd8317 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -831,6 +831,22 @@ config ARCH_SHARK
Support for the StrongARM based Digital DNARD machine, also known
as "Shark" (<http://www.shark-linux.de/shark.html>).
+config ARCH_SPMP8000
+ bool "Sunplus SPMP8000"
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select ARM_PATCH_PHYS_VIRT
+ select ARM_VIC
+ select CLKDEV_LOOKUP
+ select CLKSRC_MMIO
+ select CPU_ARM926T
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_IRQ_CHIP
+ select MULTI_IRQ_HANDLER
+ select NO_IOPORT
+ select USE_OF
+ help
+ Support for Sunplus SPMP8000A/8010A/8016A SoC.
+
config ARCH_TCC_926
bool "Telechips TCC ARM926-based systems"
select CLKSRC_MMIO
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index e0ac6eb..f837a3b 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -180,6 +180,7 @@ machine-$(CONFIG_ARCH_EXYNOS4) := exynos4
machine-$(CONFIG_ARCH_SA1100) := sa1100
machine-$(CONFIG_ARCH_SHARK) := shark
machine-$(CONFIG_ARCH_SHMOBILE) := shmobile
+machine-$(CONFIG_ARCH_SPMP8000) := spmp8000
machine-$(CONFIG_ARCH_TCC8K) := tcc8k
machine-$(CONFIG_ARCH_TEGRA) := tegra
machine-$(CONFIG_ARCH_U300) := u300
--
1.7.4.1
^ permalink raw reply related [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-19 16:01 ` [PATCH v2 1/5] ARM: SPMP8000: Add machine base files Zoltan Devai
@ 2011-10-19 19:15 ` Arnd Bergmann
2011-10-21 22:54 ` Russell King - ARM Linux
2011-10-23 21:37 ` Zoltan Devai
0 siblings, 2 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-19 19:15 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 19 October 2011 18:01:54 Zoltan Devai wrote:
> Files needed for the basic machine support of SPMP8000
>
> Signed-off-by: Zoltan Devai <zoss@devai.org>
Hi Zoltan,
This version looks very nice, only a few small things remain that I noticed
reading through it again:
> +
> +void __iomem *spmp8000_wdt_base;
> +EXPORT_SYMBOL(spmp8000_wdt_base);
This should really be EXPORT_SYMBOL_GPL.
> +#define SERIAL_BASE ((volatile unsigned char *)SPMP8000_UARTC0_BASE)
drop this, then
> +static void putc(const char c)
> +{
> + volatile unsigned char *base = SERIAL_BASE;
make this a "unsigned char __iomem *".
> + int i;
> +
> + for (i = 0; i < 0x1000; i++) {
> + if (base[UART_LSR << 2] & UART_LSR_THRE)
> + break;
> + barrier();
> + }
> +
> + base[UART_TX << 2] = c;
> +}
and use readb_relaxed/writeb_relaxed to do the access. You should
never just dereference volatile pointers to do an MMIO access.
Best check your code by running 'sparse' over it (make C=1). It will warn
about things like this. Try to fix all warnings that sparse reports.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-19 19:15 ` Arnd Bergmann
@ 2011-10-21 22:54 ` Russell King - ARM Linux
2011-10-23 21:47 ` Zoltan Devai
2011-10-23 21:37 ` Zoltan Devai
1 sibling, 1 reply; 78+ messages in thread
From: Russell King - ARM Linux @ 2011-10-21 22:54 UTC (permalink / raw)
To: linux-arm-kernel
On Wed, Oct 19, 2011 at 09:15:35PM +0200, Arnd Bergmann wrote:
> > +#define SERIAL_BASE ((volatile unsigned char *)SPMP8000_UARTC0_BASE)
>
> drop this, then
>
> > +static void putc(const char c)
> > +{
> > + volatile unsigned char *base = SERIAL_BASE;
>
> make this a "unsigned char __iomem *".
>
> > + int i;
> > +
> > + for (i = 0; i < 0x1000; i++) {
> > + if (base[UART_LSR << 2] & UART_LSR_THRE)
> > + break;
> > + barrier();
> > + }
> > +
> > + base[UART_TX << 2] = c;
> > +}
>
> and use readb_relaxed/writeb_relaxed to do the access. You should
> never just dereference volatile pointers to do an MMIO access.
Note that uncompress.h isn't part of the kernel proper, and so the
MMIO accessors may not work (depends whether the arch out-of-lines
them.) Moreover, as the MMU is setup with 1:1 mappings, arguably
it's not IOMEM anyway.
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-19 19:15 ` Arnd Bergmann
2011-10-21 22:54 ` Russell King - ARM Linux
@ 2011-10-23 21:37 ` Zoltan Devai
2011-10-24 9:13 ` Arnd Bergmann
1 sibling, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-10-23 21:37 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/19 Arnd Bergmann <arnd@arndb.de>:
> On Wednesday 19 October 2011 18:01:54 Zoltan Devai wrote:
>> Files needed for the basic machine support of SPMP8000
>>
>> Signed-off-by: Zoltan Devai <zoss@devai.org>
>
> Hi Zoltan,
>
> This version looks very nice, only a few small things remain that I noticed
> reading through it again:
OK, will correct these.
What's next then ?
I assume I'd need some more review on at least the dts file.
Also, can the timer code go through your tree into drivers/clocksource ?
Thanks,
Zoltan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-21 22:54 ` Russell King - ARM Linux
@ 2011-10-23 21:47 ` Zoltan Devai
0 siblings, 0 replies; 78+ messages in thread
From: Zoltan Devai @ 2011-10-23 21:47 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/22 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Wed, Oct 19, 2011 at 09:15:35PM +0200, Arnd Bergmann wrote:
>> > +#define SERIAL_BASE ? ? ? ?((volatile unsigned char *)SPMP8000_UARTC0_BASE)
>>
>> drop this, then
>>
>> > +static void putc(const char c)
>> > +{
>> > + ? volatile unsigned char *base = SERIAL_BASE;
>>
>> make this a "unsigned char __iomem *".
>>
>> > + ? int i;
>> > +
>> > + ? for (i = 0; i < 0x1000; i++) {
>> > + ? ? ? ? ? if (base[UART_LSR << 2] & UART_LSR_THRE)
>> > + ? ? ? ? ? ? ? ? ? break;
>> > + ? ? ? ? ? barrier();
>> > + ? }
>> > +
>> > + ? base[UART_TX << 2] = c;
>> > +}
>>
>> and use readb_relaxed/writeb_relaxed to do the access. You should
>> never just dereference volatile pointers to do an MMIO access.
>
> Note that uncompress.h isn't part of the kernel proper, and so the
> MMIO accessors may not work (depends whether the arch out-of-lines
> them.) ?Moreover, as the MMU is setup with 1:1 mappings, arguably
> it's not IOMEM anyway.
What's the preferred method then ?
The current uncompress.h files use all possible methods.
This is certainly also a question for the uncompress.h cleanup series.
Z
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-23 21:37 ` Zoltan Devai
@ 2011-10-24 9:13 ` Arnd Bergmann
2011-10-24 11:00 ` Jamie Iles
0 siblings, 1 reply; 78+ messages in thread
From: Arnd Bergmann @ 2011-10-24 9:13 UTC (permalink / raw)
To: linux-arm-kernel
On Sunday 23 October 2011, Zoltan Devai wrote:
> 2011/10/19 Arnd Bergmann <arnd@arndb.de>:
> > On Wednesday 19 October 2011 18:01:54 Zoltan Devai wrote:
> >> Files needed for the basic machine support of SPMP8000
> >>
> >> Signed-off-by: Zoltan Devai <zoss@devai.org>
> >
> > Hi Zoltan,
> >
> > This version looks very nice, only a few small things remain that I noticed
> > reading through it again:
> OK, will correct these.
>
> What's next then ?
We talked about it at the ARM subarchitecture maintainer summit, and I think
I'll just merge your platform code for 3.2 if you send the fixed version
in time. I'm not going to merge your clk support patch (2/5) though, since
there is a lot of work going into the common clk framework right now, and
I don't want to cause more work going into rewriting your code.
Please instead replace that patch with a stubbed-out version that builds
but doesn't actually do anything. Obviously you won't be able to run on
actual hardware then but you still have the patch you did and know how to
apply it for testing ;-).
> I assume I'd need some more review on at least the dts file.
It seems all good to me, but I would definitely appreciate Grant and Rob
to take a closer look.
> Also, can the timer code go through your tree into drivers/clocksource ?
It can, but it needs an Acked-by from John and/or Thomas in that case.
Alternatively, feel free to stick my acked-by on the patch and have
Thomas handle the patch.
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-24 9:13 ` Arnd Bergmann
@ 2011-10-24 11:00 ` Jamie Iles
2011-11-02 13:29 ` Zoltan Devai
0 siblings, 1 reply; 78+ messages in thread
From: Jamie Iles @ 2011-10-24 11:00 UTC (permalink / raw)
To: linux-arm-kernel
Hi Arnd,
On Mon, Oct 24, 2011 at 11:13:21AM +0200, Arnd Bergmann wrote:
> On Sunday 23 October 2011, Zoltan Devai wrote:
> > 2011/10/19 Arnd Bergmann <arnd@arndb.de>:
> > > On Wednesday 19 October 2011 18:01:54 Zoltan Devai wrote:
> > >> Files needed for the basic machine support of SPMP8000
> > >>
> > >> Signed-off-by: Zoltan Devai <zoss@devai.org>
> > >
> > > Hi Zoltan,
> > >
> > > This version looks very nice, only a few small things remain that I noticed
> > > reading through it again:
> > OK, will correct these.
> >
> > What's next then ?
>
> We talked about it at the ARM subarchitecture maintainer summit, and I think
> I'll just merge your platform code for 3.2 if you send the fixed version
> in time. I'm not going to merge your clk support patch (2/5) though, since
Zoltan uses my device tree bindings and multi IRQ handler for the VIC
which hasn't yet been merged (and I haven't had any
Tested-by/Acked-by's) from anyone other than Zoltan yet.
I suppose the device tree binding and multi IRQ handler patches /could/
go in without the other platform conversions though they haven't had any
time in -next.
Jamie
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions
2011-10-19 16:01 ` [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions Zoltan Devai
@ 2011-10-24 12:47 ` Rob Herring
0 siblings, 0 replies; 78+ messages in thread
From: Rob Herring @ 2011-10-24 12:47 UTC (permalink / raw)
To: linux-arm-kernel
On 10/19/2011 11:01 AM, Zoltan Devai wrote:
> This adds the DT description of the SPMP8000 SoC, the Letcool
> N350JP board and documentation of required bindings
>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> CC: devicetree-discuss at lists.ozlabs.org
> Signed-off-by: Zoltan Devai <zoss@devai.org>
> ---
Only a couple of minor things below. Otherwise looks good.
Acked-by: Rob Herring <rob.herring@calxeda.com>
> Documentation/devicetree/bindings/arm/spmp8000.txt | 25 +++++
> arch/arm/boot/dts/spmp8000-letcool.dts | 20 ++++
> arch/arm/boot/dts/spmp8000.dtsi | 93 ++++++++++++++++++++
> 3 files changed, 138 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/arm/spmp8000.txt
> create mode 100644 arch/arm/boot/dts/spmp8000-letcool.dts
> create mode 100644 arch/arm/boot/dts/spmp8000.dtsi
>
> diff --git a/Documentation/devicetree/bindings/arm/spmp8000.txt b/Documentation/devicetree/bindings/arm/spmp8000.txt
> new file mode 100644
> index 0000000..c392b09
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/spmp8000.txt
> @@ -0,0 +1,25 @@
> +Sunplus SPMP8000 device tree bindings
> +=====================================
> +
> +Required root node properties:
> + - compatible:
> + - "gameware,letcool" : Letcool N350JO handheld game console board
> + - "sunplus,spmp8000" : A board based on the SPMP8000 SoC
> +
> +Timer required properties:
> + - compatible = "sunplus,spmp8000-timer"
> + - interrupt-parent : The interrupt controller node this timer belongs to
> + - interrupts : IRQs of the timer
> + - clock-freq : The frequency in HZ of the timer.
"clock-frequency" is what is commonly used.
> + - reg : The register bank for the timer.
> +
> +Watchdog required properties:
> + - compatible = "sunplus,spmp8000-watchdof"
s/watchdof/watchdog/
> + - interrupt-parent : The interrupt controller node this timer belongs to
> + - interrupts : IRQs of the watchdog
> + - reg : The register bank for the watchdog controller
> +
> +SCU required properties:
> + - compatible: "sunplus,spmp8000-scua" or "sunplus,spmp8000-scuab" or
> + "sunplus,spmp8000-scuc"
> + - reg: The register bank of the System Control Unit
> diff --git a/arch/arm/boot/dts/spmp8000-letcool.dts b/arch/arm/boot/dts/spmp8000-letcool.dts
> new file mode 100644
> index 0000000..424f2aa
> --- /dev/null
> +++ b/arch/arm/boot/dts/spmp8000-letcool.dts
> @@ -0,0 +1,20 @@
> +/dts-v1/;
> +/include/ "spmp8000.dtsi"
> +/ {
> + model = "Letcool N350JP handheld game console";
> + compatible = "gameware,letcool", "sunplus,spmp8000";
> +
> + memory {
> + reg = <0x00000000 0x02000000>;
> + };
> +
> + chosen {
> + linux,stdout-path = &uart0;
> + };
> +
> + armapb {
> + timer at 90000000 {
> + clock-freq = <15187500>;
> + };
> + };
> +};
> diff --git a/arch/arm/boot/dts/spmp8000.dtsi b/arch/arm/boot/dts/spmp8000.dtsi
> new file mode 100644
> index 0000000..15b25fa
> --- /dev/null
> +++ b/arch/arm/boot/dts/spmp8000.dtsi
> @@ -0,0 +1,93 @@
> +/ {
> + compatible = "sunplus,spmp8000";
> + #address-cells = <1>;
> + #size-cells = <1>;
> +
> + armapb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0x90000000 0x10000>;
> +
> + timer at 90000000 {
> + compatible = "sunplus,spmp8000-timer";
> + reg = <0x0 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <7 8 9>;
> + };
> +
> + watchdog at 90001000 {
> + compatible = "sunplus,spmp8000-wdt";
> + reg = <0x1000 0x1000>;
> + interrupt-parent = <&vic0>;
> + interrupts = <10 11 12>;
> + };
> +
> + scu-b at 90005000 {
> + compatible = "sunplus,spmp8000-scub";
> + reg = <0x5000 0x1000>;
> + };
> + };
> +
> + armahb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0x90010000 0x20000>;
> +
> + vic0: interrupt-controller at 90010000 {
> + compatible = "arm,pl192";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + reg = <0x0 0x1000>;
> + };
> +
> + vic1: interrupt-controller at 900020000 {
> + compatible = "arm,pl192";
> + interrupt-controller;
> + #interrupt-cells = <1>;
> + reg = <0x10000 0x1000>;
> + };
> + };
> +
> + plat {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0x92000000 0x1000000>;
> +
> + scu-c at 92005000 {
> + compatible = "sunplus,spmp8000-scuc";
> + reg = <0x5000 0x1000>;
> + };
> +
> + plat-apb {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0xB00000 0x10000>;
lower case for hex is preferred.
> +
> + uart0: uart-c0 at 92B04000 {
> + compatible = "ns16550a";
> + reg = <0x4000 0x1000>;
> + clock-frequency = <2076923>;
> + interrupt-parent = <&vic1>;
> + interrupts = <24>;
> + current-speed = <115200>;
> + reg-shift = <2>;
> + };
> + };
> + };
> +
> + axi {
> + compatible = "simple-bus";
> + #address-cells = <1>;
> + #size-cells = <1>;
> + ranges = <0 0x93000000 0x20000>;
> +
> + scu-a at 93007000 {
> + compatible = "sunplus,spmp8000-scua";
> + reg = <0x7000 0x1000>;
> + };
> + };
> +};
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-10-24 11:00 ` Jamie Iles
@ 2011-11-02 13:29 ` Zoltan Devai
2011-11-03 15:08 ` Arnd Bergmann
0 siblings, 1 reply; 78+ messages in thread
From: Zoltan Devai @ 2011-11-02 13:29 UTC (permalink / raw)
To: linux-arm-kernel
2011/10/24 Jamie Iles <jamie@jamieiles.com>:
> On Mon, Oct 24, 2011 at 11:13:21AM +0200, Arnd Bergmann wrote:
>> On Sunday 23 October 2011, Zoltan Devai wrote:
>> > 2011/10/19 Arnd Bergmann <arnd@arndb.de>:
>> > > On Wednesday 19 October 2011 18:01:54 Zoltan Devai wrote:
>> > >> Files needed for the basic machine support of SPMP8000
>> > >>
>> > >> Signed-off-by: Zoltan Devai <zoss@devai.org>
>> > >
>> > > Hi Zoltan,
>> > >
>> > > This version looks very nice, only a few small things remain that I noticed
>> > > reading through it again:
>> > OK, will correct these.
>> >
>> > What's next then ?
>>
>> We talked about it at the ARM subarchitecture maintainer summit, and I think
>> I'll just merge your platform code for 3.2 if you send the fixed version
>> in time. I'm not going to merge your clk support patch (2/5) though, since
>
> Zoltan uses my device tree bindings and multi IRQ handler for the VIC
> which hasn't yet been merged (and I haven't had any
> Tested-by/Acked-by's) from anyone other than Zoltan yet.
>
> I suppose the device tree binding and multi IRQ handler patches /could/
> go in without the other platform conversions though they haven't had any
> time in -next.
Arnd, Russell,
What about Jamie's VIC patches ?
Should I wait for those to get in somehow, or rebase SPMP8000
to not depend on those ?
Thanks,
Zoltan
^ permalink raw reply [flat|nested] 78+ messages in thread
* [PATCH v2 1/5] ARM: SPMP8000: Add machine base files
2011-11-02 13:29 ` Zoltan Devai
@ 2011-11-03 15:08 ` Arnd Bergmann
0 siblings, 0 replies; 78+ messages in thread
From: Arnd Bergmann @ 2011-11-03 15:08 UTC (permalink / raw)
To: linux-arm-kernel
On Wednesday 02 November 2011, Zoltan Devai wrote:
> 2011/10/24 Jamie Iles <jamie@jamieiles.com>:
> > On Mon, Oct 24, 2011 at 11:13:21AM +0200, Arnd Bergmann wrote:
> >> On Sunday 23 October 2011, Zoltan Devai wrote:
> >> > 2011/10/19 Arnd Bergmann <arnd@arndb.de>:
> >> We talked about it at the ARM subarchitecture maintainer summit, and I think
> >> I'll just merge your platform code for 3.2 if you send the fixed version
> >> in time. I'm not going to merge your clk support patch (2/5) though, since
> >
> > Zoltan uses my device tree bindings and multi IRQ handler for the VIC
> > which hasn't yet been merged (and I haven't had any
> > Tested-by/Acked-by's) from anyone other than Zoltan yet.
> >
> > I suppose the device tree binding and multi IRQ handler patches could
> > go in without the other platform conversions though they haven't had any
> > time in -next.
> Arnd, Russell,
>
> What about Jamie's VIC patches ?
> Should I wait for those to get in somehow, or rebase SPMP8000
> to not depend on those ?
Sorry I didn't get back to you on this any more. As you may have noticed,
Linus merged a large number of patches through my tree today and yours were
not a part of that.
It's too late for 3.2 now, but everything looks good for 3.3. I'll wait for
Jamie's patches to get stable first and then put your code into the arm-soc
tree.
There are other problems with the process in your series: you should never
cherry-pick a kernel from another branch if you depend on them. Instead,
make sure that the patches are queued up for the next merge window and not
changing any more (they are now obviously, as Linus merged them).
Arnd
^ permalink raw reply [flat|nested] 78+ messages in thread
end of thread, other threads:[~2011-11-03 15:08 UTC | newest]
Thread overview: 78+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-09 16:36 Add support for the SPMP8000 SoC and Letcool board Zoltan Devai
2011-10-09 16:36 ` [PATCH 1/9] ARM: vic: Don't write to the read-only register VIC_IRQ_STATUS Zoltan Devai
2011-10-10 1:35 ` Linus Walleij
2011-10-10 13:59 ` Zoltan Devai
2011-10-09 16:36 ` [PATCH 2/9] ARM: SPMP8000: Add machine base files Zoltan Devai
2011-10-09 17:22 ` Jamie Iles
2011-10-10 11:36 ` Zoltan Devai
2011-10-10 11:52 ` Jamie Iles
2011-10-11 14:44 ` Arnd Bergmann
2011-10-16 14:10 ` Zoltan Devai
2011-10-16 15:57 ` Russell King - ARM Linux
2011-10-16 20:59 ` Arnd Bergmann
2011-10-16 20:52 ` Jean-Christophe PLAGNIOL-VILLARD
2011-10-17 11:44 ` Arnd Bergmann
2011-10-09 16:36 ` [PATCH 3/9] ARM: SPMP8000: Add clk support Zoltan Devai
2011-10-13 9:38 ` Russell King - ARM Linux
2011-10-16 14:16 ` Zoltan Devai
2011-10-17 12:15 ` Mark Brown
2011-10-18 10:18 ` Russell King - ARM Linux
2011-10-09 16:36 ` [PATCH 4/9] ARM: SPMP8000: Add ADC driver Zoltan Devai
2011-10-10 1:29 ` Linus Walleij
2011-10-10 9:42 ` Jonathan Cameron
2011-10-10 9:46 ` Jonathan Cameron
2011-10-10 10:00 ` Mark Brown
2011-10-10 11:42 ` Zoltan Devai
2011-10-10 11:44 ` Mark Brown
2011-10-11 14:17 ` Arnd Bergmann
2011-10-11 14:40 ` Mark Brown
2011-10-11 15:24 ` Arnd Bergmann
2011-10-11 15:39 ` Jonathan Cameron
2011-10-12 14:42 ` Mark Brown
2011-10-12 15:41 ` Jonathan Cameron
2011-10-13 9:47 ` Russell King - ARM Linux
2011-10-13 11:09 ` Linus Walleij
2011-10-13 11:35 ` Jonathan Cameron
2011-10-13 11:35 ` Mark Brown
2011-10-13 12:17 ` Russell King - ARM Linux
2011-10-13 14:19 ` Arnd Bergmann
2011-10-13 14:27 ` Mark Brown
2011-10-13 14:38 ` Mark Brown
2011-10-13 14:56 ` Arnd Bergmann
2011-10-13 16:25 ` Mark Brown
2011-10-09 16:36 ` [PATCH 5/9] ARM: SPMP8000: Add pinmux driver Zoltan Devai
2011-10-10 1:32 ` Linus Walleij
2011-10-10 8:01 ` Barry Song
2011-10-10 8:34 ` Linus Walleij
2011-10-09 16:36 ` [PATCH 6/9] ARM: SPMP8000: Add pwm driver Zoltan Devai
2011-10-10 1:50 ` Linus Walleij
2011-10-10 9:30 ` Sascha Hauer
2011-10-09 16:36 ` [PATCH 7/9] ARM: SPMP8000: Add dts file of SPMP8000 SoC and Letcool board Zoltan Devai
2011-10-10 8:54 ` Jamie Iles
2011-10-09 16:36 ` [PATCH 8/9] ARM: SPMP8000: Add support for the " Zoltan Devai
2011-10-11 14:09 ` Arnd Bergmann
2011-10-11 14:43 ` Zoltan Devai
2011-10-11 15:18 ` Arnd Bergmann
2011-10-13 9:54 ` Russell King - ARM Linux
2011-10-09 16:36 ` [PATCH 9/9] ARM: SPMP8000: Add Kconfig and Makefile entries to build the machine Zoltan Devai
2011-10-09 17:25 ` Jamie Iles
2011-10-10 1:43 ` Linus Walleij
2011-10-13 9:53 ` Russell King - ARM Linux
2011-10-10 8:55 ` Add support for the SPMP8000 SoC and Letcool board Jamie Iles
2011-10-10 12:00 ` Zoltan Devai
2011-10-10 12:03 ` Jamie Iles
2011-10-11 14:57 ` Arnd Bergmann
[not found] ` <1319040118-29773-1-git-send-email-zoss@devai.org>
2011-10-19 16:01 ` [PATCH v2 1/5] ARM: SPMP8000: Add machine base files Zoltan Devai
2011-10-19 19:15 ` Arnd Bergmann
2011-10-21 22:54 ` Russell King - ARM Linux
2011-10-23 21:47 ` Zoltan Devai
2011-10-23 21:37 ` Zoltan Devai
2011-10-24 9:13 ` Arnd Bergmann
2011-10-24 11:00 ` Jamie Iles
2011-11-02 13:29 ` Zoltan Devai
2011-11-03 15:08 ` Arnd Bergmann
2011-10-19 16:01 ` [PATCH v2 2/5] ARM: SPMP8000: Add clk support Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 3/5] ARM: SPMP8000: Add clocksource and clockevent drivers Zoltan Devai
2011-10-19 16:01 ` [PATCH v2 4/5] ARM: SPMP8000: Add SPMP8000 SoC and Letcool board dts descriptions Zoltan Devai
2011-10-24 12:47 ` Rob Herring
2011-10-19 16:01 ` [PATCH v2 5/5] ARM: SPMP8000: Add Kconfig and Makefile entries Zoltan Devai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).