mirror of https://github.com/hak5/openwrt.git
cns21xx: add support for 3.8
Signed-off-by: Gabor Juhos <juhosg@openwrt.org> SVN-Revision: 35737lede-17.01
parent
9ec9adf3ea
commit
42cdd3bef4
|
@ -0,0 +1,160 @@
|
||||||
|
CONFIG_ALIGNMENT_TRAP=y
|
||||||
|
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
|
||||||
|
CONFIG_ARCH_CNS21XX=y
|
||||||
|
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
|
||||||
|
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
|
||||||
|
# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
|
||||||
|
CONFIG_ARCH_NR_GPIO=0
|
||||||
|
CONFIG_ARCH_REQUIRE_GPIOLIB=y
|
||||||
|
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
|
||||||
|
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
|
||||||
|
# CONFIG_ARCH_VT8500_SINGLE is not set
|
||||||
|
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
|
||||||
|
CONFIG_ARM=y
|
||||||
|
# CONFIG_ARM_CPU_SUSPEND is not set
|
||||||
|
CONFIG_ARM_L1_CACHE_SHIFT=4
|
||||||
|
CONFIG_ARM_L1_CACHE_SHIFT_4=y
|
||||||
|
CONFIG_ARM_NR_BANKS=8
|
||||||
|
# CONFIG_ARPD is not set
|
||||||
|
CONFIG_ATA=m
|
||||||
|
CONFIG_ATAGS=y
|
||||||
|
# CONFIG_CACHE_L2X0 is not set
|
||||||
|
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
|
||||||
|
CONFIG_CLONE_BACKWARDS=y
|
||||||
|
CONFIG_CMDLINE="console=ttyS0,38400 rootfstype=squashfs,jffs2 noinitrd"
|
||||||
|
CONFIG_CMDLINE_FROM_BOOTLOADER=y
|
||||||
|
CONFIG_CNS21XX_DEV_GEC=y
|
||||||
|
CONFIG_CNS21XX_DEV_SPI_MASTER=y
|
||||||
|
CONFIG_CNS21XX_DEV_USB=y
|
||||||
|
CONFIG_CNS21XX_GEC=y
|
||||||
|
CONFIG_CPU_32v4=y
|
||||||
|
CONFIG_CPU_ABRT_EV4=y
|
||||||
|
# CONFIG_CPU_BPREDICT_DISABLE is not set
|
||||||
|
CONFIG_CPU_CACHE_FA=y
|
||||||
|
CONFIG_CPU_CACHE_VIVT=y
|
||||||
|
CONFIG_CPU_COPY_FA=y
|
||||||
|
CONFIG_CPU_CP15=y
|
||||||
|
CONFIG_CPU_CP15_MMU=y
|
||||||
|
# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
|
||||||
|
CONFIG_CPU_FA526=y
|
||||||
|
# CONFIG_CPU_ICACHE_DISABLE is not set
|
||||||
|
CONFIG_CPU_PABRT_LEGACY=y
|
||||||
|
CONFIG_CPU_TLB_FA=y
|
||||||
|
CONFIG_CPU_USE_DOMAINS=y
|
||||||
|
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
|
||||||
|
# CONFIG_DEBUG_USER is not set
|
||||||
|
CONFIG_DECOMPRESS_LZMA=y
|
||||||
|
CONFIG_DLCI=m
|
||||||
|
CONFIG_DLCI_MAX=8
|
||||||
|
CONFIG_DMADEVICES=y
|
||||||
|
CONFIG_DNOTIFY=y
|
||||||
|
CONFIG_EEPROM_AT25=y
|
||||||
|
CONFIG_FA_WATCHDOG=y
|
||||||
|
CONFIG_FRAME_POINTER=y
|
||||||
|
CONFIG_GENERIC_ATOMIC64=y
|
||||||
|
CONFIG_GENERIC_BUG=y
|
||||||
|
CONFIG_GENERIC_GPIO=y
|
||||||
|
CONFIG_GENERIC_IO=y
|
||||||
|
CONFIG_GENERIC_IRQ_SHOW=y
|
||||||
|
CONFIG_GENERIC_PCI_IOMAP=y
|
||||||
|
CONFIG_GENERIC_SMP_IDLE_THREAD=y
|
||||||
|
CONFIG_GENERIC_STRNCPY_FROM_USER=y
|
||||||
|
CONFIG_GENERIC_STRNLEN_USER=y
|
||||||
|
CONFIG_GPIOLIB=y
|
||||||
|
CONFIG_GPIO_SYSFS=y
|
||||||
|
# CONFIG_HAMRADIO is not set
|
||||||
|
CONFIG_HARDIRQS_SW_RESEND=y
|
||||||
|
CONFIG_HAS_DMA=y
|
||||||
|
CONFIG_HAS_IOMEM=y
|
||||||
|
CONFIG_HAS_IOPORT=y
|
||||||
|
CONFIG_HAVE_AOUT=y
|
||||||
|
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||||
|
CONFIG_HAVE_ARCH_KGDB=y
|
||||||
|
CONFIG_HAVE_ARCH_PFN_VALID=y
|
||||||
|
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
|
||||||
|
CONFIG_HAVE_ARCH_TRACEHOOK=y
|
||||||
|
CONFIG_HAVE_BPF_JIT=y
|
||||||
|
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||||
|
CONFIG_HAVE_DEBUG_KMEMLEAK=y
|
||||||
|
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||||
|
CONFIG_HAVE_DMA_ATTRS=y
|
||||||
|
CONFIG_HAVE_DMA_CONTIGUOUS=y
|
||||||
|
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||||
|
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||||
|
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||||
|
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||||
|
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||||
|
CONFIG_HAVE_GENERIC_HARDIRQS=y
|
||||||
|
CONFIG_HAVE_IRQ_WORK=y
|
||||||
|
CONFIG_HAVE_KERNEL_GZIP=y
|
||||||
|
CONFIG_HAVE_KERNEL_LZMA=y
|
||||||
|
CONFIG_HAVE_KERNEL_LZO=y
|
||||||
|
CONFIG_HAVE_KERNEL_XZ=y
|
||||||
|
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
|
||||||
|
CONFIG_HAVE_MEMBLOCK=y
|
||||||
|
CONFIG_HAVE_NET_DSA=y
|
||||||
|
CONFIG_HAVE_OPROFILE=y
|
||||||
|
CONFIG_HAVE_PERF_EVENTS=y
|
||||||
|
CONFIG_HAVE_PROC_CPU=y
|
||||||
|
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
|
||||||
|
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
|
||||||
|
CONFIG_HAVE_UID16=y
|
||||||
|
CONFIG_HDLC=m
|
||||||
|
CONFIG_HDLC_CISCO=m
|
||||||
|
CONFIG_HDLC_FR=m
|
||||||
|
CONFIG_HDLC_PPP=m
|
||||||
|
CONFIG_HDLC_RAW=m
|
||||||
|
CONFIG_HWMON=y
|
||||||
|
CONFIG_HW_RANDOM=y
|
||||||
|
CONFIG_INITRAMFS_SOURCE=""
|
||||||
|
# CONFIG_IP_ADVANCED_ROUTER is not set
|
||||||
|
CONFIG_IP_PIMSM_V1=y
|
||||||
|
CONFIG_IP_PIMSM_V2=y
|
||||||
|
CONFIG_KTIME_SCALAR=y
|
||||||
|
CONFIG_LEGACY_PTYS=y
|
||||||
|
CONFIG_LEGACY_PTY_COUNT=256
|
||||||
|
CONFIG_M25PXX_USE_FAST_READ=y
|
||||||
|
CONFIG_MACH_NSB3AST=y
|
||||||
|
CONFIG_MACH_NS_K330=y
|
||||||
|
CONFIG_MDIO_BOARDINFO=y
|
||||||
|
CONFIG_MODULES_USE_ELF_REL=y
|
||||||
|
# CONFIG_MTD_CFI is not set
|
||||||
|
CONFIG_MTD_M25P80=y
|
||||||
|
CONFIG_NEED_DMA_MAP_STATE=y
|
||||||
|
CONFIG_NEED_PER_CPU_KM=y
|
||||||
|
CONFIG_NLS=m
|
||||||
|
CONFIG_PAGEFLAGS_EXTENDED=y
|
||||||
|
CONFIG_PAGE_OFFSET=0xC0000000
|
||||||
|
# CONFIG_PCI_SYSCALL is not set
|
||||||
|
CONFIG_PERCPU_RWSEM=y
|
||||||
|
CONFIG_PERF_USE_VMALLOC=y
|
||||||
|
CONFIG_PHYLIB=y
|
||||||
|
CONFIG_PHYS_OFFSET=0x00000000
|
||||||
|
CONFIG_PLAT_FA=y
|
||||||
|
CONFIG_PLAT_FA_GPIO=y
|
||||||
|
CONFIG_PLAT_FA_TIME=y
|
||||||
|
# CONFIG_PREEMPT_RCU is not set
|
||||||
|
CONFIG_SCSI=m
|
||||||
|
CONFIG_SCSI_MOD=m
|
||||||
|
# CONFIG_SCSI_MULTI_LUN is not set
|
||||||
|
CONFIG_SERIO=y
|
||||||
|
CONFIG_SERIO_LIBPS2=y
|
||||||
|
CONFIG_SERIO_SERPORT=y
|
||||||
|
CONFIG_SPI=y
|
||||||
|
CONFIG_SPI_BITBANG=y
|
||||||
|
CONFIG_SPI_CNS21XX=y
|
||||||
|
CONFIG_SPI_DEBUG=y
|
||||||
|
CONFIG_SPI_MASTER=y
|
||||||
|
CONFIG_SPLIT_PTLOCK_CPUS=999999
|
||||||
|
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
|
||||||
|
CONFIG_TICK_CPU_ACCOUNTING=y
|
||||||
|
CONFIG_UID16=y
|
||||||
|
CONFIG_UIDGID_CONVERTED=y
|
||||||
|
# CONFIG_USB_ARCH_HAS_XHCI is not set
|
||||||
|
CONFIG_USB_SUPPORT=y
|
||||||
|
CONFIG_VECTORS_BASE=0xffff0000
|
||||||
|
CONFIG_VM_EVENT_COUNTERS=y
|
||||||
|
CONFIG_WAN=y
|
||||||
|
CONFIG_ZBOOT_ROM_BSS=0x0
|
||||||
|
CONFIG_ZBOOT_ROM_TEXT=0x0
|
||||||
|
CONFIG_ZONE_DMA_FLAG=0
|
|
@ -0,0 +1,24 @@
|
||||||
|
--- a/kernel/printk.c
|
||||||
|
+++ b/kernel/printk.c
|
||||||
|
@@ -48,6 +48,10 @@
|
||||||
|
#define CREATE_TRACE_POINTS
|
||||||
|
#include <trace/events/printk.h>
|
||||||
|
|
||||||
|
+#ifdef CONFIG_DEBUG_LL
|
||||||
|
+extern void printascii(char *);
|
||||||
|
+#endif /* CONFIG_DEBUG_LL */
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Architectures can override it:
|
||||||
|
*/
|
||||||
|
@@ -473,6 +477,10 @@ static ssize_t devkmsg_read(struct file
|
||||||
|
ts_usec = msg->ts_nsec;
|
||||||
|
do_div(ts_usec, 1000);
|
||||||
|
|
||||||
|
+#ifdef CONFIG_DEBUG_LL
|
||||||
|
+ printascii(printk_buf);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* If we couldn't merge continuation line fragments during the print,
|
||||||
|
* export the stored flags to allow an optional external merge of the
|
|
@ -0,0 +1,56 @@
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -1133,10 +1133,15 @@ source "arch/arm/mach-w90x900/Kconfig"
|
||||||
|
|
||||||
|
source "arch/arm/mach-zynq/Kconfig"
|
||||||
|
|
||||||
|
+source "arch/arm/plat-fa/Kconfig"
|
||||||
|
+
|
||||||
|
# Definitions to make life easier
|
||||||
|
config ARCH_ACORN
|
||||||
|
bool
|
||||||
|
|
||||||
|
+config PLAT_FA
|
||||||
|
+ bool
|
||||||
|
+
|
||||||
|
config PLAT_IOP
|
||||||
|
bool
|
||||||
|
select GENERIC_CLOCKEVENTS
|
||||||
|
--- a/arch/arm/Makefile
|
||||||
|
+++ b/arch/arm/Makefile
|
||||||
|
@@ -202,6 +202,7 @@ machine-$(CONFIG_ARCH_SUNXI) += sunxi
|
||||||
|
plat-$(CONFIG_ARCH_OMAP) += omap
|
||||||
|
plat-$(CONFIG_ARCH_S3C64XX) += samsung
|
||||||
|
plat-$(CONFIG_PLAT_IOP) += iop
|
||||||
|
+plat-$(CONFIG_PLAT_FA) += fa
|
||||||
|
plat-$(CONFIG_PLAT_ORION) += orion
|
||||||
|
plat-$(CONFIG_PLAT_PXA) += pxa
|
||||||
|
plat-$(CONFIG_PLAT_S3C24XX) += s3c24xx samsung
|
||||||
|
@@ -311,7 +312,7 @@ define archhelp
|
||||||
|
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
|
||||||
|
echo '* xipImage - XIP kernel image, if configured (arch/$(ARCH)/boot/xipImage)'
|
||||||
|
echo ' uImage - U-Boot wrapped zImage'
|
||||||
|
- echo ' bootpImage - Combined zImage and initial RAM disk'
|
||||||
|
+ echo ' bootpImage - Combined zImage and initial RAM disk'
|
||||||
|
echo ' (supply initrd image via make variable INITRD=<path>)'
|
||||||
|
echo '* dtbs - Build device tree blobs for enabled boards'
|
||||||
|
echo ' install - Install uncompressed kernel'
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/Makefile
|
||||||
|
@@ -0,0 +1,10 @@
|
||||||
|
+#
|
||||||
|
+# Makefile for the linux kernel.
|
||||||
|
+#
|
||||||
|
+
|
||||||
|
+obj-y :=
|
||||||
|
+
|
||||||
|
+obj-m :=
|
||||||
|
+obj-n :=
|
||||||
|
+obj- :=
|
||||||
|
+
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/Kconfig
|
||||||
|
@@ -0,0 +1,3 @@
|
||||||
|
+if PLAT_FA
|
||||||
|
+
|
||||||
|
+endif
|
|
@ -0,0 +1,143 @@
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/include/plat/time.h
|
||||||
|
@@ -0,0 +1,20 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License as published by
|
||||||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||||||
|
+ * (at your option) any later version.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _FA_TIME_H
|
||||||
|
+#define _FA_TIME_H
|
||||||
|
+
|
||||||
|
+#define FA_TIMER1 0
|
||||||
|
+#define FA_TIMER2 1
|
||||||
|
+#define FA_TIMER3 2
|
||||||
|
+
|
||||||
|
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
|
||||||
|
+ unsigned int timer, unsigned int freq);
|
||||||
|
+
|
||||||
|
+#endif /* _FA_TIME_H */
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/time.c
|
||||||
|
@@ -0,0 +1,97 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (C) 2001-2006 Storlink, Corp.
|
||||||
|
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License as published by
|
||||||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||||||
|
+ * (at your option) any later version.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+#include <linux/irq.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+
|
||||||
|
+#include <asm/mach/time.h>
|
||||||
|
+#include <plat/time.h>
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Register definitions for the timers
|
||||||
|
+ */
|
||||||
|
+#define TIMER_COUNT(_base, _tmr) ((_base) + 0x00 + (_tmr) * 0x10)
|
||||||
|
+#define TIMER_LOAD(_base, _tmr) ((_base) + 0x04 + (_tmr) * 0x10)
|
||||||
|
+#define TIMER_MATCH1(_base, _tmr) ((_base) + 0x08 + (_tmr) * 0x10)
|
||||||
|
+#define TIMER_MATCH2(_base, _tmr) ((_base) + 0x0c + (_tmr) * 0x10)
|
||||||
|
+
|
||||||
|
+#define TIMER_CR(_base) ((_base) + 0x30)
|
||||||
|
+#define TIMER_STATUS(_base) ((_base) + 0x34)
|
||||||
|
+#define TIMER_MASK(_base) ((_base) + 0x38)
|
||||||
|
+
|
||||||
|
+#define TIMER_SIZE 0x3c
|
||||||
|
+
|
||||||
|
+#define TIMER_CR_ENABLE(x) (1 << ((x) * 3))
|
||||||
|
+#define TIMER_CR_CLOCK(x) (1 << ((x) * 3 + 1))
|
||||||
|
+#define TIMER_CR_INT(x) (1 << ((x) * 3 + 2))
|
||||||
|
+#define TIMER_CR_DOWN(x) (1 << ((x) * 3 + 9))
|
||||||
|
+
|
||||||
|
+#define TIMER_MASK_MATCH1(x) (1 << ((x) * 3))
|
||||||
|
+#define TIMER_MASK_MATCH2(x) (1 << ((x) * 3 + 1))
|
||||||
|
+#define TIMER_MASK_OF(x) (1 << ((x) * 3 + 2))
|
||||||
|
+
|
||||||
|
+#define TIMER_MASK_ALL 0x7ff
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * IRQ handler for the timer
|
||||||
|
+ */
|
||||||
|
+static irqreturn_t fa_timer_interrupt(int irq, void *dev_id)
|
||||||
|
+{
|
||||||
|
+ timer_tick();
|
||||||
|
+ return IRQ_HANDLED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct irqaction fa_timer_irq = {
|
||||||
|
+ .name = "Timer Tick",
|
||||||
|
+ .flags = IRQF_DISABLED | IRQF_TIMER,
|
||||||
|
+ .handler = fa_timer_interrupt,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int __init fa_timer_init(unsigned int mapbase, unsigned int irq,
|
||||||
|
+ unsigned int timer, unsigned int freq)
|
||||||
|
+{
|
||||||
|
+ void __iomem *base;
|
||||||
|
+
|
||||||
|
+ base = ioremap(mapbase, TIMER_SIZE);
|
||||||
|
+ if (!base)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ /* disable timers, clear status and mask all interrupts */
|
||||||
|
+ __raw_writel(0, TIMER_CR(base));
|
||||||
|
+ __raw_writel(0, TIMER_STATUS(base));
|
||||||
|
+ __raw_writel(TIMER_MASK_ALL, TIMER_MASK(base));
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Make irqs happen for the system timer
|
||||||
|
+ */
|
||||||
|
+ setup_irq(irq, &fa_timer_irq);
|
||||||
|
+
|
||||||
|
+ /* Setup the timer */
|
||||||
|
+ __raw_writel(freq / HZ, TIMER_COUNT(base, timer));
|
||||||
|
+ __raw_writel(freq / HZ, TIMER_LOAD(base, timer));
|
||||||
|
+ __raw_writel(0, TIMER_MATCH1(base, timer));
|
||||||
|
+ __raw_writel(0, TIMER_MATCH2(base, timer));
|
||||||
|
+
|
||||||
|
+ /* Enable interrupt and start the timer */
|
||||||
|
+ __raw_writel(TIMER_MASK_ALL & ~TIMER_MASK_OF(timer),
|
||||||
|
+ TIMER_MASK(base));
|
||||||
|
+
|
||||||
|
+ __raw_writel(TIMER_CR_ENABLE(timer) |
|
||||||
|
+ TIMER_CR_INT(timer) |
|
||||||
|
+ TIMER_CR_DOWN(timer),
|
||||||
|
+ TIMER_CR(base));
|
||||||
|
+
|
||||||
|
+ iounmap(base);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
--- a/arch/arm/plat-fa/Kconfig
|
||||||
|
+++ b/arch/arm/plat-fa/Kconfig
|
||||||
|
@@ -1,3 +1,6 @@
|
||||||
|
if PLAT_FA
|
||||||
|
|
||||||
|
+config PLAT_FA_TIME
|
||||||
|
+ def_bool n
|
||||||
|
+
|
||||||
|
endif
|
||||||
|
--- a/arch/arm/plat-fa/Makefile
|
||||||
|
+++ b/arch/arm/plat-fa/Makefile
|
||||||
|
@@ -4,6 +4,8 @@
|
||||||
|
|
||||||
|
obj-y :=
|
||||||
|
|
||||||
|
+obj-$(CONFIG_PLAT_FA_TIME) += time.o
|
||||||
|
+
|
||||||
|
obj-m :=
|
||||||
|
obj-n :=
|
||||||
|
obj- :=
|
|
@ -0,0 +1,343 @@
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/gpio.c
|
||||||
|
@@ -0,0 +1,283 @@
|
||||||
|
+/*
|
||||||
|
+ * Gpiochip and interrupt routines for Faraday FA526 based SoCs
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
|
||||||
|
+ * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * Based on plat-mxc/gpio.c:
|
||||||
|
+ * MXC GPIO supchip. (c) 2008 Daniel Mack <daniel@caiaq.de>
|
||||||
|
+ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License as published by
|
||||||
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||||||
|
+ * (at your option) any later version.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
+
|
||||||
|
+#include <plat/gpio.h>
|
||||||
|
+
|
||||||
|
+#define GPIO_DATA_OUT 0x0
|
||||||
|
+#define GPIO_DATA_IN 0x4
|
||||||
|
+#define GPIO_DIR 0x8
|
||||||
|
+#define GPIO_DATA_SET 0x10
|
||||||
|
+#define GPIO_DATA_CLR 0x14
|
||||||
|
+#define GPIO_PULL_EN 0x18
|
||||||
|
+#define GPIO_PULL_TYPE 0x1C
|
||||||
|
+#define GPIO_INT_EN 0x20
|
||||||
|
+#define GPIO_INT_STAT 0x24
|
||||||
|
+#define GPIO_INT_MASK 0x2C
|
||||||
|
+#define GPIO_INT_CLR 0x30
|
||||||
|
+#define GPIO_INT_TYPE 0x34
|
||||||
|
+#define GPIO_INT_BOTH_EDGE 0x38
|
||||||
|
+#define GPIO_INT_LEVEL 0x3C
|
||||||
|
+#define GPIO_DEBOUNCE_EN 0x40
|
||||||
|
+#define GPIO_DEBOUNCE_PRESCALE 0x44
|
||||||
|
+
|
||||||
|
+#define GPIO_REGS_SIZE 0x48
|
||||||
|
+
|
||||||
|
+static DEFINE_SPINLOCK(fa_gpio_lock);
|
||||||
|
+
|
||||||
|
+static inline struct fa_gpio_chip *to_fgc(struct gpio_chip *chip)
|
||||||
|
+{
|
||||||
|
+ return container_of(chip, struct fa_gpio_chip, gpio_chip);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void _fa_gpio_irq_setenable(struct irq_data *d, int enable)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
|
||||||
|
+ void __iomem *base = fgc->mem_base;
|
||||||
|
+ unsigned int gpio = d->irq - fgc->irq_base;
|
||||||
|
+ unsigned int reg;
|
||||||
|
+
|
||||||
|
+ reg = __raw_readl(base + GPIO_INT_EN);
|
||||||
|
+ reg = (reg & (~(1 << gpio))) | (!!enable << gpio);
|
||||||
|
+ __raw_writel(reg, base + GPIO_INT_EN);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void fa_gpio_irq_ack(struct irq_data *d)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
|
||||||
|
+ unsigned int gpio = d->irq - fgc->irq_base;
|
||||||
|
+
|
||||||
|
+ __raw_writel(1 << gpio, fgc->mem_base + GPIO_INT_CLR);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void fa_gpio_irq_mask(struct irq_data *d)
|
||||||
|
+{
|
||||||
|
+ _fa_gpio_irq_setenable(d, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void fa_gpio_irq_unmask(struct irq_data *d)
|
||||||
|
+{
|
||||||
|
+ _fa_gpio_irq_setenable(d, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = irq_get_chip_data(d->irq);
|
||||||
|
+ void __iomem *base = fgc->mem_base;
|
||||||
|
+ unsigned int gpio = d->irq - fgc->irq_base;
|
||||||
|
+ unsigned int gpio_mask = 1 << gpio;
|
||||||
|
+ unsigned int reg_both, reg_level, reg_type;
|
||||||
|
+
|
||||||
|
+ reg_type = __raw_readl(base + GPIO_INT_TYPE);
|
||||||
|
+ reg_level = __raw_readl(base + GPIO_INT_LEVEL);
|
||||||
|
+ reg_both = __raw_readl(base + GPIO_INT_BOTH_EDGE);
|
||||||
|
+
|
||||||
|
+ switch (type) {
|
||||||
|
+ case IRQ_TYPE_EDGE_BOTH:
|
||||||
|
+ reg_type &= ~gpio_mask;
|
||||||
|
+ reg_both |= gpio_mask;
|
||||||
|
+ break;
|
||||||
|
+ case IRQ_TYPE_EDGE_RISING:
|
||||||
|
+ reg_type &= ~gpio_mask;
|
||||||
|
+ reg_both &= ~gpio_mask;
|
||||||
|
+ reg_level &= ~gpio_mask;
|
||||||
|
+ break;
|
||||||
|
+ case IRQ_TYPE_EDGE_FALLING:
|
||||||
|
+ reg_type &= ~gpio_mask;
|
||||||
|
+ reg_both &= ~gpio_mask;
|
||||||
|
+ reg_level |= gpio_mask;
|
||||||
|
+ break;
|
||||||
|
+ case IRQ_TYPE_LEVEL_HIGH:
|
||||||
|
+ reg_type |= gpio_mask;
|
||||||
|
+ reg_level &= ~gpio_mask;
|
||||||
|
+ break;
|
||||||
|
+ case IRQ_TYPE_LEVEL_LOW:
|
||||||
|
+ reg_type |= gpio_mask;
|
||||||
|
+ reg_level |= gpio_mask;
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ __raw_writel(reg_type, base + GPIO_INT_TYPE);
|
||||||
|
+ __raw_writel(reg_level, base + GPIO_INT_LEVEL);
|
||||||
|
+ __raw_writel(reg_both, base + GPIO_INT_BOTH_EDGE);
|
||||||
|
+
|
||||||
|
+ fa_gpio_irq_ack(d);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void fa_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_data *data = irq_get_handler_data(irq);
|
||||||
|
+ unsigned int chip;
|
||||||
|
+
|
||||||
|
+ for (chip = 0; chip < data->nchips; chip++) {
|
||||||
|
+ struct fa_gpio_chip *fgc = &data->chips[chip];
|
||||||
|
+ unsigned int status;
|
||||||
|
+ unsigned int i;
|
||||||
|
+
|
||||||
|
+ status = __raw_readl(fgc->mem_base + GPIO_INT_STAT);
|
||||||
|
+ for (i = fgc->irq_base; status != 0; status >>= 1, i++) {
|
||||||
|
+ if ((status & 1) == 0)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ BUG_ON(!(irq_desc[i].handle_irq));
|
||||||
|
+ irq_desc[i].handle_irq(i, &irq_desc[i]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct irq_chip fa_gpio_irq_chip = {
|
||||||
|
+ .name = "GPIO",
|
||||||
|
+ .irq_ack = fa_gpio_irq_ack,
|
||||||
|
+ .irq_mask = fa_gpio_irq_mask,
|
||||||
|
+ .irq_unmask = fa_gpio_irq_unmask,
|
||||||
|
+ .irq_set_type = fa_gpio_irq_set_type,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void _fa_gpio_set_direction(struct fa_gpio_chip *fgc, unsigned offset,
|
||||||
|
+ int is_output)
|
||||||
|
+{
|
||||||
|
+ unsigned int reg;
|
||||||
|
+
|
||||||
|
+ reg = __raw_readl(fgc->mem_base + GPIO_DIR);
|
||||||
|
+ if (is_output)
|
||||||
|
+ reg |= 1 << offset;
|
||||||
|
+ else
|
||||||
|
+ reg &= ~(1 << offset);
|
||||||
|
+ __raw_writel(reg, fgc->mem_base + GPIO_DIR);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void _fa_gpio_set(struct fa_gpio_chip *fgc, unsigned offset, int value)
|
||||||
|
+{
|
||||||
|
+ if (value)
|
||||||
|
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_SET);
|
||||||
|
+ else
|
||||||
|
+ __raw_writel(1 << offset, fgc->mem_base + GPIO_DATA_CLR);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void fa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = to_fgc(chip);
|
||||||
|
+
|
||||||
|
+ _fa_gpio_set(fgc, offset, value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = to_fgc(chip);
|
||||||
|
+
|
||||||
|
+ return (__raw_readl(fgc->mem_base + GPIO_DATA_IN) >> offset) & 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = to_fgc(chip);
|
||||||
|
+
|
||||||
|
+ return fgc->irq_base + offset;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = to_fgc(chip);
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&fa_gpio_lock, flags);
|
||||||
|
+
|
||||||
|
+ _fa_gpio_set_direction(fgc, offset, 0);
|
||||||
|
+
|
||||||
|
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_direction_output(struct gpio_chip *chip,
|
||||||
|
+ unsigned offset,
|
||||||
|
+ int value)
|
||||||
|
+{
|
||||||
|
+ struct fa_gpio_chip *fgc = to_fgc(chip);
|
||||||
|
+ unsigned long flags;
|
||||||
|
+
|
||||||
|
+ spin_lock_irqsave(&fa_gpio_lock, flags);
|
||||||
|
+
|
||||||
|
+ _fa_gpio_set(fgc, offset, value);
|
||||||
|
+ _fa_gpio_set_direction(fgc, offset, 1);
|
||||||
|
+
|
||||||
|
+ spin_unlock_irqrestore(&fa_gpio_lock, flags);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_gpio_init_chip(struct fa_gpio_chip *fgc)
|
||||||
|
+{
|
||||||
|
+ void __iomem *mem_base;
|
||||||
|
+ unsigned int i;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ mem_base = ioremap(fgc->map_base, GPIO_REGS_SIZE);
|
||||||
|
+ if (!mem_base)
|
||||||
|
+ return -ENXIO;
|
||||||
|
+
|
||||||
|
+ fgc->mem_base = mem_base;
|
||||||
|
+
|
||||||
|
+ fgc->gpio_chip.direction_input = fa_gpio_direction_input;
|
||||||
|
+ fgc->gpio_chip.direction_output = fa_gpio_direction_output;
|
||||||
|
+ fgc->gpio_chip.get = fa_gpio_get;
|
||||||
|
+ fgc->gpio_chip.set = fa_gpio_set;
|
||||||
|
+ fgc->gpio_chip.to_irq = fa_gpio_to_irq;
|
||||||
|
+
|
||||||
|
+ /* disable, unmask and clear all interrupts */
|
||||||
|
+ __raw_writel(0x0, mem_base + GPIO_INT_EN);
|
||||||
|
+ __raw_writel(0x0, mem_base + GPIO_INT_MASK);
|
||||||
|
+ __raw_writel(~0x0, mem_base + GPIO_INT_CLR);
|
||||||
|
+
|
||||||
|
+ for (i = fgc->irq_base;
|
||||||
|
+ i < fgc->irq_base + fgc->gpio_chip.ngpio; i++) {
|
||||||
|
+ irq_set_chip(i, &fa_gpio_irq_chip);
|
||||||
|
+ irq_set_chip_data(i, fgc);
|
||||||
|
+ irq_set_handler(i, handle_edge_irq);
|
||||||
|
+ set_irq_flags(i, IRQF_VALID);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ err = gpiochip_add(&fgc->gpio_chip);
|
||||||
|
+ if (err)
|
||||||
|
+ goto unmap;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ unmap:
|
||||||
|
+ iounmap(fgc->mem_base);
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void __init fa_gpio_init(struct fa_gpio_data *data)
|
||||||
|
+{
|
||||||
|
+ unsigned int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < data->nchips; i++) {
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ err = fa_gpio_init_chip(&data->chips[i]);
|
||||||
|
+ if (WARN(err, "GPIO init failed\n"))
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ irq_set_chained_handler(data->irq, fa_gpio_irq_handler);
|
||||||
|
+ irq_set_handler_data(data->irq, data);
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/plat-fa/include/plat/gpio.h
|
||||||
|
@@ -0,0 +1,33 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _FA_GPIO_H
|
||||||
|
+#define _FA_GPIO_H
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+#include <linux/irq.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+
|
||||||
|
+struct fa_gpio_chip {
|
||||||
|
+ struct gpio_chip gpio_chip;
|
||||||
|
+ unsigned int map_base;
|
||||||
|
+ unsigned int irq_base;
|
||||||
|
+
|
||||||
|
+ void __iomem *mem_base;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct fa_gpio_data {
|
||||||
|
+ struct fa_gpio_chip *chips;
|
||||||
|
+ unsigned int nchips;
|
||||||
|
+ unsigned int irq;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void __init fa_gpio_init(struct fa_gpio_data *data);
|
||||||
|
+
|
||||||
|
+#endif /* _FA_GPIO_H */
|
||||||
|
--- a/arch/arm/plat-fa/Kconfig
|
||||||
|
+++ b/arch/arm/plat-fa/Kconfig
|
||||||
|
@@ -1,5 +1,8 @@
|
||||||
|
if PLAT_FA
|
||||||
|
|
||||||
|
+config PLAT_FA_GPIO
|
||||||
|
+ def_bool n
|
||||||
|
+
|
||||||
|
config PLAT_FA_TIME
|
||||||
|
def_bool n
|
||||||
|
|
||||||
|
--- a/arch/arm/plat-fa/Makefile
|
||||||
|
+++ b/arch/arm/plat-fa/Makefile
|
||||||
|
@@ -4,6 +4,7 @@
|
||||||
|
|
||||||
|
obj-y :=
|
||||||
|
|
||||||
|
+obj-$(CONFIG_PLAT_FA_GPIO) += gpio.o
|
||||||
|
obj-$(CONFIG_PLAT_FA_TIME) += time.o
|
||||||
|
|
||||||
|
obj-m :=
|
|
@ -0,0 +1,458 @@
|
||||||
|
--- a/drivers/watchdog/Kconfig
|
||||||
|
+++ b/drivers/watchdog/Kconfig
|
||||||
|
@@ -364,6 +364,13 @@ config IMX2_WDT
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called imx2_wdt.
|
||||||
|
|
||||||
|
+config FA_WATCHDOG
|
||||||
|
+ tristate "Faraday watchdog"
|
||||||
|
+ depends on ARCH_GEMINI
|
||||||
|
+ help
|
||||||
|
+ Say Y here if you want support for the built-in watchdog timer
|
||||||
|
+ found in some Faraday FA526 based SoCs.
|
||||||
|
+
|
||||||
|
# AVR32 Architecture
|
||||||
|
|
||||||
|
config AT32AP700X_WDT
|
||||||
|
--- a/drivers/watchdog/Makefile
|
||||||
|
+++ b/drivers/watchdog/Makefile
|
||||||
|
@@ -52,6 +52,7 @@ obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3
|
||||||
|
obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
|
||||||
|
obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
|
||||||
|
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
|
||||||
|
+obj-$(CONFIG_FA_WATCHDOG) += fa_wdt.o
|
||||||
|
|
||||||
|
# AVR32 Architecture
|
||||||
|
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/watchdog/fa_wdt.c
|
||||||
|
@@ -0,0 +1,413 @@
|
||||||
|
+/*
|
||||||
|
+ * Watchdog driver for SoCs based on the Faraday FA526 core
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
|
||||||
|
+ * Copyright (C) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License version 2 as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/fs.h>
|
||||||
|
+#include <linux/notifier.h>
|
||||||
|
+#include <linux/reboot.h>
|
||||||
|
+#include <linux/uaccess.h>
|
||||||
|
+#include <linux/miscdevice.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/watchdog.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <linux/fa_wdt.h>
|
||||||
|
+
|
||||||
|
+#define FA_WDCOUNTER 0x0
|
||||||
|
+#define FA_WDLOAD 0x4
|
||||||
|
+#define FA_WDRESTART 0x8
|
||||||
|
+
|
||||||
|
+#define WDRESTART_MAGIC 0x5AB9
|
||||||
|
+
|
||||||
|
+#define FA_WDCR 0xC
|
||||||
|
+
|
||||||
|
+#define WDCR_CLOCK_5MHZ (1 << 4)
|
||||||
|
+#define WDCR_SYS_RST (1 << 1)
|
||||||
|
+#define WDCR_ENABLE (1 << 0)
|
||||||
|
+
|
||||||
|
+#define WDT_DEFAULT_TIMEOUT 13
|
||||||
|
+
|
||||||
|
+/* status bits */
|
||||||
|
+#define WDT_ACTIVE 0
|
||||||
|
+#define WDT_OK_TO_CLOSE 1
|
||||||
|
+
|
||||||
|
+static unsigned int timeout = WDT_DEFAULT_TIMEOUT;
|
||||||
|
+static int nowayout = WATCHDOG_NOWAYOUT;
|
||||||
|
+
|
||||||
|
+static DEFINE_SPINLOCK(fa_wdt_lock);
|
||||||
|
+
|
||||||
|
+static struct platform_device *fa_wdt_dev;
|
||||||
|
+
|
||||||
|
+struct fa_wdt_struct {
|
||||||
|
+ struct resource *res;
|
||||||
|
+ struct device *dev;
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ unsigned long status;
|
||||||
|
+ unsigned int clock;
|
||||||
|
+ unsigned int max_timeout;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct watchdog_info fa_wdt_info = {
|
||||||
|
+ .identity = "Faraday watchdog",
|
||||||
|
+ .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
|
||||||
|
+ WDIOF_SETTIMEOUT,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* Disable the watchdog. */
|
||||||
|
+static void fa_wdt_stop(struct fa_wdt_struct *fa_wdt)
|
||||||
|
+{
|
||||||
|
+ spin_lock(&fa_wdt_lock);
|
||||||
|
+
|
||||||
|
+ __raw_writel(0, fa_wdt->base + FA_WDCR);
|
||||||
|
+
|
||||||
|
+ clear_bit(WDT_ACTIVE, &fa_wdt->status);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&fa_wdt_lock);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Service the watchdog */
|
||||||
|
+static void fa_wdt_service(struct fa_wdt_struct *fa_wdt)
|
||||||
|
+{
|
||||||
|
+ __raw_writel(WDRESTART_MAGIC, fa_wdt->base + FA_WDRESTART);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Enable and reset the watchdog. */
|
||||||
|
+static void fa_wdt_start(struct fa_wdt_struct *fa_wdt)
|
||||||
|
+{
|
||||||
|
+ spin_lock(&fa_wdt_lock);
|
||||||
|
+
|
||||||
|
+ __raw_writel(timeout * fa_wdt->clock,
|
||||||
|
+ fa_wdt->base + FA_WDLOAD);
|
||||||
|
+
|
||||||
|
+ fa_wdt_service(fa_wdt);
|
||||||
|
+
|
||||||
|
+ /* set clock before enabling */
|
||||||
|
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
|
||||||
|
+ fa_wdt->base + FA_WDCR);
|
||||||
|
+
|
||||||
|
+ __raw_writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
|
||||||
|
+ fa_wdt->base + FA_WDCR);
|
||||||
|
+
|
||||||
|
+ set_bit(WDT_ACTIVE, &fa_wdt->status);
|
||||||
|
+
|
||||||
|
+ spin_unlock(&fa_wdt_lock);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Watchdog device is opened, and watchdog starts running. */
|
||||||
|
+static int fa_wdt_open(struct inode *inode, struct file *file)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
|
||||||
|
+
|
||||||
|
+ if (test_bit(WDT_ACTIVE, &fa_wdt->status))
|
||||||
|
+ return -EBUSY;
|
||||||
|
+
|
||||||
|
+ file->private_data = fa_wdt;
|
||||||
|
+
|
||||||
|
+ fa_wdt_start(fa_wdt);
|
||||||
|
+
|
||||||
|
+ return nonseekable_open(inode, file);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Close the watchdog device. */
|
||||||
|
+static int fa_wdt_close(struct inode *inode, struct file *file)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = file->private_data;
|
||||||
|
+
|
||||||
|
+ /* Disable the watchdog if possible */
|
||||||
|
+ if (test_bit(WDT_OK_TO_CLOSE, &fa_wdt->status))
|
||||||
|
+ fa_wdt_stop(fa_wdt);
|
||||||
|
+ else
|
||||||
|
+ dev_warn(fa_wdt->dev, "Device closed unexpectedly - timer will not stop\n");
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Handle commands from user-space. */
|
||||||
|
+static long fa_wdt_ioctl(struct file *file, unsigned int cmd,
|
||||||
|
+ unsigned long arg)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = file->private_data;
|
||||||
|
+
|
||||||
|
+ int value;
|
||||||
|
+
|
||||||
|
+ switch (cmd) {
|
||||||
|
+ case WDIOC_KEEPALIVE:
|
||||||
|
+ fa_wdt_service(fa_wdt);
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ case WDIOC_GETSUPPORT:
|
||||||
|
+ return copy_to_user((struct watchdog_info *)arg, &fa_wdt_info,
|
||||||
|
+ sizeof(fa_wdt_info)) ? -EFAULT : 0;
|
||||||
|
+
|
||||||
|
+ case WDIOC_SETTIMEOUT:
|
||||||
|
+ if (get_user(value, (int *)arg))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+
|
||||||
|
+ if ((value < 1) || (value > fa_wdt->max_timeout))
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ timeout = value;
|
||||||
|
+
|
||||||
|
+ /* restart wdt to use new timeout */
|
||||||
|
+ fa_wdt_stop(fa_wdt);
|
||||||
|
+ fa_wdt_start(fa_wdt);
|
||||||
|
+
|
||||||
|
+ /* Fall through */
|
||||||
|
+ case WDIOC_GETTIMEOUT:
|
||||||
|
+ return put_user(timeout, (int *)arg);
|
||||||
|
+
|
||||||
|
+ case WDIOC_GETTIMELEFT:
|
||||||
|
+ value = __raw_readl(fa_wdt->base + FA_WDCOUNTER);
|
||||||
|
+ return put_user(value / fa_wdt->clock, (int *)arg);
|
||||||
|
+
|
||||||
|
+ default:
|
||||||
|
+ return -ENOTTY;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Refresh the watchdog whenever device is written to. */
|
||||||
|
+static ssize_t fa_wdt_write(struct file *file, const char *data,
|
||||||
|
+ size_t len, loff_t *ppos)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = file->private_data;
|
||||||
|
+
|
||||||
|
+ if (len) {
|
||||||
|
+ if (!nowayout) {
|
||||||
|
+ size_t i;
|
||||||
|
+
|
||||||
|
+ clear_bit(WDT_OK_TO_CLOSE, &fa_wdt->status);
|
||||||
|
+ for (i = 0; i != len; i++) {
|
||||||
|
+ char c;
|
||||||
|
+
|
||||||
|
+ if (get_user(c, data + i))
|
||||||
|
+ return -EFAULT;
|
||||||
|
+ if (c == 'V')
|
||||||
|
+ set_bit(WDT_OK_TO_CLOSE,
|
||||||
|
+ &fa_wdt->status);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ fa_wdt_service(fa_wdt);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_wdt_notify_sys(struct notifier_block *this,
|
||||||
|
+ unsigned long code, void *unused)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(fa_wdt_dev);
|
||||||
|
+
|
||||||
|
+ if (code == SYS_DOWN || code == SYS_HALT)
|
||||||
|
+ fa_wdt_stop(fa_wdt);
|
||||||
|
+
|
||||||
|
+ return NOTIFY_DONE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct notifier_block fa_wdt_notifier = {
|
||||||
|
+ .notifier_call = fa_wdt_notify_sys,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct file_operations fa_wdt_fops = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .llseek = no_llseek,
|
||||||
|
+ .unlocked_ioctl = fa_wdt_ioctl,
|
||||||
|
+ .open = fa_wdt_open,
|
||||||
|
+ .release = fa_wdt_close,
|
||||||
|
+ .write = fa_wdt_write,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct miscdevice fa_wdt_miscdev = {
|
||||||
|
+ .minor = WATCHDOG_MINOR,
|
||||||
|
+ .name = "watchdog",
|
||||||
|
+ .fops = &fa_wdt_fops,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void fa_wdt_shutdown(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ fa_wdt_stop(fa_wdt);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_wdt_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+ int res_size;
|
||||||
|
+ struct resource *res;
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ struct fa_wdt_struct *fa_wdt;
|
||||||
|
+ struct fa_wdt_platform_data *pdata;
|
||||||
|
+
|
||||||
|
+ pdata = pdev->dev.platform_data;
|
||||||
|
+ if (!pdata) {
|
||||||
|
+ dev_err(&pdev->dev, "no platform data specified\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!pdata->clock) {
|
||||||
|
+ dev_err(&pdev->dev, "invalid clock value\n");
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_err(&pdev->dev, "can't get device resources\n");
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ res_size = resource_size(res);
|
||||||
|
+ if (!request_mem_region(res->start, res_size, res->name)) {
|
||||||
|
+ dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
|
||||||
|
+ res_size, res->start);
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ base = ioremap(res->start, res_size);
|
||||||
|
+ if (!base) {
|
||||||
|
+ dev_err(&pdev->dev, "ioremap failed\n");
|
||||||
|
+ ret = -EIO;
|
||||||
|
+ goto fail0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ fa_wdt = kzalloc(sizeof(struct fa_wdt_struct), GFP_KERNEL);
|
||||||
|
+ if (!fa_wdt) {
|
||||||
|
+ dev_err(&pdev->dev, "can't allocate interface\n");
|
||||||
|
+ ret = -ENOMEM;
|
||||||
|
+ goto fail1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Setup fa_wdt driver structure */
|
||||||
|
+ fa_wdt->base = base;
|
||||||
|
+ fa_wdt->res = res;
|
||||||
|
+ fa_wdt->dev = &pdev->dev;
|
||||||
|
+ fa_wdt->clock = pdata->clock;
|
||||||
|
+ fa_wdt->max_timeout = 0xffffffffU / pdata->clock;
|
||||||
|
+
|
||||||
|
+ /* Set up platform driver data */
|
||||||
|
+ platform_set_drvdata(pdev, fa_wdt);
|
||||||
|
+ fa_wdt_dev = pdev;
|
||||||
|
+
|
||||||
|
+ if (fa_wdt_miscdev.parent) {
|
||||||
|
+ ret = -EBUSY;
|
||||||
|
+ goto fail2;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ret = register_reboot_notifier(&fa_wdt_notifier);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto fail2;
|
||||||
|
+
|
||||||
|
+ fa_wdt_miscdev.parent = &pdev->dev;
|
||||||
|
+
|
||||||
|
+ ret = misc_register(&fa_wdt_miscdev);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto fail3;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+fail3:
|
||||||
|
+ unregister_reboot_notifier(&fa_wdt_notifier);
|
||||||
|
+fail2:
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+ kfree(fa_wdt);
|
||||||
|
+fail1:
|
||||||
|
+ iounmap(base);
|
||||||
|
+fail0:
|
||||||
|
+ release_mem_region(res->start, res_size);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_wdt_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+ misc_deregister(&fa_wdt_miscdev);
|
||||||
|
+ unregister_reboot_notifier(&fa_wdt_notifier);
|
||||||
|
+ fa_wdt_dev = NULL;
|
||||||
|
+ iounmap(fa_wdt->base);
|
||||||
|
+ release_mem_region(fa_wdt->res->start, resource_size(fa_wdt->res));
|
||||||
|
+
|
||||||
|
+ kfree(fa_wdt);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef CONFIG_PM
|
||||||
|
+static int fa_wdt_suspend(struct platform_device *pdev, pm_message_t message)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
|
||||||
|
+ unsigned int reg;
|
||||||
|
+
|
||||||
|
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
|
||||||
|
+ reg &= ~(WDCR_WDENABLE);
|
||||||
|
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int fa_wdt_resume(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct fa_wdt_struct *fa_wdt = platform_get_drvdata(pdev);
|
||||||
|
+ unsigned int reg;
|
||||||
|
+
|
||||||
|
+ if (fa_wdt->status) {
|
||||||
|
+ reg = __raw_readw(fa_wdt->base + FA_WDCR);
|
||||||
|
+ reg |= WDCR_WDENABLE;
|
||||||
|
+ __raw_writel(reg, fa_wdt->base + FA_WDCR);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+#else
|
||||||
|
+#define fa_wdt_suspend NULL
|
||||||
|
+#define fa_wdt_resume NULL
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static struct platform_driver fa_wdt_driver = {
|
||||||
|
+ .probe = fa_wdt_probe,
|
||||||
|
+ .remove = fa_wdt_remove,
|
||||||
|
+ .shutdown = fa_wdt_shutdown,
|
||||||
|
+ .suspend = fa_wdt_suspend,
|
||||||
|
+ .resume = fa_wdt_resume,
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "fa-wdt",
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init fa_wdt_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_probe(&fa_wdt_driver, fa_wdt_probe);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit fa_wdt_exit(void)
|
||||||
|
+{
|
||||||
|
+ platform_driver_unregister(&fa_wdt_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(fa_wdt_init);
|
||||||
|
+module_exit(fa_wdt_exit);
|
||||||
|
+
|
||||||
|
+module_param(timeout, uint, 0);
|
||||||
|
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
|
||||||
|
+
|
||||||
|
+module_param(nowayout, int, 0);
|
||||||
|
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Paulius Zaleckas");
|
||||||
|
+MODULE_AUTHOR("Gabor Juhos");
|
||||||
|
+MODULE_DESCRIPTION("Watchdog driver for Faraday FA526 based SoCs");
|
||||||
|
+MODULE_LICENSE("GPL v2");
|
||||||
|
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
|
||||||
|
+MODULE_ALIAS("platform:fa-wdt");
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/include/linux/fa_wdt.h
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+/*
|
||||||
|
+ * Platform data definition for the Faraday watchdog driver
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _FA_WDT_H
|
||||||
|
+#define _FA_WDT_H
|
||||||
|
+
|
||||||
|
+struct fa_wdt_platform_data {
|
||||||
|
+ unsigned int clock;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#endif /* _FA_WDT_H */
|
||||||
|
+
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,103 @@
|
||||||
|
--- a/arch/arm/mach-cns21xx/common.h
|
||||||
|
+++ b/arch/arm/mach-cns21xx/common.h
|
||||||
|
@@ -16,4 +16,7 @@ void cns21xx_init_irq(void);
|
||||||
|
|
||||||
|
extern struct sys_timer cns21xx_timer;
|
||||||
|
|
||||||
|
+int cns21xx_register_uart0(void);
|
||||||
|
+int cns21xx_register_uart1(void);
|
||||||
|
+
|
||||||
|
#endif /* _MACH_CNS21XX_COMMON_H */
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/devices.c
|
||||||
|
@@ -0,0 +1,79 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/serial_8250.h>
|
||||||
|
+
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/cns21xx_misc.h>
|
||||||
|
+
|
||||||
|
+#define CNS21XX_UART_CLOCK 24000000
|
||||||
|
+
|
||||||
|
+#define CNS21XX_UART_FLAGS (UPF_SKIP_TEST | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST)
|
||||||
|
+
|
||||||
|
+static struct plat_serial8250_port cns21xx_uart0_data[] = {
|
||||||
|
+ {
|
||||||
|
+ .mapbase = CNS21XX_UART0_BASE,
|
||||||
|
+ .membase = (void *) CNS21XX_UART0_BASE_VIRT,
|
||||||
|
+ .irq = CNS21XX_IRQ_UART0,
|
||||||
|
+ .uartclk = CNS21XX_UART_CLOCK,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ .flags = CNS21XX_UART_FLAGS,
|
||||||
|
+ }, {
|
||||||
|
+ /* terminating entry */
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_uart0_device = {
|
||||||
|
+ .name = "serial8250",
|
||||||
|
+ .id = PLAT8250_DEV_PLATFORM,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = cns21xx_uart0_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int __init cns21xx_register_uart0(void)
|
||||||
|
+{
|
||||||
|
+ return platform_device_register(&cns21xx_uart0_device);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct plat_serial8250_port cns21xx_uart1_data[] = {
|
||||||
|
+ {
|
||||||
|
+ .mapbase = CNS21XX_UART1_BASE,
|
||||||
|
+ .membase = (void *) CNS21XX_UART1_BASE_VIRT,
|
||||||
|
+ .irq = CNS21XX_IRQ_UART1,
|
||||||
|
+ .uartclk = CNS21XX_UART_CLOCK,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ .flags = CNS21XX_UART_FLAGS,
|
||||||
|
+ }, {
|
||||||
|
+ /* terminating entry */
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_uart1_device = {
|
||||||
|
+ .name = "serial8250",
|
||||||
|
+ .id = PLAT8250_DEV_PLATFORM1,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = cns21xx_uart1_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int __init cns21xx_register_uart1(void)
|
||||||
|
+{
|
||||||
|
+ HAL_MISC_ENABLE_UART1_PINS();
|
||||||
|
+ return platform_device_register(&cns21xx_uart1_device);
|
||||||
|
+}
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
# Object file lists.
|
||||||
|
|
||||||
|
-obj-y := core.o irq.o mm.o time.o
|
||||||
|
+obj-y := core.o devices.o irq.o mm.o time.o
|
||||||
|
|
||||||
|
# machine specific files
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -378,6 +378,8 @@ config ARCH_CNS21XX
|
||||||
|
select CPU_FA526
|
||||||
|
select PLAT_FA
|
||||||
|
select PLAT_FA_TIME
|
||||||
|
+ select PLAT_FA_GPIO
|
||||||
|
+ select ARCH_REQUIRE_GPIOLIB
|
||||||
|
select ARM_L1_CACHE_SHIFT_4
|
||||||
|
help
|
||||||
|
Support for Cavium Networks CNS21xx family.
|
||||||
|
--- a/arch/arm/mach-cns21xx/common.h
|
||||||
|
+++ b/arch/arm/mach-cns21xx/common.h
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
void cns21xx_restart(char mode, const char *cmd);
|
||||||
|
void cns21xx_map_io(void);
|
||||||
|
void cns21xx_init_irq(void);
|
||||||
|
+void cns21xx_gpio_init(void);
|
||||||
|
|
||||||
|
extern struct sys_timer cns21xx_timer;
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/gpio.c
|
||||||
|
@@ -0,0 +1,45 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <plat/gpio.h>
|
||||||
|
+
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+
|
||||||
|
+static struct fa_gpio_chip cns21xx_gpio_chips[] = {
|
||||||
|
+ {
|
||||||
|
+ .gpio_chip = {
|
||||||
|
+ .label = "GPIOA",
|
||||||
|
+ .base = 0,
|
||||||
|
+ .ngpio = 32,
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ .map_base = CNS21XX_GPIOA_BASE,
|
||||||
|
+ .irq_base = CNS21XX_GPIO_IRQ_BASE,
|
||||||
|
+ }, {
|
||||||
|
+ .gpio_chip = {
|
||||||
|
+ .label = "GPIOB",
|
||||||
|
+ .base = 32,
|
||||||
|
+ .ngpio = 32,
|
||||||
|
+ },
|
||||||
|
+
|
||||||
|
+ .map_base = CNS21XX_GPIOB_BASE,
|
||||||
|
+ .irq_base = CNS21XX_GPIO_IRQ_BASE + 32,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct fa_gpio_data cns21xx_gpio_data = {
|
||||||
|
+ .chips = cns21xx_gpio_chips,
|
||||||
|
+ .nchips = ARRAY_SIZE(cns21xx_gpio_chips),
|
||||||
|
+ .irq = CNS21XX_IRQ_GPIO,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void __init cns21xx_gpio_init(void)
|
||||||
|
+{
|
||||||
|
+ fa_gpio_init(&cns21xx_gpio_data);
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/include/mach/gpio.h
|
||||||
|
@@ -0,0 +1,2 @@
|
||||||
|
+/* empty */
|
||||||
|
+
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
# Object file lists.
|
||||||
|
|
||||||
|
-obj-y := core.o devices.o irq.o mm.o time.o
|
||||||
|
+obj-y := core.o devices.o gpio.o irq.o mm.o time.o
|
||||||
|
|
||||||
|
# machine specific files
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
--- a/drivers/usb/host/ohci-hcd.c
|
||||||
|
+++ b/drivers/usb/host/ohci-hcd.c
|
||||||
|
@@ -691,6 +691,9 @@ retry:
|
||||||
|
|
||||||
|
periodic_reinit (ohci);
|
||||||
|
|
||||||
|
+ if (ohci->flags & OHCI_QUIRK_INIT_FMINTERVAL)
|
||||||
|
+ ohci_writel (ohci, ohci->fminterval, &ohci->regs->fminterval);
|
||||||
|
+
|
||||||
|
/* some OHCI implementations are finicky about how they init.
|
||||||
|
* bogus values here mean not even enumeration could work.
|
||||||
|
*/
|
||||||
|
@@ -1186,6 +1189,11 @@ MODULE_LICENSE ("GPL");
|
||||||
|
#define PLATFORM_DRIVER ohci_hcd_tilegx_driver
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef CONFIG_ARCH_CNS21XX
|
||||||
|
+#include "ohci-cns21xx.c"
|
||||||
|
+#define PLATFORM_DRIVER ohci_cns21xx_driver
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
|
||||||
|
#include "ohci-platform.c"
|
||||||
|
#define OHCI_PLATFORM_DRIVER ohci_platform_driver
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/usb/host/ohci-cns21xx.c
|
||||||
|
@@ -0,0 +1,178 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+
|
||||||
|
+#define DRIVER_NAME "cns21xx-ohci"
|
||||||
|
+
|
||||||
|
+static int cns21xx_ohci_start(struct usb_hcd *hcd)
|
||||||
|
+{
|
||||||
|
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = ohci_init(ohci);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = ohci_run(ohci);
|
||||||
|
+ if (ret) {
|
||||||
|
+ ohci_err(ohci, "can't start %s",
|
||||||
|
+ ohci_to_hcd(ohci)->self.bus_name);
|
||||||
|
+ goto err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+err:
|
||||||
|
+ ohci_stop(hcd);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct hc_driver ohci_cns21xx_hc_driver = {
|
||||||
|
+ .description = hcd_name,
|
||||||
|
+ .product_desc = "cns21xx-ohci",
|
||||||
|
+ .hcd_priv_size = sizeof(struct ohci_hcd),
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * generic hardware linkage
|
||||||
|
+ */
|
||||||
|
+ .irq = ohci_irq,
|
||||||
|
+ .flags = HCD_USB11 | HCD_MEMORY,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * basic lifecycle operations
|
||||||
|
+ */
|
||||||
|
+ .start = cns21xx_ohci_start,
|
||||||
|
+ .stop = ohci_stop,
|
||||||
|
+ .shutdown = ohci_shutdown,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * managing i/o requests and associated device resources
|
||||||
|
+ */
|
||||||
|
+ .urb_enqueue = ohci_urb_enqueue,
|
||||||
|
+ .urb_dequeue = ohci_urb_dequeue,
|
||||||
|
+ .endpoint_disable = ohci_endpoint_disable,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * scheduling support
|
||||||
|
+ */
|
||||||
|
+ .get_frame_number = ohci_get_frame,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * root hub support
|
||||||
|
+ */
|
||||||
|
+ .hub_status_data = ohci_hub_status_data,
|
||||||
|
+ .hub_control = ohci_hub_control,
|
||||||
|
+ .start_port_reset = ohci_start_port_reset,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void cns21xx_ohci_init_hc(void)
|
||||||
|
+{
|
||||||
|
+ void __iomem *base = (void __iomem *) CNS21XX_OHCI_CONFIG_BASE_VIRT;
|
||||||
|
+
|
||||||
|
+ __raw_writel(0x146, base + 0x04);
|
||||||
|
+ __raw_writel(0x200, base + 0x44);
|
||||||
|
+ msleep(100);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ohci_cns21xx_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct usb_hcd *hcd;
|
||||||
|
+ struct resource *res;
|
||||||
|
+ struct ohci_hcd *ohci;
|
||||||
|
+ int irq;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (usb_disabled())
|
||||||
|
+ return -ENODEV;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+ irq = res->start;
|
||||||
|
+
|
||||||
|
+ hcd = usb_create_hcd(&ohci_cns21xx_hc_driver, &pdev->dev,
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ if (!hcd)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ ret = -ENODEV;
|
||||||
|
+ goto err_put_hcd;
|
||||||
|
+ }
|
||||||
|
+ hcd->rsrc_start = res->start;
|
||||||
|
+ hcd->rsrc_len = res->end - res->start + 1;
|
||||||
|
+
|
||||||
|
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||||
|
+ dev_dbg(&pdev->dev, "controller already in use\n");
|
||||||
|
+ ret = -EBUSY;
|
||||||
|
+ goto err_put_hcd;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+ if (!hcd->regs) {
|
||||||
|
+ dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||||
|
+ ret = -EFAULT;
|
||||||
|
+ goto err_release_region;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cns21xx_ohci_init_hc();
|
||||||
|
+
|
||||||
|
+ ohci = hcd_to_ohci(hcd);
|
||||||
|
+ ohci->flags |= OHCI_QUIRK_INIT_FMINTERVAL;
|
||||||
|
+ ohci_hcd_init(ohci);
|
||||||
|
+
|
||||||
|
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto err_unmap;
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, hcd);
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+err_unmap:
|
||||||
|
+ iounmap(hcd->regs);
|
||||||
|
+err_release_region:
|
||||||
|
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+err_put_hcd:
|
||||||
|
+ usb_put_hcd(hcd);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ohci_cns21xx_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ usb_remove_hcd(hcd);
|
||||||
|
+ iounmap(hcd->regs);
|
||||||
|
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+ usb_put_hcd(hcd);
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct platform_driver ohci_cns21xx_driver = {
|
||||||
|
+ .probe = ohci_cns21xx_probe,
|
||||||
|
+ .remove = ohci_cns21xx_remove,
|
||||||
|
+ .shutdown = usb_hcd_platform_shutdown,
|
||||||
|
+ .driver = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .name = DRIVER_NAME,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||||
|
--- a/drivers/usb/host/ohci.h
|
||||||
|
+++ b/drivers/usb/host/ohci.h
|
||||||
|
@@ -405,6 +405,7 @@ struct ohci_hcd {
|
||||||
|
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
|
||||||
|
#define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/
|
||||||
|
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
|
||||||
|
+#define OHCI_QUIRK_INIT_FMINTERVAL 0x1000 /* fminterval must be initialized */
|
||||||
|
// there are also chip quirks/bugs in init logic
|
||||||
|
|
||||||
|
struct work_struct nec_work; /* Worker for NEC quirk */
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -381,6 +381,7 @@ config ARCH_CNS21XX
|
||||||
|
select PLAT_FA_GPIO
|
||||||
|
select ARCH_REQUIRE_GPIOLIB
|
||||||
|
select ARM_L1_CACHE_SHIFT_4
|
||||||
|
+ select USB_ARCH_HAS_OHCI
|
||||||
|
help
|
||||||
|
Support for Cavium Networks CNS21xx family.
|
||||||
|
|
|
@ -0,0 +1,214 @@
|
||||||
|
--- a/drivers/usb/host/ehci-hcd.c
|
||||||
|
+++ b/drivers/usb/host/ehci-hcd.c
|
||||||
|
@@ -1342,6 +1342,11 @@ MODULE_LICENSE ("GPL");
|
||||||
|
#define PLATFORM_DRIVER ehci_hcd_sead3_driver
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef CONFIG_ARCH_CNS21XX
|
||||||
|
+#include "ehci-cns21xx.c"
|
||||||
|
+#define PLATFORM_DRIVER ehci_cns21xx_driver
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if !IS_ENABLED(CONFIG_USB_EHCI_PCI) && \
|
||||||
|
!IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \
|
||||||
|
!IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/usb/host/ehci-cns21xx.c
|
||||||
|
@@ -0,0 +1,187 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/irq.h>
|
||||||
|
+
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+
|
||||||
|
+#define DRIVER_NAME "cns21xx-ehci"
|
||||||
|
+
|
||||||
|
+static int cns21xx_ehci_reset(struct usb_hcd *hcd)
|
||||||
|
+{
|
||||||
|
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = ehci_halt(ehci);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ret = ehci_init(hcd);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
+ ehci_reset(ehci);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static const struct hc_driver ehci_cns21xx_hc_driver = {
|
||||||
|
+ .description = hcd_name,
|
||||||
|
+ .product_desc = DRIVER_NAME,
|
||||||
|
+ .hcd_priv_size = sizeof(struct ehci_hcd),
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * generic hardware linkage
|
||||||
|
+ */
|
||||||
|
+ .irq = ehci_irq,
|
||||||
|
+ .flags = HCD_MEMORY | HCD_USB2,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * basic lifecycle operations
|
||||||
|
+ */
|
||||||
|
+ .reset = cns21xx_ehci_reset,
|
||||||
|
+ .start = ehci_run,
|
||||||
|
+ .stop = ehci_stop,
|
||||||
|
+ .shutdown = ehci_shutdown,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * managing i/o requests and associated device resources
|
||||||
|
+ */
|
||||||
|
+ .urb_enqueue = ehci_urb_enqueue,
|
||||||
|
+ .urb_dequeue = ehci_urb_dequeue,
|
||||||
|
+ .endpoint_disable = ehci_endpoint_disable,
|
||||||
|
+ .endpoint_reset = ehci_endpoint_reset,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * scheduling support
|
||||||
|
+ */
|
||||||
|
+ .get_frame_number = ehci_get_frame,
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * root hub support
|
||||||
|
+ */
|
||||||
|
+ .hub_status_data = ehci_hub_status_data,
|
||||||
|
+ .hub_control = ehci_hub_control,
|
||||||
|
+ .relinquish_port = ehci_relinquish_port,
|
||||||
|
+ .port_handed_over = ehci_port_handed_over,
|
||||||
|
+
|
||||||
|
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void cns21xx_ehci_init_hc(void)
|
||||||
|
+{
|
||||||
|
+ void __iomem *base = (void __iomem *) CNS21XX_EHCI_CONFIG_BASE_VIRT;
|
||||||
|
+
|
||||||
|
+ __raw_writel(0x106, base + 0x04);
|
||||||
|
+ __raw_writel((3 << 5) | 0x2000, base + 0x40);
|
||||||
|
+ msleep(100);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ehci_cns21xx_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct usb_hcd *hcd;
|
||||||
|
+ struct ehci_hcd *ehci;
|
||||||
|
+ struct resource *res;
|
||||||
|
+ int irq;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ if (usb_disabled())
|
||||||
|
+ return -ENODEV;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_dbg(&pdev->dev, "no IRQ specified for %s\n",
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+ irq = res->start;
|
||||||
|
+
|
||||||
|
+ hcd = usb_create_hcd(&ehci_cns21xx_hc_driver, &pdev->dev,
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ if (!hcd)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_dbg(&pdev->dev, "no base address specified for %s\n",
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ ret = -ENODEV;
|
||||||
|
+ goto err_put_hcd;
|
||||||
|
+ }
|
||||||
|
+ hcd->rsrc_start = res->start;
|
||||||
|
+ hcd->rsrc_len = res->end - res->start + 1;
|
||||||
|
+
|
||||||
|
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||||
|
+ dev_dbg(&pdev->dev, "controller already in use\n");
|
||||||
|
+ ret = -EBUSY;
|
||||||
|
+ goto err_put_hcd;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+ if (!hcd->regs) {
|
||||||
|
+ dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||||
|
+ ret = -EFAULT;
|
||||||
|
+ goto err_release_region;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cns21xx_ehci_init_hc();
|
||||||
|
+
|
||||||
|
+ ehci = hcd_to_ehci(hcd);
|
||||||
|
+
|
||||||
|
+ ehci->caps = hcd->regs;
|
||||||
|
+ ehci->regs = hcd->regs +
|
||||||
|
+ HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
|
||||||
|
+ dbg_hcs_params(ehci, "reset");
|
||||||
|
+ dbg_hcc_params(ehci, "reset");
|
||||||
|
+
|
||||||
|
+ /* cache this readonly data; minimize chip reads */
|
||||||
|
+ ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||||
|
+ ehci->sbrn = 0x20;
|
||||||
|
+
|
||||||
|
+ ret = usb_add_hcd(hcd, CNS21XX_IRQ_EHCI, IRQF_DISABLED);
|
||||||
|
+ if (ret)
|
||||||
|
+ goto err_unmap;
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, hcd);
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+err_unmap:
|
||||||
|
+ iounmap(hcd->regs);
|
||||||
|
+err_release_region:
|
||||||
|
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+err_put_hcd:
|
||||||
|
+ usb_put_hcd(hcd);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int ehci_cns21xx_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ usb_remove_hcd(hcd);
|
||||||
|
+ iounmap(hcd->regs);
|
||||||
|
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||||
|
+ usb_put_hcd(hcd);
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct platform_driver ehci_cns21xx_driver = {
|
||||||
|
+ .probe = ehci_cns21xx_probe,
|
||||||
|
+ .remove = ehci_cns21xx_remove,
|
||||||
|
+ .shutdown = usb_hcd_platform_shutdown,
|
||||||
|
+ .driver = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .name = DRIVER_NAME,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -382,6 +382,7 @@ config ARCH_CNS21XX
|
||||||
|
select ARCH_REQUIRE_GPIOLIB
|
||||||
|
select ARM_L1_CACHE_SHIFT_4
|
||||||
|
select USB_ARCH_HAS_OHCI
|
||||||
|
+ select USB_ARCH_HAS_EHCI
|
||||||
|
help
|
||||||
|
Support for Cavium Networks CNS21xx family.
|
||||||
|
|
|
@ -0,0 +1,578 @@
|
||||||
|
--- a/include/linux/spi/spi.h
|
||||||
|
+++ b/include/linux/spi/spi.h
|
||||||
|
@@ -510,6 +510,8 @@ struct spi_transfer {
|
||||||
|
u16 delay_usecs;
|
||||||
|
u32 speed_hz;
|
||||||
|
|
||||||
|
+ unsigned last_in_message_list;
|
||||||
|
+
|
||||||
|
struct list_head transfer_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
--- a/drivers/spi/Kconfig
|
||||||
|
+++ b/drivers/spi/Kconfig
|
||||||
|
@@ -186,6 +186,14 @@ config SPI_GPIO_OLD
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
+config SPI_CNS21XX
|
||||||
|
+ tristate "Cavium Netowrks CNS21xx SPI master"
|
||||||
|
+ depends on ARCH_CNS21XX && EXPERIMENTAL
|
||||||
|
+ select SPI_BITBANG
|
||||||
|
+ help
|
||||||
|
+ This driver supports the buil-in SPI controller of the Cavium Networks
|
||||||
|
+ CNS21xx SoCs.
|
||||||
|
+
|
||||||
|
config SPI_IMX
|
||||||
|
tristate "Freescale i.MX SPI controllers"
|
||||||
|
depends on ARCH_MXC
|
||||||
|
--- a/drivers/spi/Makefile
|
||||||
|
+++ b/drivers/spi/Makefile
|
||||||
|
@@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfi
|
||||||
|
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
|
||||||
|
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
|
||||||
|
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
|
||||||
|
+obj-$(CONFIG_SPI_CNS21XX) += spi-cns21xx.o
|
||||||
|
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
|
||||||
|
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
|
||||||
|
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
|
||||||
|
--- a/drivers/spi/spi-bitbang.c
|
||||||
|
+++ b/drivers/spi/spi-bitbang.c
|
||||||
|
@@ -328,6 +328,13 @@ static void bitbang_work(struct work_str
|
||||||
|
*/
|
||||||
|
if (!m->is_dma_mapped)
|
||||||
|
t->rx_dma = t->tx_dma = 0;
|
||||||
|
+
|
||||||
|
+ if (t->transfer_list.next == &m->transfers) {
|
||||||
|
+ t->last_in_message_list = 1;
|
||||||
|
+ } else {
|
||||||
|
+ t->last_in_message_list = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
status = bitbang->txrx_bufs(spi, t);
|
||||||
|
}
|
||||||
|
if (status > 0)
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/spi/spi-cns21xx.c
|
||||||
|
@@ -0,0 +1,521 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
+#include <linux/workqueue.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/spi/spi_bitbang.h>
|
||||||
|
+
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+
|
||||||
|
+#define DRIVER_NAME "cns21xx-spi"
|
||||||
|
+
|
||||||
|
+#ifdef CONFIG_CNS21XX_SPI_DEBUG
|
||||||
|
+#define DBG(fmt, args...) pr_info("[CNS21XX_SPI_DEBUG]" fmt, ## args)
|
||||||
|
+#else
|
||||||
|
+#define DBG(fmt, args...) do {} while (0)
|
||||||
|
+#endif /* CNS21XX_SPI_DEBUG */
|
||||||
|
+
|
||||||
|
+#define SPI_REG_CFG 0x40
|
||||||
|
+#define SPI_REG_STAT 0x44
|
||||||
|
+#define SPI_REG_BIT_RATE 0x48
|
||||||
|
+#define SPI_REG_TX_CTRL 0x4c
|
||||||
|
+#define SPI_REG_TX_DATA 0x50
|
||||||
|
+#define SPI_REG_RX_CTRL 0x54
|
||||||
|
+#define SPI_REG_RX_DATA 0x58
|
||||||
|
+#define SPI_REG_FIFO_TX_CFG 0x5c
|
||||||
|
+#define SPI_REG_FIFO_TX_CTRL 0x60
|
||||||
|
+#define SPI_REG_FIFO_RX_CFG 0x64
|
||||||
|
+#define SPI_REG_INTR_STAT 0x68
|
||||||
|
+#define SPI_REG_INTR_ENA 0x6c
|
||||||
|
+
|
||||||
|
+#define CFG_SPI_EN BIT(31)
|
||||||
|
+#define CFG_SPI_CLKPOL BIT(14)
|
||||||
|
+#define CFG_SPI_CLKPHA BIT(13)
|
||||||
|
+#define CFG_SPI_MASTER_EN BIT(11)
|
||||||
|
+#define CFG_SPI_CHAR_LEN_M 0x3
|
||||||
|
+#define CFG_SPI_CHAR_LEN_8BITS 0
|
||||||
|
+#define CFG_SPI_CHAR_LEN_16BITS 1
|
||||||
|
+#define CFG_SPI_CHAR_LEN_24BITS 2
|
||||||
|
+#define CFG_SPI_CHAR_LEN_32BITS 3
|
||||||
|
+
|
||||||
|
+#define STAT_SPI_BUSY_STA BIT(1)
|
||||||
|
+
|
||||||
|
+#define BIT_RATE_DIV_1 0
|
||||||
|
+#define BIT_RATE_DIV_2 1
|
||||||
|
+#define BIT_RATE_DIV_4 2
|
||||||
|
+#define BIT_RATE_DIV_8 3
|
||||||
|
+#define BIT_RATE_DIV_16 4
|
||||||
|
+#define BIT_RATE_DIV_32 5
|
||||||
|
+#define BIT_RATE_DIV_64 6
|
||||||
|
+#define BIT_RATE_DIV_128 7
|
||||||
|
+
|
||||||
|
+#define TX_CTRL_SPI_TXDAT_EOF BIT(2)
|
||||||
|
+#define TX_CTRL_SPI_TXCH_NUM_M 0x3
|
||||||
|
+#define TX_CTRL_CLEAR_MASK (TX_CTRL_SPI_TXDAT_EOF | \
|
||||||
|
+ TX_CTRL_SPI_TXCH_NUM_M)
|
||||||
|
+
|
||||||
|
+#define RX_CTRL_SPI_RXDAT_EOF BIT(2)
|
||||||
|
+#define RX_CTRL_SPI_RXCH_NUM_M 0x3
|
||||||
|
+
|
||||||
|
+#define INTR_STAT_SPI_TXBF_UNRN_FG BIT(7)
|
||||||
|
+#define INTR_STAT_SPI_RXBF_OVRN_FG BIT(6)
|
||||||
|
+#define INTR_STAT_SPI_TXFF_UNRN_FG BIT(5)
|
||||||
|
+#define INTR_STAT_SPI_RXFF_OVRN_FG BIT(4)
|
||||||
|
+#define INTR_STAT_SPI_TXBUF_FG BIT(3)
|
||||||
|
+#define INTR_STAT_SPI_RXBUF_FG BIT(2)
|
||||||
|
+#define INTR_STAT_SPI_TXFF_FG BIT(1)
|
||||||
|
+#define INTR_STAT_SPI_RXFF_FG BIT(0)
|
||||||
|
+
|
||||||
|
+#define INTR_STAT_CLEAR_MASK (INTR_STAT_SPI_TXBF_UNRN_FG | \
|
||||||
|
+ INTR_STAT_SPI_RXBF_OVRN_FG | \
|
||||||
|
+ INTR_STAT_SPI_TXFF_UNRN_FG | \
|
||||||
|
+ INTR_STAT_SPI_RXFF_OVRN_FG)
|
||||||
|
+
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_THRED_M 0x3
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_THRED_S 4
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_THRED_2 0
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_THRED_4 1
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_THRED_6 0
|
||||||
|
+#define FIFO_TX_CFG_SPI_TXFF_STATUS_M 0xf
|
||||||
|
+
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_THRED_M 0x3
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_THRED_S 4
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_THRED_2 0
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_THRED_4 1
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_THRED_6 0
|
||||||
|
+#define FIFO_RX_CFG_SPI_RXFF_STATUS_M 0xf
|
||||||
|
+
|
||||||
|
+#define CNS21XX_SPI_NUM_BIT_RATES 8
|
||||||
|
+
|
||||||
|
+struct cns21xx_spi {
|
||||||
|
+ struct spi_bitbang bitbang;
|
||||||
|
+
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct device *dev;
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ struct resource *region;
|
||||||
|
+
|
||||||
|
+ unsigned freq_max;
|
||||||
|
+ unsigned freq_min;
|
||||||
|
+
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static inline struct cns21xx_spi *to_hw(struct spi_device *spi)
|
||||||
|
+{
|
||||||
|
+ return spi_master_get_devdata(spi->master);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u32 cns21xx_spi_rr(struct cns21xx_spi *hw, unsigned int reg)
|
||||||
|
+{
|
||||||
|
+ return __raw_readl(hw->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void cns21xx_spi_wr(struct cns21xx_spi *hw, u32 val,
|
||||||
|
+ unsigned int reg)
|
||||||
|
+{
|
||||||
|
+ __raw_writel(val, hw->base + reg);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define CNS21XX_SPI_RETRY_COUNT 100
|
||||||
|
+static inline int cns21xx_spi_wait(struct cns21xx_spi *hw, unsigned int reg,
|
||||||
|
+ u32 mask, u32 val)
|
||||||
|
+{
|
||||||
|
+ int retry_cnt = 0;
|
||||||
|
+
|
||||||
|
+ do {
|
||||||
|
+ if ((cns21xx_spi_rr(hw, reg) & mask) == val)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ if (++retry_cnt > CNS21XX_SPI_RETRY_COUNT) {
|
||||||
|
+ dev_err(hw->dev, "timeout waiting on register %02x\n",
|
||||||
|
+ reg);
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
+ } while (1);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns21xx_spi_txrx_word(struct cns21xx_spi *hw, u8 tx_channel,
|
||||||
|
+ u8 tx_eof_flag, u32 tx_data, u32 *rx_data)
|
||||||
|
+{
|
||||||
|
+ unsigned int tx_ctrl;
|
||||||
|
+ u8 rx_channel;
|
||||||
|
+ u8 rx_eof_flag;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ err = cns21xx_spi_wait(hw, SPI_REG_STAT, STAT_SPI_BUSY_STA, 0);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_TXBUF_FG,
|
||||||
|
+ INTR_STAT_SPI_TXBUF_FG);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
|
||||||
|
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
|
||||||
|
+ tx_ctrl |= (tx_channel & TX_CTRL_SPI_TXCH_NUM_M);
|
||||||
|
+ tx_ctrl |= (tx_eof_flag) ? TX_CTRL_SPI_TXDAT_EOF : 0;
|
||||||
|
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
|
||||||
|
+
|
||||||
|
+ cns21xx_spi_wr(hw, tx_data, SPI_REG_TX_DATA);
|
||||||
|
+
|
||||||
|
+ err = cns21xx_spi_wait(hw, SPI_REG_INTR_STAT, INTR_STAT_SPI_RXBUF_FG,
|
||||||
|
+ INTR_STAT_SPI_RXBUF_FG);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ rx_channel = cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
|
||||||
|
+ RX_CTRL_SPI_RXCH_NUM_M;
|
||||||
|
+
|
||||||
|
+ rx_eof_flag = (cns21xx_spi_rr(hw, SPI_REG_RX_CTRL) &
|
||||||
|
+ RX_CTRL_SPI_RXDAT_EOF) ? 1 : 0;
|
||||||
|
+
|
||||||
|
+ *rx_data = cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
|
||||||
|
+
|
||||||
|
+ if ((tx_channel != rx_channel) || (tx_eof_flag != rx_eof_flag))
|
||||||
|
+ return -EPROTO;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void cns21xx_spi_chipselect(struct spi_device *spi, int value)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw = to_hw(spi);
|
||||||
|
+ unsigned int spi_config;
|
||||||
|
+ unsigned int tx_ctrl;
|
||||||
|
+
|
||||||
|
+ switch (value) {
|
||||||
|
+ case BITBANG_CS_INACTIVE:
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case BITBANG_CS_ACTIVE:
|
||||||
|
+ spi_config = cns21xx_spi_rr(hw, SPI_REG_CFG);
|
||||||
|
+
|
||||||
|
+ if (spi->mode & SPI_CPHA)
|
||||||
|
+ spi_config |= CFG_SPI_CLKPHA;
|
||||||
|
+ else
|
||||||
|
+ spi_config &= ~CFG_SPI_CLKPHA;
|
||||||
|
+
|
||||||
|
+ if (spi->mode & SPI_CPOL)
|
||||||
|
+ spi_config |= CFG_SPI_CLKPOL;
|
||||||
|
+ else
|
||||||
|
+ spi_config &= ~CFG_SPI_CLKPOL;
|
||||||
|
+
|
||||||
|
+ cns21xx_spi_wr(hw, spi_config, SPI_REG_CFG);
|
||||||
|
+
|
||||||
|
+ tx_ctrl = cns21xx_spi_rr(hw, SPI_REG_TX_CTRL);
|
||||||
|
+ tx_ctrl &= ~(TX_CTRL_CLEAR_MASK);
|
||||||
|
+ tx_ctrl |= (spi->chip_select & TX_CTRL_SPI_TXCH_NUM_M);
|
||||||
|
+ cns21xx_spi_wr(hw, tx_ctrl, SPI_REG_TX_CTRL);
|
||||||
|
+
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns21xx_spi_setup(struct spi_device *spi)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw = to_hw(spi);
|
||||||
|
+
|
||||||
|
+ if (spi->bits_per_word != 8) {
|
||||||
|
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
|
||||||
|
+ __func__, spi->bits_per_word);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (spi->max_speed_hz == 0)
|
||||||
|
+ spi->max_speed_hz = hw->freq_max;
|
||||||
|
+
|
||||||
|
+ if (spi->max_speed_hz > hw->freq_max ||
|
||||||
|
+ spi->max_speed_hz < hw->freq_min) {
|
||||||
|
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
|
||||||
|
+ __func__, spi->max_speed_hz);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns21xx_spi_setup_transfer(struct spi_device *spi,
|
||||||
|
+ struct spi_transfer *t)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw = to_hw(spi);
|
||||||
|
+ u8 bits_per_word;
|
||||||
|
+ u32 hz;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
|
||||||
|
+ hz = t ? t->speed_hz : spi->max_speed_hz;
|
||||||
|
+
|
||||||
|
+ if (!bits_per_word)
|
||||||
|
+ bits_per_word = spi->bits_per_word;
|
||||||
|
+
|
||||||
|
+ if (!hz)
|
||||||
|
+ hz = spi->max_speed_hz;
|
||||||
|
+
|
||||||
|
+ if (bits_per_word != 8) {
|
||||||
|
+ dev_err(&spi->dev, "%s: invalid bits_per_word=%u\n",
|
||||||
|
+ __func__, bits_per_word);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) {
|
||||||
|
+ dev_err(&spi->dev, "%s: max_speed_hz=%u out of range\n",
|
||||||
|
+ __func__, hz);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < CNS21XX_SPI_NUM_BIT_RATES; i++)
|
||||||
|
+ if (spi->max_speed_hz > (cns21xx_get_apb_freq() >> i))
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ DBG("max_speed:%uHz, curr_speed:%luHz, rate_index=%d\n",
|
||||||
|
+ spi->max_speed_hz, cns21xx_get_apb_freq() / (1 << i), i);
|
||||||
|
+
|
||||||
|
+ cns21xx_spi_wr(hw, i, SPI_REG_BIT_RATE);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns21xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw = to_hw(spi);
|
||||||
|
+ const unsigned char *tx_buf;
|
||||||
|
+ unsigned char *rx_buf;
|
||||||
|
+ u32 rx_data;
|
||||||
|
+ int tx_eof;
|
||||||
|
+ int err = 0;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ tx_buf = t->tx_buf;
|
||||||
|
+ rx_buf = t->rx_buf;
|
||||||
|
+ tx_eof = t->last_in_message_list;
|
||||||
|
+
|
||||||
|
+ DBG("txrx: tx %p, rx %p, len %d\n", tx_buf, rx_buf, t->len);
|
||||||
|
+
|
||||||
|
+ if (tx_buf) {
|
||||||
|
+ for (i = 0; i < t->len; i++)
|
||||||
|
+ DBG("tx_buf[%02d]: 0x%02x\n", i, tx_buf[i]);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < (t->len - 1); i++) {
|
||||||
|
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
|
||||||
|
+ tx_buf[i], &rx_data);
|
||||||
|
+ if (err)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ if (rx_buf) {
|
||||||
|
+ rx_buf[i] = rx_data;
|
||||||
|
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
|
||||||
|
+ tx_buf[i], &rx_data);
|
||||||
|
+ if (err)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ if ((tx_eof) && rx_buf) {
|
||||||
|
+ rx_buf[i] = rx_data;
|
||||||
|
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
|
||||||
|
+ }
|
||||||
|
+ } else if (rx_buf) {
|
||||||
|
+ for (i = 0; i < (t->len - 1); i++) {
|
||||||
|
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, 0,
|
||||||
|
+ 0xff, &rx_data);
|
||||||
|
+ if (err)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ rx_buf[i] = rx_data;
|
||||||
|
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ err = cns21xx_spi_txrx_word(hw, spi->chip_select, tx_eof,
|
||||||
|
+ 0xff, &rx_data);
|
||||||
|
+ if (err)
|
||||||
|
+ goto done;
|
||||||
|
+
|
||||||
|
+ rx_buf[i] = rx_data;
|
||||||
|
+ DBG("rx_buf[%02d]:0x%02x\n", i, rx_buf[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ done:
|
||||||
|
+ return (err) ? err : t->len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __init cns21xx_spi_hw_init(struct cns21xx_spi *hw)
|
||||||
|
+{
|
||||||
|
+ u32 t;
|
||||||
|
+ u32 pclk;
|
||||||
|
+
|
||||||
|
+ /* Setup configuration register */
|
||||||
|
+ cns21xx_spi_wr(hw, CFG_SPI_MASTER_EN, SPI_REG_CFG);
|
||||||
|
+
|
||||||
|
+ /* Set default clock to PCLK/2 */
|
||||||
|
+ cns21xx_spi_wr(hw, BIT_RATE_DIV_2, SPI_REG_BIT_RATE);
|
||||||
|
+
|
||||||
|
+ /* Configure SPI's Tx channel */
|
||||||
|
+ cns21xx_spi_wr(hw, 0, SPI_REG_TX_CTRL);
|
||||||
|
+
|
||||||
|
+ /* Configure Tx FIFO Threshold */
|
||||||
|
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_TX_CFG);
|
||||||
|
+ t &= ~(FIFO_TX_CFG_SPI_TXFF_THRED_M << FIFO_TX_CFG_SPI_TXFF_THRED_S);
|
||||||
|
+ t |= (FIFO_TX_CFG_SPI_TXFF_THRED_2 << FIFO_TX_CFG_SPI_TXFF_THRED_S);
|
||||||
|
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_TX_CFG);
|
||||||
|
+
|
||||||
|
+ /* Configure Rx FIFO Threshold */
|
||||||
|
+ t = cns21xx_spi_rr(hw, SPI_REG_FIFO_RX_CFG);
|
||||||
|
+ t &= ~(FIFO_RX_CFG_SPI_RXFF_THRED_M << FIFO_RX_CFG_SPI_RXFF_THRED_S);
|
||||||
|
+ t |= (FIFO_RX_CFG_SPI_RXFF_THRED_2 << FIFO_RX_CFG_SPI_RXFF_THRED_S);
|
||||||
|
+ cns21xx_spi_wr(hw, t, SPI_REG_FIFO_RX_CFG);
|
||||||
|
+
|
||||||
|
+ /* Disable interrupts, and clear interrupt status */
|
||||||
|
+ cns21xx_spi_wr(hw, 0, SPI_REG_INTR_ENA);
|
||||||
|
+ cns21xx_spi_wr(hw, INTR_STAT_CLEAR_MASK, SPI_REG_INTR_STAT);
|
||||||
|
+
|
||||||
|
+ (void) cns21xx_spi_rr(hw, SPI_REG_RX_DATA);
|
||||||
|
+
|
||||||
|
+ /* Enable SPI */
|
||||||
|
+ t = cns21xx_spi_rr(hw, SPI_REG_CFG);
|
||||||
|
+ t |= CFG_SPI_EN;
|
||||||
|
+ cns21xx_spi_wr(hw, t, SPI_REG_CFG);
|
||||||
|
+
|
||||||
|
+ pclk = cns21xx_get_apb_freq();
|
||||||
|
+ hw->freq_max = pclk;
|
||||||
|
+ hw->freq_min = pclk / (1 << BIT_RATE_DIV_128);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __init cns21xx_spi_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw;
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct resource *res;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ master = spi_alloc_master(&pdev->dev, sizeof(struct cns21xx_spi));
|
||||||
|
+ if (!master) {
|
||||||
|
+ dev_err(&pdev->dev, "No memory for spi_master\n");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hw = spi_master_get_devdata(master);
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, hw);
|
||||||
|
+ hw->master = spi_master_get(master);
|
||||||
|
+ hw->dev = &pdev->dev;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ dev_dbg(&pdev->dev, "no MEM resource found\n");
|
||||||
|
+ err = -ENOENT;
|
||||||
|
+ goto err_put_master;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hw->region = request_mem_region(res->start, resource_size(res),
|
||||||
|
+ dev_name(&pdev->dev));
|
||||||
|
+ if (!hw->region) {
|
||||||
|
+ dev_err(&pdev->dev, "unable to reserve iomem region\n");
|
||||||
|
+ err = -ENXIO;
|
||||||
|
+ goto err_put_master;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hw->base = ioremap(res->start, resource_size(res));
|
||||||
|
+ if (!hw->base) {
|
||||||
|
+ dev_err(&pdev->dev, "ioremap failed\n");
|
||||||
|
+ err = -ENOENT;
|
||||||
|
+ goto err_release_region;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cns21xx_spi_hw_init(hw);
|
||||||
|
+
|
||||||
|
+ master->bus_num = pdev->id;
|
||||||
|
+ if (master->bus_num == -1)
|
||||||
|
+ master->bus_num = 0;
|
||||||
|
+
|
||||||
|
+ master->num_chipselect = 4;
|
||||||
|
+ master->setup = cns21xx_spi_setup;
|
||||||
|
+
|
||||||
|
+ hw->bitbang.master = hw->master;
|
||||||
|
+ hw->bitbang.chipselect = cns21xx_spi_chipselect;
|
||||||
|
+ hw->bitbang.txrx_bufs = cns21xx_spi_txrx;
|
||||||
|
+ hw->bitbang.setup_transfer = cns21xx_spi_setup_transfer;
|
||||||
|
+
|
||||||
|
+ err = spi_bitbang_start(&hw->bitbang);
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(hw->dev, "unable to register SPI master\n");
|
||||||
|
+ goto err_unmap;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ dev_info(hw->dev, "iomem at %08x\n", res->start);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ err_unmap:
|
||||||
|
+ iounmap(hw->base);
|
||||||
|
+
|
||||||
|
+ err_release_region:
|
||||||
|
+ release_resource(hw->region);
|
||||||
|
+ kfree(hw->region);
|
||||||
|
+
|
||||||
|
+ err_put_master:
|
||||||
|
+ spi_master_put(hw->bitbang.master);
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns21xx_spi_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct cns21xx_spi *hw = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ spi_bitbang_stop(&hw->bitbang);
|
||||||
|
+ iounmap(hw->base);
|
||||||
|
+ release_resource(hw->region);
|
||||||
|
+ kfree(hw->region);
|
||||||
|
+ spi_master_put(hw->bitbang.master);
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct platform_driver cns21xx_spi_driver = {
|
||||||
|
+ .remove = cns21xx_spi_remove,
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = DRIVER_NAME,
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init cns21xx_spi_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_probe(&cns21xx_spi_driver, cns21xx_spi_probe);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit cns21xx_spi_exit(void)
|
||||||
|
+{
|
||||||
|
+ platform_driver_unregister(&cns21xx_spi_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(cns21xx_spi_init);
|
||||||
|
+module_exit(cns21xx_spi_exit);
|
||||||
|
+
|
||||||
|
+MODULE_DESCRIPTION("Cavium Networks CNS21xx SPI Controller driver");
|
||||||
|
+MODULE_AUTHOR("STAR Semi Corp.");
|
||||||
|
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
|
||||||
|
+MODULE_LICENSE("GPL v2");
|
||||||
|
+MODULE_ALIAS("platform:" DRIVER_NAME);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,104 @@
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/dev-usb.c
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/irq.h>
|
||||||
|
+#include <linux/dma-mapping.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+
|
||||||
|
+static u64 cns21xx_usb_dmamask = DMA_BIT_MASK(32);
|
||||||
|
+
|
||||||
|
+static struct resource cns21xx_ohci_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS21XX_OHCI_CTRL_BASE,
|
||||||
|
+ .end = CNS21XX_OHCI_CTRL_BASE + SZ_1M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = CNS21XX_IRQ_OHCI,
|
||||||
|
+ .end = CNS21XX_IRQ_OHCI,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_ohci_device = {
|
||||||
|
+ .name = "cns21xx-ohci",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns21xx_usb_dmamask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+ .resource = cns21xx_ohci_resources,
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns21xx_ohci_resources),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct resource cns21xx_ehci_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS21XX_EHCI_CTRL_BASE,
|
||||||
|
+ .end = CNS21XX_EHCI_CTRL_BASE + SZ_1M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = CNS21XX_IRQ_EHCI,
|
||||||
|
+ .end = CNS21XX_IRQ_EHCI,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_ehci_device = {
|
||||||
|
+ .name = "cns21xx-ehci",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns21xx_usb_dmamask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+ .resource = cns21xx_ehci_resources,
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns21xx_ehci_resources),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void __init cns21xx_register_usb(void)
|
||||||
|
+{
|
||||||
|
+ platform_device_register(&cns21xx_ehci_device);
|
||||||
|
+ platform_device_register(&cns21xx_ohci_device);
|
||||||
|
+}
|
||||||
|
--- a/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
@@ -3,4 +3,7 @@ if ARCH_CNS21XX
|
||||||
|
menu "Cavium Networks CNS21xx based machines"
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
+config CNS21XX_DEV_USB
|
||||||
|
+ def_bool n
|
||||||
|
+
|
||||||
|
endif
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -6,5 +6,8 @@
|
||||||
|
|
||||||
|
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
|
||||||
|
|
||||||
|
+# devices
|
||||||
|
+obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
|
||||||
|
+
|
||||||
|
# machine specific files
|
||||||
|
|
||||||
|
--- a/arch/arm/mach-cns21xx/common.h
|
||||||
|
+++ b/arch/arm/mach-cns21xx/common.h
|
||||||
|
@@ -19,5 +19,6 @@ extern struct sys_timer cns21xx_timer;
|
||||||
|
|
||||||
|
int cns21xx_register_uart0(void);
|
||||||
|
int cns21xx_register_uart1(void);
|
||||||
|
+int cns21xx_register_usb(void);
|
||||||
|
|
||||||
|
#endif /* _MACH_CNS21XX_COMMON_H */
|
|
@ -0,0 +1,63 @@
|
||||||
|
--- a/arch/arm/mach-cns21xx/common.h
|
||||||
|
+++ b/arch/arm/mach-cns21xx/common.h
|
||||||
|
@@ -20,5 +20,6 @@ extern struct sys_timer cns21xx_timer;
|
||||||
|
int cns21xx_register_uart0(void);
|
||||||
|
int cns21xx_register_uart1(void);
|
||||||
|
int cns21xx_register_usb(void);
|
||||||
|
+int cns21xx_register_wdt(void);
|
||||||
|
|
||||||
|
#endif /* _MACH_CNS21XX_COMMON_H */
|
||||||
|
--- a/arch/arm/mach-cns21xx/devices.c
|
||||||
|
+++ b/arch/arm/mach-cns21xx/devices.c
|
||||||
|
@@ -11,6 +11,7 @@
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/serial_8250.h>
|
||||||
|
+#include <linux/fa_wdt.h>
|
||||||
|
|
||||||
|
#include <mach/irqs.h>
|
||||||
|
#include <mach/hardware.h>
|
||||||
|
@@ -77,3 +78,32 @@ int __init cns21xx_register_uart1(void)
|
||||||
|
HAL_MISC_ENABLE_UART1_PINS();
|
||||||
|
return platform_device_register(&cns21xx_uart1_device);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+static struct resource cns21xx_wdt_resources[] = {
|
||||||
|
+ {
|
||||||
|
+ .start = CNS21XX_WDT_BASE,
|
||||||
|
+ .end = CNS21XX_WDT_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#define CNS21XX_WDT_CLOCK 10 /* 10 Hz */
|
||||||
|
+
|
||||||
|
+static struct fa_wdt_platform_data cns21xx_wdt_data = {
|
||||||
|
+ .clock = CNS21XX_WDT_CLOCK,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_wdt_device = {
|
||||||
|
+ .name = "fa-wdt",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .resource = cns21xx_wdt_resources,
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns21xx_wdt_resources),
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = &cns21xx_wdt_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int __init cns21xx_register_wdt(void)
|
||||||
|
+{
|
||||||
|
+ return platform_device_register(&cns21xx_wdt_device);
|
||||||
|
+}
|
||||||
|
--- a/drivers/watchdog/Kconfig
|
||||||
|
+++ b/drivers/watchdog/Kconfig
|
||||||
|
@@ -366,7 +366,7 @@ config IMX2_WDT
|
||||||
|
|
||||||
|
config FA_WATCHDOG
|
||||||
|
tristate "Faraday watchdog"
|
||||||
|
- depends on ARCH_GEMINI
|
||||||
|
+ depends on ARCH_GEMINI || ARCH_CNS21XX
|
||||||
|
help
|
||||||
|
Say Y here if you want support for the built-in watchdog timer
|
||||||
|
found in some Faraday FA526 based SoCs.
|
|
@ -0,0 +1,117 @@
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/dev-spi-master.c
|
||||||
|
@@ -0,0 +1,83 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/dma-mapping.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/cns21xx_misc.h>
|
||||||
|
+#include <mach/cns21xx_powermgmt.h>
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+
|
||||||
|
+#include "common.h"
|
||||||
|
+
|
||||||
|
+static u64 spi_dmamask = DMA_BIT_MASK(32);
|
||||||
|
+static struct resource cns21xx_spi_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS21XX_SPI_BASE,
|
||||||
|
+ .end = CNS21XX_SPI_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = CNS21XX_IRQ_SPI,
|
||||||
|
+ .end = CNS21XX_IRQ_SPI,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device cns21xx_spi_master_device = {
|
||||||
|
+ .name = "cns21xx-spi",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &spi_dmamask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+ .resource = cns21xx_spi_resources,
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns21xx_spi_resources),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
|
||||||
|
+ unsigned int n)
|
||||||
|
+{
|
||||||
|
+ unsigned int i;
|
||||||
|
+
|
||||||
|
+ /* Enable SPI pins */
|
||||||
|
+ HAL_MISC_ENABLE_SPIDR_PINS();
|
||||||
|
+ HAL_MISC_ENABLE_SPICLK_PINS();
|
||||||
|
+ for (i = 0; i < n; i++) {
|
||||||
|
+ switch (info[i].chip_select) {
|
||||||
|
+ case 0:
|
||||||
|
+ HAL_MISC_ENABLE_SPICSN0_PINS();
|
||||||
|
+ break;
|
||||||
|
+ case 1:
|
||||||
|
+ HAL_MISC_ENABLE_SPICSN1_PINS();
|
||||||
|
+ break;
|
||||||
|
+ case 2:
|
||||||
|
+ HAL_MISC_ENABLE_SPICSN2_PINS();
|
||||||
|
+ break;
|
||||||
|
+ case 3:
|
||||||
|
+ HAL_MISC_ENABLE_SPICSN3_PINS();
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Disable SPI serial flash access through 0x30000000 region */
|
||||||
|
+ HAL_MISC_DISABLE_SPI_SERIAL_FLASH_BANK_ACCESS();
|
||||||
|
+
|
||||||
|
+ /* Enable SPI clock */
|
||||||
|
+ HAL_PWRMGT_ENABLE_SPI_CLOCK();
|
||||||
|
+
|
||||||
|
+ cns21xx_spi_master_device.id = id;
|
||||||
|
+
|
||||||
|
+ spi_register_board_info(info, n);
|
||||||
|
+ platform_device_register(&cns21xx_spi_master_device);
|
||||||
|
+}
|
||||||
|
--- a/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
@@ -6,4 +6,7 @@ endmenu
|
||||||
|
config CNS21XX_DEV_USB
|
||||||
|
def_bool n
|
||||||
|
|
||||||
|
+config CNS21XX_DEV_SPI_MASTER
|
||||||
|
+ def_bool n
|
||||||
|
+
|
||||||
|
endif
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -8,6 +8,7 @@ obj-y := core.o devices.o gpio.o irq.o
|
||||||
|
|
||||||
|
# devices
|
||||||
|
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
|
||||||
|
+obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
|
||||||
|
|
||||||
|
# machine specific files
|
||||||
|
|
||||||
|
--- a/arch/arm/mach-cns21xx/common.h
|
||||||
|
+++ b/arch/arm/mach-cns21xx/common.h
|
||||||
|
@@ -22,4 +22,8 @@ int cns21xx_register_uart1(void);
|
||||||
|
int cns21xx_register_usb(void);
|
||||||
|
int cns21xx_register_wdt(void);
|
||||||
|
|
||||||
|
+struct spi_board_info;
|
||||||
|
+void __init cns21xx_register_spi_master(int id, struct spi_board_info *info,
|
||||||
|
+ unsigned int n);
|
||||||
|
+
|
||||||
|
#endif /* _MACH_CNS21XX_COMMON_H */
|
|
@ -0,0 +1,178 @@
|
||||||
|
--- a/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
@@ -3,6 +3,9 @@ if ARCH_CNS21XX
|
||||||
|
menu "Cavium Networks CNS21xx based machines"
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
+config CNS21XX_DEV_GEC
|
||||||
|
+ def_bool n
|
||||||
|
+
|
||||||
|
config CNS21XX_DEV_USB
|
||||||
|
def_bool n
|
||||||
|
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -7,6 +7,7 @@
|
||||||
|
obj-y := core.o devices.o gpio.o irq.o mm.o time.o
|
||||||
|
|
||||||
|
# devices
|
||||||
|
+obj-$(CONFIG_CNS21XX_DEV_GEC) += dev-gec.o
|
||||||
|
obj-$(CONFIG_CNS21XX_DEV_USB) += dev-usb.o
|
||||||
|
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/dev-gec.c
|
||||||
|
@@ -0,0 +1,98 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/dma-mapping.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/etherdevice.h>
|
||||||
|
+
|
||||||
|
+#include <asm/sizes.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+
|
||||||
|
+#include "dev-gec.h"
|
||||||
|
+
|
||||||
|
+static u8 cns21xx_ethaddr[ETH_ALEN];
|
||||||
|
+struct cns21xx_gec_plat_data cns21xx_gec_data;
|
||||||
|
+
|
||||||
|
+static struct resource cns21xx_gec_resources[] = {
|
||||||
|
+ {
|
||||||
|
+ .start = CNS21XX_NIC_BASE,
|
||||||
|
+ .end = CNS21XX_NIC_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ }, {
|
||||||
|
+ .name = CNS21XX_GEC_STATUS_IRQ_NAME,
|
||||||
|
+ .start = CNS21XX_IRQ_NIC_STATUS,
|
||||||
|
+ .end = CNS21XX_IRQ_NIC_STATUS,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }, {
|
||||||
|
+ .name = CNS21XX_GEC_RXRC_IRQ_NAME,
|
||||||
|
+ .start = CNS21XX_IRQ_NIC_RXRC,
|
||||||
|
+ .end = CNS21XX_IRQ_NIC_RXRC,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }, {
|
||||||
|
+ .name = CNS21XX_GEC_RXQF_IRQ_NAME,
|
||||||
|
+ .start = CNS21XX_IRQ_NIC_RXQF,
|
||||||
|
+ .end = CNS21XX_IRQ_NIC_RXQF,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }, {
|
||||||
|
+ .name = CNS21XX_GEC_TXTC_IRQ_NAME,
|
||||||
|
+ .start = CNS21XX_IRQ_NIC_TXTC,
|
||||||
|
+ .end = CNS21XX_IRQ_NIC_TXTC,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }, {
|
||||||
|
+ .name = CNS21XX_GEC_TXQE_IRQ_NAME,
|
||||||
|
+ .start = CNS21XX_IRQ_NIC_TXQE,
|
||||||
|
+ .end = CNS21XX_IRQ_NIC_TXQE,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u64 cns21xx_gec_dmamask = DMA_BIT_MASK(32);
|
||||||
|
+static struct platform_device cns21xx_gec_device = {
|
||||||
|
+ .name = "cns21xx-gec",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .resource = cns21xx_gec_resources,
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns21xx_gec_resources),
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns21xx_gec_dmamask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ .platform_data = &cns21xx_gec_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init cns21xx_ethaddr_setup(char *str)
|
||||||
|
+{
|
||||||
|
+ int t;
|
||||||
|
+
|
||||||
|
+ t = sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
|
||||||
|
+ &cns21xx_ethaddr[0], &cns21xx_ethaddr[1],
|
||||||
|
+ &cns21xx_ethaddr[2], &cns21xx_ethaddr[3],
|
||||||
|
+ &cns21xx_ethaddr[4], &cns21xx_ethaddr[5]);
|
||||||
|
+
|
||||||
|
+ if (t != ETH_ALEN)
|
||||||
|
+ pr_err("cns21xx: failed to parse mac address \"%s\"\n", str);
|
||||||
|
+
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+__setup("ethaddr=", cns21xx_ethaddr_setup);
|
||||||
|
+
|
||||||
|
+__init int cns21xx_register_gec(void)
|
||||||
|
+{
|
||||||
|
+ if (cns21xx_gec_data.mac_addr == NULL)
|
||||||
|
+ cns21xx_gec_data.mac_addr = cns21xx_ethaddr;
|
||||||
|
+
|
||||||
|
+ if (!is_valid_ether_addr(cns21xx_gec_data.mac_addr)) {
|
||||||
|
+ random_ether_addr(cns21xx_gec_data.mac_addr);
|
||||||
|
+ pr_debug("cns21xx: using random MAC address \"%s\"\n",
|
||||||
|
+ cns21xx_gec_data.mac_addr);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return platform_device_register(&cns21xx_gec_device);
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/dev-gec.h
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _CNS21XX_DEV_GEC_H
|
||||||
|
+#define _CNS21XX_DEV_GEC_H
|
||||||
|
+
|
||||||
|
+#include <mach/cns21xx_gec_platform.h>
|
||||||
|
+
|
||||||
|
+extern struct cns21xx_gec_plat_data cns21xx_gec_data;
|
||||||
|
+
|
||||||
|
+__init int cns21xx_register_gec(void);
|
||||||
|
+
|
||||||
|
+#endif /* _CNS21XX_DEV_GEC_H */
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/include/mach/cns21xx_gec_platform.h
|
||||||
|
@@ -0,0 +1,31 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _CNS21XX_GEC_PLATFORM_H
|
||||||
|
+#define _CNS21XX_GEC_PLATFORM_H
|
||||||
|
+
|
||||||
|
+#define CNS21XX_GEC_STATUS_IRQ_NAME "status"
|
||||||
|
+#define CNS21XX_GEC_RXRC_IRQ_NAME "rxrc"
|
||||||
|
+#define CNS21XX_GEC_RXQF_IRQ_NAME "rxqf"
|
||||||
|
+#define CNS21XX_GEC_TXTC_IRQ_NAME "txtc"
|
||||||
|
+#define CNS21XX_GEC_TXQE_IRQ_NAME "txqe"
|
||||||
|
+
|
||||||
|
+enum cns21xx_gec_phy_type {
|
||||||
|
+ CNS21XX_GEC_PHY_TYPE_INTERNAL = 0,
|
||||||
|
+ CNS21XX_GEC_PHY_TYPE_VSC8601,
|
||||||
|
+ CNS21XX_GEC_PHY_TYPE_IP101A,
|
||||||
|
+ CNS21XX_GEC_PHY_TYPE_IP1001,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct cns21xx_gec_plat_data {
|
||||||
|
+ u8 *mac_addr;
|
||||||
|
+ enum cns21xx_gec_phy_type phy_type;
|
||||||
|
+ u8 phy_addr;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+#endif /* _CNS21XX_GEC_PLATFORM_H */
|
|
@ -0,0 +1,234 @@
|
||||||
|
--- a/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
@@ -1,6 +1,16 @@
|
||||||
|
if ARCH_CNS21XX
|
||||||
|
|
||||||
|
menu "Cavium Networks CNS21xx based machines"
|
||||||
|
+
|
||||||
|
+config MACH_NS_K330
|
||||||
|
+ bool "NS-K330 NAS"
|
||||||
|
+ select CNS21XX_DEV_GEC
|
||||||
|
+ select CNS21XX_DEV_SPI_MASTER
|
||||||
|
+ select CNS21XX_DEV_USB
|
||||||
|
+ help
|
||||||
|
+ Say Y here if you intend to run this kernel on the
|
||||||
|
+ NS-K330 NAS board.
|
||||||
|
+
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
config CNS21XX_DEV_GEC
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/mach-ns-k330.c
|
||||||
|
@@ -0,0 +1,204 @@
|
||||||
|
+/*
|
||||||
|
+ * NS-K330 NAS board support
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/mtd/mtd.h>
|
||||||
|
+#include <linux/mtd/map.h>
|
||||||
|
+#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/spi/flash.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+#include <linux/leds.h>
|
||||||
|
+#include <linux/gpio_keys.h>
|
||||||
|
+#include <linux/input.h>
|
||||||
|
+
|
||||||
|
+#include <asm/setup.h>
|
||||||
|
+#include <asm/mach-types.h>
|
||||||
|
+#include <asm/mach/arch.h>
|
||||||
|
+#include <asm/mach/time.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/cns21xx_misc.h>
|
||||||
|
+
|
||||||
|
+#include "common.h"
|
||||||
|
+#include "dev-gec.h"
|
||||||
|
+
|
||||||
|
+#define NS_K330_GPIO_LED_LINK 1
|
||||||
|
+#define NS_K330_GPIO_LED_USB1 16
|
||||||
|
+#define NS_K330_GPIO_LED_USB2 17
|
||||||
|
+#define NS_K330_GPIO_LED_ETH_GREEN 22
|
||||||
|
+#define NS_K330_GPIO_LED_ETH_ORANGE 23
|
||||||
|
+
|
||||||
|
+#define NS_K330_GPIO_BTN_RESET 13
|
||||||
|
+#define NS_K330_GPIO_BTN_USB1 14
|
||||||
|
+#define NS_K330_GPIO_BTN_USB2 15
|
||||||
|
+
|
||||||
|
+static struct mtd_partition ns_k330_partitions[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "boot",
|
||||||
|
+ .offset = 0x0,
|
||||||
|
+ .size = 0x040000,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "config",
|
||||||
|
+ .offset = 0x040000,
|
||||||
|
+ .size = 0x020000,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "kernel",
|
||||||
|
+ .offset = 0x060000,
|
||||||
|
+ .size = 0x100000,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "rootfs",
|
||||||
|
+ .offset = 0x160000,
|
||||||
|
+ .size = 0x290000,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "firmware",
|
||||||
|
+ .offset = 0x060000,
|
||||||
|
+ .size = 0x390000,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct flash_platform_data ns_k330_flash_data = {
|
||||||
|
+ .parts = ns_k330_partitions,
|
||||||
|
+ .nr_parts = ARRAY_SIZE(ns_k330_partitions),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct spi_board_info ns_k330_spi_board_info[] = {
|
||||||
|
+ {
|
||||||
|
+ .bus_num = 0,
|
||||||
|
+ .chip_select = 0,
|
||||||
|
+ .max_speed_hz = 25000000,
|
||||||
|
+ .modalias = "m25p80",
|
||||||
|
+ .platform_data = &ns_k330_flash_data,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_led ns_k330_gpio_leds[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "ns-k330:red:link",
|
||||||
|
+ .gpio = NS_K330_GPIO_LED_LINK,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "ns-k330:green:usb1",
|
||||||
|
+ .gpio = NS_K330_GPIO_LED_USB1,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "ns-k330:green:usb2",
|
||||||
|
+ .gpio = NS_K330_GPIO_LED_USB2,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "ns-k330:green:eth",
|
||||||
|
+ .gpio = NS_K330_GPIO_LED_ETH_GREEN,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "ns-k330:orange:eth",
|
||||||
|
+ .gpio = NS_K330_GPIO_LED_ETH_ORANGE,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_led_platform_data ns_k330_gpio_leds_data = {
|
||||||
|
+ .num_leds = ARRAY_SIZE(ns_k330_gpio_leds),
|
||||||
|
+ .leds = ns_k330_gpio_leds,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device ns_k330_gpio_leds_device = {
|
||||||
|
+ .name = "leds-gpio",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev.platform_data = &ns_k330_gpio_leds_data,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_keys_button ns_k330_gpio_keys[] = {
|
||||||
|
+ {
|
||||||
|
+ .code = KEY_RESTART,
|
||||||
|
+ .gpio = NS_K330_GPIO_BTN_RESET,
|
||||||
|
+ .desc = "Reset Button",
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ .code = BTN_0,
|
||||||
|
+ .gpio = NS_K330_GPIO_BTN_USB1,
|
||||||
|
+ .desc = "USB1 Button",
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ .code = BTN_1,
|
||||||
|
+ .gpio = NS_K330_GPIO_BTN_USB2,
|
||||||
|
+ .desc = "USB2 Button",
|
||||||
|
+ .active_low = 0,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_keys_platform_data ns_k330_gpio_keys_data = {
|
||||||
|
+ .buttons = ns_k330_gpio_keys,
|
||||||
|
+ .nbuttons = ARRAY_SIZE(ns_k330_gpio_keys),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device ns_k330_gpio_keys_device = {
|
||||||
|
+ .name = "gpio-keys",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .num_resources = 0,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = &ns_k330_gpio_keys_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void __init ns_k330_fixup(struct tag *tags, char **cmdline,
|
||||||
|
+ struct meminfo *mi)
|
||||||
|
+{
|
||||||
|
+ struct tag *t;
|
||||||
|
+
|
||||||
|
+ /* The board has 32MB of RAM mapped at 0. */
|
||||||
|
+ mi->nr_banks = 1;
|
||||||
|
+ mi->bank[0].start = 0;
|
||||||
|
+ mi->bank[0].size = SZ_32M;
|
||||||
|
+
|
||||||
|
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
|
||||||
|
+ switch (t->hdr.tag) {
|
||||||
|
+ case ATAG_CORE:
|
||||||
|
+ if (t->u.core.rootdev == 255)
|
||||||
|
+ t->u.core.rootdev = 0;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __init ns_k330_init(void)
|
||||||
|
+{
|
||||||
|
+ cns21xx_gpio_init();
|
||||||
|
+
|
||||||
|
+ HAL_MISC_DISABLE_LED012_PINS();
|
||||||
|
+ HAL_MISC_DISABLE_I2C_PINS();
|
||||||
|
+ HAL_MISC_DISABLE_I2S_PINS();
|
||||||
|
+
|
||||||
|
+ cns21xx_register_uart0();
|
||||||
|
+ cns21xx_register_wdt();
|
||||||
|
+ cns21xx_register_usb();
|
||||||
|
+ cns21xx_register_spi_master(-1, ns_k330_spi_board_info,
|
||||||
|
+ ARRAY_SIZE(ns_k330_spi_board_info));
|
||||||
|
+
|
||||||
|
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
|
||||||
|
+ cns21xx_register_gec();
|
||||||
|
+
|
||||||
|
+ platform_device_register(&ns_k330_gpio_leds_device);
|
||||||
|
+ platform_device_register(&ns_k330_gpio_keys_device);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+MACHINE_START(NS_K330, "NS-K330 NAS")
|
||||||
|
+ .fixup = ns_k330_fixup,
|
||||||
|
+ .map_io = cns21xx_map_io,
|
||||||
|
+ .init_irq = cns21xx_init_irq,
|
||||||
|
+ .timer = &cns21xx_timer,
|
||||||
|
+ .init_machine = ns_k330_init,
|
||||||
|
+ .restart = cns21xx_restart,
|
||||||
|
+MACHINE_END
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -12,4 +12,4 @@ obj-$(CONFIG_CNS21XX_DEV_USB) += dev-us
|
||||||
|
obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) += dev-spi-master.o
|
||||||
|
|
||||||
|
# machine specific files
|
||||||
|
-
|
||||||
|
+obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o
|
|
@ -0,0 +1,201 @@
|
||||||
|
--- a/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Kconfig
|
||||||
|
@@ -2,6 +2,15 @@ if ARCH_CNS21XX
|
||||||
|
|
||||||
|
menu "Cavium Networks CNS21xx based machines"
|
||||||
|
|
||||||
|
+config MACH_NSB3AST
|
||||||
|
+ bool "AGESTAR NSB3AST support"
|
||||||
|
+ select CNS21XX_DEV_GEC
|
||||||
|
+ select CNS21XX_DEV_SPI_MASTER
|
||||||
|
+ select CNS21XX_DEV_USB
|
||||||
|
+ help
|
||||||
|
+ Say Y here if you intend to run this kernel on the
|
||||||
|
+ AGESTAR NSB3AST board.
|
||||||
|
+
|
||||||
|
config MACH_NS_K330
|
||||||
|
bool "NS-K330 NAS"
|
||||||
|
select CNS21XX_DEV_GEC
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns21xx/mach-nsb3ast.c
|
||||||
|
@@ -0,0 +1,173 @@
|
||||||
|
+/*
|
||||||
|
+ * AGESTAR NSB3AST board support
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2010-2012 Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
+ *
|
||||||
|
+ * This file is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License, Version 2, as
|
||||||
|
+ * published by the Free Software Foundation.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/mtd/mtd.h>
|
||||||
|
+#include <linux/mtd/map.h>
|
||||||
|
+#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/spi/flash.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/gpio.h>
|
||||||
|
+#include <linux/leds.h>
|
||||||
|
+#include <linux/gpio_keys.h>
|
||||||
|
+#include <linux/input.h>
|
||||||
|
+
|
||||||
|
+#include <asm/setup.h>
|
||||||
|
+#include <asm/mach-types.h>
|
||||||
|
+#include <asm/mach/arch.h>
|
||||||
|
+#include <asm/mach/time.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns21xx.h>
|
||||||
|
+#include <mach/cns21xx_misc.h>
|
||||||
|
+
|
||||||
|
+#include "common.h"
|
||||||
|
+#include "dev-gec.h"
|
||||||
|
+
|
||||||
|
+static struct mtd_partition nsb3ast_partitions[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "armboot",
|
||||||
|
+ .offset = 0x0,
|
||||||
|
+ .size = 0x040000,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "kernel",
|
||||||
|
+ .offset = 0x040000,
|
||||||
|
+ .size = 0x100000,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "rootfs",
|
||||||
|
+ .offset = 0x140000,
|
||||||
|
+ .size = 0x6c0000,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "firmware",
|
||||||
|
+ .offset = 0x040000,
|
||||||
|
+ .size = 0x7c0000,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "wholeflash",
|
||||||
|
+ .offset = 0x0,
|
||||||
|
+ .size = 0x800000,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct flash_platform_data nsb3ast_flash_data = {
|
||||||
|
+ .parts = nsb3ast_partitions,
|
||||||
|
+ .nr_parts = ARRAY_SIZE(nsb3ast_partitions),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct spi_board_info nsb3ast_spi_board_info[] = {
|
||||||
|
+ {
|
||||||
|
+ .bus_num = 0,
|
||||||
|
+ .chip_select = 0,
|
||||||
|
+ .max_speed_hz = 25000000,
|
||||||
|
+ .modalias = "m25p80",
|
||||||
|
+ .platform_data = &nsb3ast_flash_data,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_led nsb3ast_gpio_leds[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "nsb3ast:red:d1",
|
||||||
|
+ .gpio = 15,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "nsb3ast:amber:eth",
|
||||||
|
+ .gpio = 22,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_led_platform_data nsb3ast_gpio_leds_data = {
|
||||||
|
+ .num_leds = ARRAY_SIZE(nsb3ast_gpio_leds),
|
||||||
|
+ .leds = nsb3ast_gpio_leds,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device nsb3ast_gpio_leds_device = {
|
||||||
|
+ .name = "leds-gpio",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev.platform_data = &nsb3ast_gpio_leds_data,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_keys_button nsb3ast_gpio_keys[] = {
|
||||||
|
+ {
|
||||||
|
+ .code = KEY_RESTART,
|
||||||
|
+ .gpio = 0,
|
||||||
|
+ .desc = "Reset Button",
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },
|
||||||
|
+ {
|
||||||
|
+ .code = BTN_0,
|
||||||
|
+ .gpio = 2,
|
||||||
|
+ .desc = "USB Button",
|
||||||
|
+ .active_low = 0,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_keys_platform_data nsb3ast_gpio_keys_data = {
|
||||||
|
+ .buttons = nsb3ast_gpio_keys,
|
||||||
|
+ .nbuttons = ARRAY_SIZE(nsb3ast_gpio_keys),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device nsb3ast_gpio_keys_device = {
|
||||||
|
+ .name = "gpio-keys",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .num_resources = 0,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = &nsb3ast_gpio_keys_data,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void __init nsb3ast_fixup(struct tag *tags, char **cmdline,
|
||||||
|
+ struct meminfo *mi)
|
||||||
|
+{
|
||||||
|
+ struct tag *t;
|
||||||
|
+
|
||||||
|
+ /* The board has 32MB of RAM mapped at 0. */
|
||||||
|
+ mi->nr_banks = 1;
|
||||||
|
+ mi->bank[0].start = 0;
|
||||||
|
+ mi->bank[0].size = SZ_32M;
|
||||||
|
+
|
||||||
|
+ for (t = tags; t->hdr.size; t = tag_next(t)) {
|
||||||
|
+ switch (t->hdr.tag) {
|
||||||
|
+ case ATAG_CORE:
|
||||||
|
+ if (t->u.core.rootdev == 255)
|
||||||
|
+ t->u.core.rootdev = 0;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __init nsb3ast_init(void)
|
||||||
|
+{
|
||||||
|
+ cns21xx_gpio_init();
|
||||||
|
+ cns21xx_register_uart0();
|
||||||
|
+ cns21xx_register_uart1();
|
||||||
|
+ cns21xx_register_wdt();
|
||||||
|
+ cns21xx_register_usb();
|
||||||
|
+ cns21xx_register_spi_master(-1, nsb3ast_spi_board_info,
|
||||||
|
+ ARRAY_SIZE(nsb3ast_spi_board_info));
|
||||||
|
+
|
||||||
|
+ cns21xx_gec_data.phy_type = CNS21XX_GEC_PHY_TYPE_INTERNAL;
|
||||||
|
+ cns21xx_register_gec();
|
||||||
|
+
|
||||||
|
+ HAL_MISC_DISABLE_LED012_PINS();
|
||||||
|
+ platform_device_register(&nsb3ast_gpio_leds_device);
|
||||||
|
+ platform_device_register(&nsb3ast_gpio_keys_device);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+MACHINE_START(NSB3AST, "AGESTAR NSB3AST")
|
||||||
|
+ .fixup = nsb3ast_fixup,
|
||||||
|
+ .map_io = cns21xx_map_io,
|
||||||
|
+ .init_irq = cns21xx_init_irq,
|
||||||
|
+ .timer = &cns21xx_timer,
|
||||||
|
+ .init_machine = nsb3ast_init,
|
||||||
|
+ .restart = cns21xx_restart,
|
||||||
|
+MACHINE_END
|
||||||
|
--- a/arch/arm/mach-cns21xx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns21xx/Makefile
|
||||||
|
@@ -13,3 +13,4 @@ obj-$(CONFIG_CNS21XX_DEV_SPI_MASTER) +=
|
||||||
|
|
||||||
|
# machine specific files
|
||||||
|
obj-$(CONFIG_MACH_NS_K330) += mach-ns-k330.o
|
||||||
|
+obj-$(CONFIG_MACH_NSB3AST) += mach-nsb3ast.o
|
Loading…
Reference in New Issue