mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-18 06:47:30 +02:00
[cns3xxx]: preliminary 3.0 support
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27328 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
7437ee4707
commit
5bdb3e2cb7
419
target/linux/cns3xxx/patches-3.0/049-cns3xxx_smp_support.patch
Normal file
419
target/linux/cns3xxx/patches-3.0/049-cns3xxx_smp_support.patch
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/Makefile
|
||||||
|
@@ -1,3 +1,6 @@
|
||||||
|
obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o
|
||||||
|
obj-$(CONFIG_PCI) += pcie.o
|
||||||
|
obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o
|
||||||
|
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||||
|
+obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||||
|
+obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/headsmp.S
|
||||||
|
@@ -0,0 +1,43 @@
|
||||||
|
+/*
|
||||||
|
+ * linux/arch/arm/mach-cns3xxx/headsmp.S
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2003 ARM Limited
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved
|
||||||
|
+ *
|
||||||
|
+ * 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/linkage.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+
|
||||||
|
+ __INIT
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * CNS3XXX specific entry point for secondary CPUs. This
|
||||||
|
+ * provides a "holding pen" into which all secondary cores are held
|
||||||
|
+ * until we're ready for them to initialise.
|
||||||
|
+ */
|
||||||
|
+ENTRY(cns3xxx_secondary_startup)
|
||||||
|
+ mrc p15, 0, r0, c0, c0, 5
|
||||||
|
+ and r0, r0, #15
|
||||||
|
+ adr r4, 1f
|
||||||
|
+ ldmia r4, {r5, r6}
|
||||||
|
+ sub r4, r4, r5
|
||||||
|
+ add r6, r6, r4
|
||||||
|
+pen: ldr r7, [r6]
|
||||||
|
+ cmp r7, r0
|
||||||
|
+ bne pen
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * we've been released from the holding pen: secondary_stack
|
||||||
|
+ * should now contain the SVC stack for this core
|
||||||
|
+ */
|
||||||
|
+ b secondary_startup
|
||||||
|
+
|
||||||
|
+ .align
|
||||||
|
+1: .long .
|
||||||
|
+ .long pen_release
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/hotplug.c
|
||||||
|
@@ -0,0 +1,131 @@
|
||||||
|
+/*
|
||||||
|
+ * linux/arch/arm/mach-cns3xxx/hotplug.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2002 ARM Ltd.
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved
|
||||||
|
+ *
|
||||||
|
+ * 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/errno.h>
|
||||||
|
+#include <linux/smp.h>
|
||||||
|
+
|
||||||
|
+#include <asm/cacheflush.h>
|
||||||
|
+
|
||||||
|
+extern volatile int pen_release;
|
||||||
|
+
|
||||||
|
+static inline void cpu_enter_lowpower(void)
|
||||||
|
+{
|
||||||
|
+ unsigned int v;
|
||||||
|
+
|
||||||
|
+ flush_cache_all();
|
||||||
|
+ asm volatile(
|
||||||
|
+ "mcr p15, 0, %1, c7, c5, 0\n"
|
||||||
|
+ " mcr p15, 0, %1, c7, c10, 4\n"
|
||||||
|
+ /*
|
||||||
|
+ * Turn off coherency
|
||||||
|
+ */
|
||||||
|
+ " mrc p15, 0, %0, c1, c0, 1\n"
|
||||||
|
+ " bic %0, %0, %3\n"
|
||||||
|
+ " mcr p15, 0, %0, c1, c0, 1\n"
|
||||||
|
+ " mrc p15, 0, %0, c1, c0, 0\n"
|
||||||
|
+ " bic %0, %0, %2\n"
|
||||||
|
+ " mcr p15, 0, %0, c1, c0, 0\n"
|
||||||
|
+ : "=&r" (v)
|
||||||
|
+ : "r" (0), "Ir" (CR_C), "Ir" (0x40)
|
||||||
|
+ : "cc");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void cpu_leave_lowpower(void)
|
||||||
|
+{
|
||||||
|
+ unsigned int v;
|
||||||
|
+
|
||||||
|
+ asm volatile(
|
||||||
|
+ "mrc p15, 0, %0, c1, c0, 0\n"
|
||||||
|
+ " orr %0, %0, %1\n"
|
||||||
|
+ " mcr p15, 0, %0, c1, c0, 0\n"
|
||||||
|
+ " mrc p15, 0, %0, c1, c0, 1\n"
|
||||||
|
+ " orr %0, %0, %2\n"
|
||||||
|
+ " mcr p15, 0, %0, c1, c0, 1\n"
|
||||||
|
+ : "=&r" (v)
|
||||||
|
+ : "Ir" (CR_C), "Ir" (0x40)
|
||||||
|
+ : "cc");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
|
||||||
|
+{
|
||||||
|
+ /*
|
||||||
|
+ * there is no power-control hardware on this platform, so all
|
||||||
|
+ * we can do is put the core into WFI; this is safe as the calling
|
||||||
|
+ * code will have already disabled interrupts
|
||||||
|
+ */
|
||||||
|
+ for (;;) {
|
||||||
|
+ /*
|
||||||
|
+ * here's the WFI
|
||||||
|
+ */
|
||||||
|
+ asm(".word 0xe320f003\n"
|
||||||
|
+ :
|
||||||
|
+ :
|
||||||
|
+ : "memory", "cc");
|
||||||
|
+
|
||||||
|
+ if (pen_release == cpu) {
|
||||||
|
+ /*
|
||||||
|
+ * OK, proper wakeup, we're done
|
||||||
|
+ */
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Getting here, means that we have come out of WFI without
|
||||||
|
+ * having been woken up - this shouldn't happen
|
||||||
|
+ *
|
||||||
|
+ * Just note it happening - when we're woken, we can report
|
||||||
|
+ * its occurrence.
|
||||||
|
+ */
|
||||||
|
+ (*spurious)++;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int platform_cpu_kill(unsigned int cpu)
|
||||||
|
+{
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * platform-specific code to shutdown a CPU
|
||||||
|
+ *
|
||||||
|
+ * Called with IRQs disabled
|
||||||
|
+ */
|
||||||
|
+void platform_cpu_die(unsigned int cpu)
|
||||||
|
+{
|
||||||
|
+ int spurious = 0;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * we're ready for shutdown now, so do it
|
||||||
|
+ */
|
||||||
|
+ cpu_enter_lowpower();
|
||||||
|
+ platform_do_lowpower(cpu, &spurious);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * bring this CPU back into the world of cache
|
||||||
|
+ * coherency, and then restore interrupts
|
||||||
|
+ */
|
||||||
|
+ cpu_leave_lowpower();
|
||||||
|
+
|
||||||
|
+ if (spurious)
|
||||||
|
+ pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int platform_cpu_disable(unsigned int cpu)
|
||||||
|
+{
|
||||||
|
+ /*
|
||||||
|
+ * we don't allow CPU 0 to be shutdown (it is still too special
|
||||||
|
+ * e.g. clock tick interrupts)
|
||||||
|
+ */
|
||||||
|
+ return cpu == 0 ? -EPERM : 0;
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/localtimer.c
|
||||||
|
@@ -0,0 +1,29 @@
|
||||||
|
+/*
|
||||||
|
+ * linux/arch/arm/mach-cns3xxx/localtimer.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2002 ARM Ltd.
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved
|
||||||
|
+ *
|
||||||
|
+ * 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/init.h>
|
||||||
|
+#include <linux/smp.h>
|
||||||
|
+#include <linux/clockchips.h>
|
||||||
|
+
|
||||||
|
+#include <asm/smp_twd.h>
|
||||||
|
+#include <asm/localtimer.h>
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Setup the local clock events for a CPU.
|
||||||
|
+ */
|
||||||
|
+void __cpuinit local_timer_setup(struct clock_event_device *evt)
|
||||||
|
+{
|
||||||
|
+ evt->irq = IRQ_LOCALTIMER;
|
||||||
|
+ twd_timer_setup(evt);
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/platsmp.c
|
||||||
|
@@ -0,0 +1,168 @@
|
||||||
|
+/*
|
||||||
|
+ * linux/arch/arm/mach-cns3xxx/platsmp.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 2002 ARM Ltd.
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * All Rights Reserved
|
||||||
|
+ *
|
||||||
|
+ * 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/init.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/device.h>
|
||||||
|
+#include <linux/jiffies.h>
|
||||||
|
+#include <linux/smp.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+
|
||||||
|
+#include <asm/cacheflush.h>
|
||||||
|
+#include <asm/smp_scu.h>
|
||||||
|
+#include <asm/unified.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns3xxx.h>
|
||||||
|
+
|
||||||
|
+#include "core.h"
|
||||||
|
+
|
||||||
|
+extern void cns3xxx_secondary_startup(void);
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * control for which core is the next to come out of the secondary
|
||||||
|
+ * boot "holding pen"
|
||||||
|
+ */
|
||||||
|
+volatile int __cpuinitdata pen_release = -1;
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Write pen_release in a way that is guaranteed to be visible to all
|
||||||
|
+ * observers, irrespective of whether they're taking part in coherency
|
||||||
|
+ * or not. This is necessary for the hotplug code to work reliably.
|
||||||
|
+ */
|
||||||
|
+static void __cpuinit write_pen_release(int val)
|
||||||
|
+{
|
||||||
|
+ pen_release = val;
|
||||||
|
+ smp_wmb();
|
||||||
|
+ __cpuc_flush_dcache_area((void *)&pen_release, sizeof(pen_release));
|
||||||
|
+ outer_clean_range(__pa(&pen_release), __pa(&pen_release + 1));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __iomem *scu_base_addr(void)
|
||||||
|
+{
|
||||||
|
+ return (void __iomem *)(CNS3XXX_TC11MP_SCU_BASE_VIRT);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static DEFINE_SPINLOCK(boot_lock);
|
||||||
|
+
|
||||||
|
+void __cpuinit platform_secondary_init(unsigned int cpu)
|
||||||
|
+{
|
||||||
|
+ /*
|
||||||
|
+ * if any interrupts are already enabled for the primary
|
||||||
|
+ * core (e.g. timer irq), then they will not have been enabled
|
||||||
|
+ * for us: do so
|
||||||
|
+ */
|
||||||
|
+ gic_secondary_init(0);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * let the primary processor know we're out of the
|
||||||
|
+ * pen, then head off into the C entry point
|
||||||
|
+ */
|
||||||
|
+ write_pen_release(-1);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Synchronise with the boot thread.
|
||||||
|
+ */
|
||||||
|
+ spin_lock(&boot_lock);
|
||||||
|
+ spin_unlock(&boot_lock);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
|
||||||
|
+{
|
||||||
|
+ unsigned long timeout;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Set synchronisation state between this boot processor
|
||||||
|
+ * and the secondary one
|
||||||
|
+ */
|
||||||
|
+ spin_lock(&boot_lock);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * This is really belt and braces; we hold unintended secondary
|
||||||
|
+ * CPUs in the holding pen until we're ready for them. However,
|
||||||
|
+ * since we haven't sent them a soft interrupt, they shouldn't
|
||||||
|
+ * be there.
|
||||||
|
+ */
|
||||||
|
+ write_pen_release(cpu);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Send the secondary CPU a soft interrupt, thereby causing
|
||||||
|
+ * the boot monitor to read the system wide flags register,
|
||||||
|
+ * and branch to the address found there.
|
||||||
|
+ */
|
||||||
|
+ smp_cross_call(cpumask_of(cpu), 1);
|
||||||
|
+
|
||||||
|
+ timeout = jiffies + (1 * HZ);
|
||||||
|
+ while (time_before(jiffies, timeout)) {
|
||||||
|
+ smp_rmb();
|
||||||
|
+ if (pen_release == -1)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ udelay(10);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * now the secondary core is starting up let it run its
|
||||||
|
+ * calibrations, then wait for it to finish
|
||||||
|
+ */
|
||||||
|
+ spin_unlock(&boot_lock);
|
||||||
|
+
|
||||||
|
+ return pen_release != -1 ? -ENOSYS : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Initialise the CPU possible map early - this describes the CPUs
|
||||||
|
+ * which may be present or become present in the system.
|
||||||
|
+ */
|
||||||
|
+void __init smp_init_cpus(void)
|
||||||
|
+{
|
||||||
|
+ void __iomem *scu_base = scu_base_addr();
|
||||||
|
+ unsigned int i, ncores;
|
||||||
|
+
|
||||||
|
+ ncores = scu_base ? scu_get_core_count(scu_base) : 1;
|
||||||
|
+
|
||||||
|
+ /* sanity check */
|
||||||
|
+ if (ncores > NR_CPUS) {
|
||||||
|
+ printk(KERN_WARNING
|
||||||
|
+ "cns3xxx: no. of cores (%d) greater than configured "
|
||||||
|
+ "maximum of %d - clipping\n",
|
||||||
|
+ ncores, NR_CPUS);
|
||||||
|
+ ncores = NR_CPUS;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ncores; i++)
|
||||||
|
+ set_cpu_possible(i, true);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void __init platform_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Initialise the present map, which describes the set of CPUs
|
||||||
|
+ * actually populated at the present time.
|
||||||
|
+ */
|
||||||
|
+ for (i = 0; i < max_cpus; i++)
|
||||||
|
+ set_cpu_present(i, true);
|
||||||
|
+
|
||||||
|
+ scu_enable(scu_base_addr());
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Write the address of secondary startup into the
|
||||||
|
+ * system-wide flags register. The boot monitor waits
|
||||||
|
+ * until it receives a soft interrupt, and then the
|
||||||
|
+ * secondary CPU branches to this address.
|
||||||
|
+ */
|
||||||
|
+ __raw_writel(virt_to_phys(cns3xxx_secondary_startup),
|
||||||
|
+ (void __iomem *)(0xFFF07000 + 0x0600));
|
||||||
|
+}
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/include/mach/smp.h
|
||||||
|
@@ -0,0 +1,13 @@
|
||||||
|
+#ifndef __MACH_SMP_H
|
||||||
|
+#define __MACH_SMP_H
|
||||||
|
+
|
||||||
|
+#include <asm/hardware/gic.h>
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * We use IRQ1 as the IPI
|
||||||
|
+ */
|
||||||
|
+static inline void smp_cross_call(const struct cpumask *mask, int ipi)
|
||||||
|
+{
|
||||||
|
+ gic_raise_softirq(mask, ipi);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -1311,7 +1311,7 @@ config SMP
|
||||||
|
depends on REALVIEW_EB_ARM11MP || REALVIEW_EB_A9MP || \
|
||||||
|
MACH_REALVIEW_PB11MP || MACH_REALVIEW_PBX || ARCH_OMAP4 || \
|
||||||
|
ARCH_EXYNOS4 || ARCH_TEGRA || ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || \
|
||||||
|
- ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE
|
||||||
|
+ ARCH_MSM_SCORPIONMP || ARCH_SHMOBILE || ARCH_CNS3XXX
|
||||||
|
select USE_GENERIC_SMP_HELPERS
|
||||||
|
select HAVE_ARM_SCU if !ARCH_MSM_SCORPIONMP
|
||||||
|
help
|
@ -0,0 +1,421 @@
|
|||||||
|
--- a/drivers/i2c/busses/Kconfig
|
||||||
|
+++ b/drivers/i2c/busses/Kconfig
|
||||||
|
@@ -327,6 +327,18 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
|
||||||
|
help
|
||||||
|
The unit of the TWI clock is kHz.
|
||||||
|
|
||||||
|
+config I2C_CNS3XXX
|
||||||
|
+ tristate "Cavium CNS3xxx I2C driver"
|
||||||
|
+ depends on ARCH_CNS3XXX
|
||||||
|
+ help
|
||||||
|
+ Support for Cavium CNS3xxx I2C controller driver.
|
||||||
|
+
|
||||||
|
+ This driver can also be built as a module. If so, the module
|
||||||
|
+ will be called i2c-cns3xxx.
|
||||||
|
+
|
||||||
|
+ Please note that this driver might be needed to bring up other
|
||||||
|
+ devices such as Cavium CNS3xxx Ethernet.
|
||||||
|
+
|
||||||
|
config I2C_CPM
|
||||||
|
tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)"
|
||||||
|
depends on (CPM1 || CPM2) && OF_I2C
|
||||||
|
--- a/drivers/i2c/busses/Makefile
|
||||||
|
+++ b/drivers/i2c/busses/Makefile
|
||||||
|
@@ -80,6 +80,7 @@ obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor
|
||||||
|
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
|
||||||
|
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||||
|
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||||
|
+obj-$(CONFIG_I2C_CNS3XXX) += i2c-cns3xxx.o
|
||||||
|
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
|
||||||
|
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/i2c/busses/i2c-cns3xxx.c
|
||||||
|
@@ -0,0 +1,387 @@
|
||||||
|
+/*
|
||||||
|
+ * Cavium CNS3xxx I2C Host Controller
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2010 Cavium Network
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * 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/module.h>
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <asm/io.h>
|
||||||
|
+#include <linux/wait.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/i2c.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+#include <mach/pm.h>
|
||||||
|
+#include <mach/cns3xxx.h>
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * We need the memory map
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#define MISC_MEM_MAP_VALUE(reg_offset) (*((uint32_t volatile *)(CNS3XXX_MISC_BASE_VIRT + reg_offset)))
|
||||||
|
+#define MISC_IOCDB_CTRL MISC_MEM_MAP_VALUE(0x020)
|
||||||
|
+
|
||||||
|
+#define I2C_MEM_MAP_ADDR(x) (CNS3XXX_SSP_BASE_VIRT + x)
|
||||||
|
+#define I2C_MEM_MAP_VALUE(x) (*((unsigned int volatile*)I2C_MEM_MAP_ADDR(x)))
|
||||||
|
+
|
||||||
|
+#define I2C_CONTROLLER_REG I2C_MEM_MAP_VALUE(0x20)
|
||||||
|
+#define I2C_TIME_OUT_REG I2C_MEM_MAP_VALUE(0x24)
|
||||||
|
+#define I2C_SLAVE_ADDRESS_REG I2C_MEM_MAP_VALUE(0x28)
|
||||||
|
+#define I2C_WRITE_DATA_REG I2C_MEM_MAP_VALUE(0x2C)
|
||||||
|
+#define I2C_READ_DATA_REG I2C_MEM_MAP_VALUE(0x30)
|
||||||
|
+#define I2C_INTERRUPT_STATUS_REG I2C_MEM_MAP_VALUE(0x34)
|
||||||
|
+#define I2C_INTERRUPT_ENABLE_REG I2C_MEM_MAP_VALUE(0x38)
|
||||||
|
+#define I2C_TWI_OUT_DLY_REG I2C_MEM_MAP_VALUE(0x3C)
|
||||||
|
+
|
||||||
|
+#define I2C_BUS_ERROR_FLAG (0x1)
|
||||||
|
+#define I2C_ACTION_DONE_FLAG (0x2)
|
||||||
|
+
|
||||||
|
+#define CNS3xxx_I2C_ENABLE() (I2C_CONTROLLER_REG) |= ((unsigned int)0x1 << 31)
|
||||||
|
+#define CNS3xxx_I2C_DISABLE() (I2C_CONTROLLER_REG) &= ~((unsigned int)0x1 << 31)
|
||||||
|
+#define CNS3xxx_I2C_ENABLE_INTR() (I2C_INTERRUPT_ENABLE_REG) |= 0x03
|
||||||
|
+#define CNS3xxx_I2C_DISABLE_INTR() (I2C_INTERRUPT_ENABLE_REG) &= 0xfc
|
||||||
|
+
|
||||||
|
+#define TWI_TIMEOUT (10*HZ)
|
||||||
|
+#define I2C_100KHZ 100000
|
||||||
|
+#define I2C_200KHZ 200000
|
||||||
|
+#define I2C_300KHZ 300000
|
||||||
|
+#define I2C_400KHZ 400000
|
||||||
|
+
|
||||||
|
+#define CNS3xxx_I2C_CLK I2C_100KHZ
|
||||||
|
+
|
||||||
|
+#define STATE_DONE 1
|
||||||
|
+#define STATE_ERROR 2
|
||||||
|
+
|
||||||
|
+struct cns3xxx_i2c {
|
||||||
|
+ void __iomem *base;
|
||||||
|
+ wait_queue_head_t wait;
|
||||||
|
+ struct i2c_adapter adap;
|
||||||
|
+ struct i2c_msg *msg;
|
||||||
|
+ int state; /* see STATE_ */
|
||||||
|
+ int rd_wr_len;
|
||||||
|
+ u8 *buf;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u32 cns3xxx_i2c_func(struct i2c_adapter *adap)
|
||||||
|
+{
|
||||||
|
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+cns3xxx_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_i2c *i2c = i2c_get_adapdata(adap);
|
||||||
|
+ int i, j;
|
||||||
|
+ u8 buf[1] = { 0 };
|
||||||
|
+
|
||||||
|
+ if (msg->len == 0) {
|
||||||
|
+ /*
|
||||||
|
+ * We are probably doing a probe for a device here,
|
||||||
|
+ * so set the length to one, and data to 0
|
||||||
|
+ */
|
||||||
|
+ msg->len = 1;
|
||||||
|
+ i2c->buf = buf;
|
||||||
|
+ } else {
|
||||||
|
+ i2c->buf = msg->buf;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (msg->flags & I2C_M_TEN) {
|
||||||
|
+ printk
|
||||||
|
+ ("%s:%d: Presently the driver does not handle extended addressing\n",
|
||||||
|
+ __FUNCTION__, __LINE__);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+ i2c->msg = msg;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < msg->len; i++) {
|
||||||
|
+ if (msg->len - i >= 4)
|
||||||
|
+ i2c->rd_wr_len = 3;
|
||||||
|
+ else
|
||||||
|
+ i2c->rd_wr_len = msg->len - i - 1;
|
||||||
|
+
|
||||||
|
+ // Set Data Width and TWI_EN
|
||||||
|
+ I2C_CONTROLLER_REG = 0x80000000 | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len);
|
||||||
|
+
|
||||||
|
+ // Clear Write Reg
|
||||||
|
+ I2C_WRITE_DATA_REG = 0;
|
||||||
|
+
|
||||||
|
+ // Set the slave address
|
||||||
|
+ I2C_SLAVE_ADDRESS_REG = (msg->addr << 1);
|
||||||
|
+
|
||||||
|
+ // Are we Writing
|
||||||
|
+ if (!(msg->flags & I2C_M_RD)) {
|
||||||
|
+ I2C_CONTROLLER_REG |= (1 << 4);
|
||||||
|
+ if (i != 0) {
|
||||||
|
+ /*
|
||||||
|
+ * We need to set the address in the first byte.
|
||||||
|
+ * The base address is going to be in buf[0] and then
|
||||||
|
+ * it needs to be incremented by i - 1.
|
||||||
|
+ */
|
||||||
|
+ i2c->buf--;
|
||||||
|
+ *i2c->buf = buf[0] + i - 1;
|
||||||
|
+
|
||||||
|
+ if (i2c->rd_wr_len < 3) {
|
||||||
|
+ i += i2c->rd_wr_len;
|
||||||
|
+ i2c->rd_wr_len++;
|
||||||
|
+ I2C_CONTROLLER_REG = 0x80000000 | (1 << 4) | (i2c->rd_wr_len << 2) | (i2c->rd_wr_len);
|
||||||
|
+ } else {
|
||||||
|
+ i += i2c->rd_wr_len - 1;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ i += i2c->rd_wr_len;
|
||||||
|
+ buf[0] = *i2c->buf;
|
||||||
|
+ }
|
||||||
|
+ for (j = 0; j <= i2c->rd_wr_len; j++) {
|
||||||
|
+ I2C_WRITE_DATA_REG |= ((*i2c->buf++) << (8 * j));
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ i += i2c->rd_wr_len;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Start the Transfer
|
||||||
|
+ i2c->state = 0; // Clear out the State
|
||||||
|
+ I2C_CONTROLLER_REG |= (1 << 6);
|
||||||
|
+
|
||||||
|
+ if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) ||
|
||||||
|
+ (i2c->state == STATE_DONE), TWI_TIMEOUT)) {
|
||||||
|
+ if (i2c->state == STATE_ERROR) {
|
||||||
|
+ return -EIO;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ return -ETIMEDOUT;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int
|
||||||
|
+cns3xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
|
||||||
|
+{
|
||||||
|
+ int i;
|
||||||
|
+ int ret;
|
||||||
|
+ for (i = 0; i < num; i++)
|
||||||
|
+ {
|
||||||
|
+ ret = cns3xxx_i2c_xfer_msg(adap, &msgs[i]);
|
||||||
|
+ if (ret < 0) {
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return num;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static struct i2c_algorithm cns3xxx_i2c_algo = {
|
||||||
|
+ .master_xfer = cns3xxx_i2c_xfer,
|
||||||
|
+ .functionality = cns3xxx_i2c_func,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct i2c_adapter cns3xxx_i2c_adapter = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .algo = &cns3xxx_i2c_algo,
|
||||||
|
+ .algo_data = NULL,
|
||||||
|
+ .nr = 0,
|
||||||
|
+ .name = "CNS3xxx I2C 0",
|
||||||
|
+ .retries = 5,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void cns3xxx_i2c_adapter_init(struct cns3xxx_i2c *i2c)
|
||||||
|
+{
|
||||||
|
+ cns3xxx_pwr_clk_en(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||||
|
+ cns3xxx_pwr_power_up(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||||
|
+ cns3xxx_pwr_soft_rst(1 << PM_CLK_GATE_REG_OFFSET_SPI_PCM_I2C);
|
||||||
|
+
|
||||||
|
+ /* Disable the I2C */
|
||||||
|
+ I2C_CONTROLLER_REG = 0; /* Disabled the I2C */
|
||||||
|
+
|
||||||
|
+ //enable SCL and SDA which share pin with GPIOB_PIN_EN(0x18)
|
||||||
|
+ //GPIOB[12]: SCL
|
||||||
|
+ //GPIOB[13]: SDA
|
||||||
|
+ (*(u32*)(CNS3XXX_MISC_BASE_VIRT+0x18)) |= ((1<<12)|(1<<13));
|
||||||
|
+
|
||||||
|
+ MISC_IOCDB_CTRL &= ~0x300;
|
||||||
|
+ MISC_IOCDB_CTRL |= 0x300; //21mA...
|
||||||
|
+
|
||||||
|
+ /* Check the Reg Dump when testing */
|
||||||
|
+ I2C_TIME_OUT_REG =
|
||||||
|
+ ((((((cns3xxx_cpu_clock()*(1000000/8)) / (2 * CNS3xxx_I2C_CLK)) -
|
||||||
|
+ 1) & 0x3FF) << 8) | (1 << 7) | 0x7F);
|
||||||
|
+ I2C_TWI_OUT_DLY_REG |= 0x3;
|
||||||
|
+
|
||||||
|
+ /* Enable The Interrupt */
|
||||||
|
+ CNS3xxx_I2C_ENABLE_INTR();
|
||||||
|
+
|
||||||
|
+ /* Clear Interrupt Status (0x2 | 0x1) */
|
||||||
|
+ I2C_INTERRUPT_STATUS_REG |= (I2C_ACTION_DONE_FLAG | I2C_BUS_ERROR_FLAG);
|
||||||
|
+
|
||||||
|
+ /* Enable the I2C Controller */
|
||||||
|
+ CNS3xxx_I2C_ENABLE();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static irqreturn_t cns3xxx_i2c_isr(int irq, void *dev_id)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_i2c *i2c = dev_id;
|
||||||
|
+ int i;
|
||||||
|
+ uint32_t stat = I2C_INTERRUPT_STATUS_REG;
|
||||||
|
+
|
||||||
|
+ /* Clear Interrupt */
|
||||||
|
+ I2C_INTERRUPT_STATUS_REG |= 0x1;
|
||||||
|
+
|
||||||
|
+ if (stat & I2C_BUS_ERROR_FLAG) {
|
||||||
|
+ i2c->state = STATE_ERROR;
|
||||||
|
+ } else {
|
||||||
|
+ if (i2c->msg->flags & I2C_M_RD) {
|
||||||
|
+ for (i = 0; i <= i2c->rd_wr_len; i++)
|
||||||
|
+ {
|
||||||
|
+ *i2c->buf++ = ((I2C_READ_DATA_REG >> (8 * i)) & 0xff);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ i2c->state = STATE_DONE;
|
||||||
|
+ }
|
||||||
|
+ wake_up(&i2c->wait);
|
||||||
|
+ return IRQ_HANDLED;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __devinit cns3xxx_i2c_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_i2c *i2c;
|
||||||
|
+ struct resource *res, *res2;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (!res) {
|
||||||
|
+ printk("%s: IORESOURCE_MEM not defined \n", __FUNCTION__);
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
+ if (!res2) {
|
||||||
|
+ printk("%s: IORESOURCE_IRQ not defined \n", __FUNCTION__);
|
||||||
|
+ return -ENODEV;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
|
||||||
|
+ if (!i2c)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ if (!request_mem_region(res->start, res->end - res->start + 1,
|
||||||
|
+ pdev->name)) {
|
||||||
|
+ dev_err(&pdev->dev, "Memory region busy\n");
|
||||||
|
+ ret = -EBUSY;
|
||||||
|
+ goto request_mem_failed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i2c->base = ioremap(res->start, res->end - res->start + 1);
|
||||||
|
+ if (!i2c->base) {
|
||||||
|
+ dev_err(&pdev->dev, "Unable to map registers\n");
|
||||||
|
+ ret = -EIO;
|
||||||
|
+ goto map_failed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ cns3xxx_i2c_adapter_init(i2c);
|
||||||
|
+
|
||||||
|
+ init_waitqueue_head(&i2c->wait);
|
||||||
|
+ ret = request_irq(res2->start, cns3xxx_i2c_isr, 0, pdev->name, i2c);
|
||||||
|
+ if (ret) {
|
||||||
|
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
|
||||||
|
+ goto request_irq_failed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, i2c);
|
||||||
|
+ i2c->adap = cns3xxx_i2c_adapter;
|
||||||
|
+ i2c_set_adapdata(&i2c->adap, i2c);
|
||||||
|
+ i2c->adap.dev.parent = &pdev->dev;
|
||||||
|
+
|
||||||
|
+ /* add i2c adapter to i2c tree */
|
||||||
|
+ ret = i2c_add_numbered_adapter(&i2c->adap);
|
||||||
|
+ if (ret) {
|
||||||
|
+ dev_err(&pdev->dev, "Failed to add adapter\n");
|
||||||
|
+ goto add_adapter_failed;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ add_adapter_failed:
|
||||||
|
+ free_irq(res2->start, i2c);
|
||||||
|
+ request_irq_failed:
|
||||||
|
+ iounmap(i2c->base);
|
||||||
|
+ map_failed:
|
||||||
|
+ release_mem_region(res->start, res->end - res->start + 1);
|
||||||
|
+ request_mem_failed:
|
||||||
|
+ kfree(i2c);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __devexit cns3xxx_i2c_remove(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_i2c *i2c = platform_get_drvdata(pdev);
|
||||||
|
+ struct resource *res;
|
||||||
|
+
|
||||||
|
+ /* disable i2c logic */
|
||||||
|
+ CNS3xxx_I2C_DISABLE_INTR();
|
||||||
|
+ CNS3xxx_I2C_DISABLE();
|
||||||
|
+ /* remove adapter & data */
|
||||||
|
+ i2c_del_adapter(&i2c->adap);
|
||||||
|
+ platform_set_drvdata(pdev, NULL);
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||||
|
+ if (res)
|
||||||
|
+ free_irq(res->start, i2c);
|
||||||
|
+
|
||||||
|
+ iounmap(i2c->base);
|
||||||
|
+
|
||||||
|
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
+ if (res)
|
||||||
|
+ release_mem_region(res->start, res->end - res->start + 1);
|
||||||
|
+
|
||||||
|
+ kfree(i2c);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef CONFIG_PM
|
||||||
|
+#warning "CONFIG_PM defined: suspend and resume not implemented"
|
||||||
|
+#define cns3xxx_i2c_suspend NULL
|
||||||
|
+#define cns3xxx_i2c_resume NULL
|
||||||
|
+#else
|
||||||
|
+#define cns3xxx_i2c_suspend NULL
|
||||||
|
+#define cns3xxx_i2c_resume NULL
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static struct platform_driver cns3xxx_i2c_driver = {
|
||||||
|
+ .probe = cns3xxx_i2c_probe,
|
||||||
|
+ .remove = cns3xxx_i2c_remove,
|
||||||
|
+ .suspend = cns3xxx_i2c_suspend,
|
||||||
|
+ .resume = cns3xxx_i2c_resume,
|
||||||
|
+ .driver = {
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ .name = "cns3xxx-i2c",
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init cns3xxx_i2c_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_register(&cns3xxx_i2c_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit cns3xxx_i2c_exit(void)
|
||||||
|
+{
|
||||||
|
+ platform_driver_unregister(&cns3xxx_i2c_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(cns3xxx_i2c_init);
|
||||||
|
+module_exit(cns3xxx_i2c_exit);
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Cavium Networks");
|
||||||
|
+MODULE_DESCRIPTION("Cavium CNS3XXX I2C Controller");
|
||||||
|
+MODULE_LICENSE("GPL");
|
1337
target/linux/cns3xxx/patches-3.0/051-cns3xxx_gigabit.patch
Normal file
1337
target/linux/cns3xxx/patches-3.0/051-cns3xxx_gigabit.patch
Normal file
File diff suppressed because it is too large
Load Diff
509
target/linux/cns3xxx/patches-3.0/052-cns3xxx_spi.patch
Normal file
509
target/linux/cns3xxx/patches-3.0/052-cns3xxx_spi.patch
Normal file
@ -0,0 +1,509 @@
|
|||||||
|
--- a/drivers/spi/Kconfig
|
||||||
|
+++ b/drivers/spi/Kconfig
|
||||||
|
@@ -123,6 +123,13 @@ config SPI_BUTTERFLY
|
||||||
|
inexpensive battery powered microcontroller evaluation board.
|
||||||
|
This same cable can be used to flash new firmware.
|
||||||
|
|
||||||
|
+config SPI_CNS3XXX
|
||||||
|
+ tristate "CNS3XXX SPI controller"
|
||||||
|
+ depends on ARCH_CNS3XXX && SPI_MASTER
|
||||||
|
+ select SPI_BITBANG
|
||||||
|
+ help
|
||||||
|
+ This enables using the CNS3XXX SPI controller in master mode.
|
||||||
|
+
|
||||||
|
config SPI_COLDFIRE_QSPI
|
||||||
|
tristate "Freescale Coldfire QSPI controller"
|
||||||
|
depends on (M520x || M523x || M5249 || M527x || M528x || M532x)
|
||||||
|
--- a/drivers/spi/Makefile
|
||||||
|
+++ b/drivers/spi/Makefile
|
||||||
|
@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.
|
||||||
|
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
|
||||||
|
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
|
||||||
|
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
|
||||||
|
+obj-$(CONFIG_SPI_CNS3XXX) += spi_cns3xxx.o
|
||||||
|
|
||||||
|
# special build for s3c24xx spi driver with fiq support
|
||||||
|
spi_s3c24xx_hw-y := spi_s3c24xx.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/spi/spi_cns3xxx.c
|
||||||
|
@@ -0,0 +1,449 @@
|
||||||
|
+/*******************************************************************************
|
||||||
|
+ *
|
||||||
|
+ * CNS3XXX SPI controller driver (master mode only)
|
||||||
|
+ *
|
||||||
|
+ * Copyright (c) 2008 Cavium Networks
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * 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.
|
||||||
|
+ *
|
||||||
|
+ * This file is distributed in the hope that it will be useful,
|
||||||
|
+ * but AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
|
||||||
|
+ * NONINFRINGEMENT. See the GNU General Public License for more details.
|
||||||
|
+ *
|
||||||
|
+ * You should have received a copy of the GNU General Public License
|
||||||
|
+ * along with this file; if not, write to the Free Software
|
||||||
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA or
|
||||||
|
+ * visit http://www.gnu.org/licenses/.
|
||||||
|
+ *
|
||||||
|
+ * This file may also be available under a different license from Cavium.
|
||||||
|
+ * Contact Cavium Networks for more information
|
||||||
|
+ *
|
||||||
|
+ ******************************************************************************/
|
||||||
|
+
|
||||||
|
+#include <linux/init.h>
|
||||||
|
+#include <linux/spinlock.h>
|
||||||
|
+#include <linux/workqueue.h>
|
||||||
|
+#include <linux/interrupt.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
+#include <linux/errno.h>
|
||||||
|
+#include <linux/err.h>
|
||||||
|
+#include <linux/clk.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/spi/spi_bitbang.h>
|
||||||
|
+#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/dma-mapping.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+
|
||||||
|
+#include <asm/io.h>
|
||||||
|
+#include <asm/memory.h>
|
||||||
|
+#include <asm/dma.h>
|
||||||
|
+#include <asm/delay.h>
|
||||||
|
+#include <mach/cns3xxx.h>
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <mach/pm.h>
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * define access macros
|
||||||
|
+ */
|
||||||
|
+#define SPI_MEM_MAP_VALUE(reg_offset) (*((u32 volatile *)(CNS3XXX_SSP_BASE_VIRT + reg_offset)))
|
||||||
|
+
|
||||||
|
+#define SPI_CONFIGURATION_REG SPI_MEM_MAP_VALUE(0x40)
|
||||||
|
+#define SPI_SERVICE_STATUS_REG SPI_MEM_MAP_VALUE(0x44)
|
||||||
|
+#define SPI_BIT_RATE_CONTROL_REG SPI_MEM_MAP_VALUE(0x48)
|
||||||
|
+#define SPI_TRANSMIT_CONTROL_REG SPI_MEM_MAP_VALUE(0x4C)
|
||||||
|
+#define SPI_TRANSMIT_BUFFER_REG SPI_MEM_MAP_VALUE(0x50)
|
||||||
|
+#define SPI_RECEIVE_CONTROL_REG SPI_MEM_MAP_VALUE(0x54)
|
||||||
|
+#define SPI_RECEIVE_BUFFER_REG SPI_MEM_MAP_VALUE(0x58)
|
||||||
|
+#define SPI_FIFO_TRANSMIT_CONFIG_REG SPI_MEM_MAP_VALUE(0x5C)
|
||||||
|
+#define SPI_FIFO_TRANSMIT_CONTROL_REG SPI_MEM_MAP_VALUE(0x60)
|
||||||
|
+#define SPI_FIFO_RECEIVE_CONFIG_REG SPI_MEM_MAP_VALUE(0x64)
|
||||||
|
+#define SPI_INTERRUPT_STATUS_REG SPI_MEM_MAP_VALUE(0x68)
|
||||||
|
+#define SPI_INTERRUPT_ENABLE_REG SPI_MEM_MAP_VALUE(0x6C)
|
||||||
|
+
|
||||||
|
+#define SPI_TRANSMIT_BUFFER_REG_ADDR (CNS3XXX_SSP_BASE +0x50)
|
||||||
|
+#define SPI_RECEIVE_BUFFER_REG_ADDR (CNS3XXX_SSP_BASE +0x58)
|
||||||
|
+
|
||||||
|
+/* Structure for SPI controller of CNS3XXX SOCs */
|
||||||
|
+struct cns3xxx_spi {
|
||||||
|
+ /* bitbang has to be first */
|
||||||
|
+ struct spi_bitbang bitbang;
|
||||||
|
+ struct completion done;
|
||||||
|
+ wait_queue_head_t wait;
|
||||||
|
+
|
||||||
|
+ int len;
|
||||||
|
+ int count;
|
||||||
|
+ int last_in_message_list;
|
||||||
|
+
|
||||||
|
+ /* data buffers */
|
||||||
|
+ const unsigned char *tx;
|
||||||
|
+ unsigned char *rx;
|
||||||
|
+
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct platform_device *pdev;
|
||||||
|
+ struct device *dev;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static inline u8 cns3xxx_spi_bus_idle(void)
|
||||||
|
+{
|
||||||
|
+ return ((SPI_SERVICE_STATUS_REG & 0x1) ? 0 : 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u8 cns3xxx_spi_tx_buffer_empty(void)
|
||||||
|
+{
|
||||||
|
+ return ((SPI_INTERRUPT_STATUS_REG & (0x1 << 3)) ? 1 : 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline u8 cns3xxx_spi_rx_buffer_full(void)
|
||||||
|
+{
|
||||||
|
+ return ((SPI_INTERRUPT_STATUS_REG & (0x1 << 2)) ? 1 : 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+u8 cns3xxx_spi_tx_rx(u8 tx_channel, u8 tx_eof, u32 tx_data,
|
||||||
|
+ u32 * rx_data)
|
||||||
|
+{
|
||||||
|
+ u8 rx_channel;
|
||||||
|
+ u8 rx_eof;
|
||||||
|
+
|
||||||
|
+ while (!cns3xxx_spi_bus_idle()) ; // do nothing
|
||||||
|
+
|
||||||
|
+ while (!cns3xxx_spi_tx_buffer_empty()) ; // do nothing
|
||||||
|
+
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG &= ~(0x7);
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG |= (tx_channel & 0x3) | ((tx_eof & 0x1) << 2);
|
||||||
|
+
|
||||||
|
+ SPI_TRANSMIT_BUFFER_REG = tx_data;
|
||||||
|
+
|
||||||
|
+ while (!cns3xxx_spi_rx_buffer_full()) ; // do nothing
|
||||||
|
+
|
||||||
|
+ rx_channel = SPI_RECEIVE_CONTROL_REG & 0x3;
|
||||||
|
+ rx_eof = (SPI_RECEIVE_CONTROL_REG & (0x1 << 2)) ? 1 : 0;
|
||||||
|
+
|
||||||
|
+ *rx_data = SPI_RECEIVE_BUFFER_REG;
|
||||||
|
+
|
||||||
|
+ if ((tx_channel != rx_channel) || (tx_eof != rx_eof)) {
|
||||||
|
+ return 0;
|
||||||
|
+ } else {
|
||||||
|
+ return 1;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+u8 cns3xxx_spi_tx(u8 tx_channel, u8 tx_eof, u32 tx_data)
|
||||||
|
+{
|
||||||
|
+
|
||||||
|
+ while (!cns3xxx_spi_bus_idle()) ; // do nothing
|
||||||
|
+
|
||||||
|
+ while (!cns3xxx_spi_tx_buffer_empty()) ; // do nothing
|
||||||
|
+
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG &= ~(0x7);
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG |= (tx_channel & 0x3) | ((tx_eof & 0x1) << 2);
|
||||||
|
+
|
||||||
|
+ SPI_TRANSMIT_BUFFER_REG = tx_data;
|
||||||
|
+
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline struct cns3xxx_spi *to_hw(struct spi_device *sdev)
|
||||||
|
+{
|
||||||
|
+ return spi_master_get_devdata(sdev->master);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_spi_setup_transfer(struct spi_device *spi,
|
||||||
|
+ struct spi_transfer *t)
|
||||||
|
+{
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void cns3xxx_spi_chipselect(struct spi_device *spi, int value)
|
||||||
|
+{
|
||||||
|
+ unsigned int spi_config;
|
||||||
|
+
|
||||||
|
+ switch (value) {
|
||||||
|
+ case BITBANG_CS_INACTIVE:
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ case BITBANG_CS_ACTIVE:
|
||||||
|
+ spi_config = SPI_CONFIGURATION_REG;
|
||||||
|
+
|
||||||
|
+ if (spi->mode & SPI_CPHA)
|
||||||
|
+ spi_config |= (0x1 << 13);
|
||||||
|
+ else
|
||||||
|
+ spi_config &= ~(0x1 << 13);
|
||||||
|
+
|
||||||
|
+ if (spi->mode & SPI_CPOL)
|
||||||
|
+ spi_config |= (0x1 << 14);
|
||||||
|
+ else
|
||||||
|
+ spi_config &= ~(0x1 << 14);
|
||||||
|
+
|
||||||
|
+ /* write new configration */
|
||||||
|
+ SPI_CONFIGURATION_REG = spi_config;
|
||||||
|
+
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG &= ~(0x7);
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG |= (spi->chip_select & 0x3);
|
||||||
|
+
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_spi_setup(struct spi_device *spi)
|
||||||
|
+{
|
||||||
|
+ if (!spi->bits_per_word)
|
||||||
|
+ spi->bits_per_word = 8;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_spi *hw = to_hw(spi);
|
||||||
|
+
|
||||||
|
+ dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", t->tx_buf, t->rx_buf,
|
||||||
|
+ t->len);
|
||||||
|
+
|
||||||
|
+ hw->tx = t->tx_buf;
|
||||||
|
+ hw->rx = t->rx_buf;
|
||||||
|
+ hw->len = t->len;
|
||||||
|
+ hw->count = 0;
|
||||||
|
+ hw->last_in_message_list = t->last_in_message_list;
|
||||||
|
+
|
||||||
|
+ init_completion(&hw->done);
|
||||||
|
+
|
||||||
|
+ if (hw->tx) {
|
||||||
|
+ int i;
|
||||||
|
+ u32 rx_data;
|
||||||
|
+ for (i = 0; i < (hw->len - 1); i++) {
|
||||||
|
+ dev_dbg(&spi->dev,
|
||||||
|
+ "[SPI_CNS3XXX_DEBUG] hw->tx[%02d]: 0x%02x\n", i,
|
||||||
|
+ hw->tx[i]);
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 0, hw->tx[i],
|
||||||
|
+ &rx_data);
|
||||||
|
+ if (hw->rx) {
|
||||||
|
+ hw->rx[i] = rx_data;
|
||||||
|
+ dev_dbg(&spi->dev,
|
||||||
|
+ "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n",
|
||||||
|
+ i, hw->rx[i]);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (t->last_in_message_list) {
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 1, hw->tx[i],
|
||||||
|
+ &rx_data);
|
||||||
|
+ if (hw->rx) {
|
||||||
|
+ hw->rx[i] = rx_data;
|
||||||
|
+ dev_dbg(&spi->dev,
|
||||||
|
+ "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n",
|
||||||
|
+ i, hw->rx[i]);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 0, hw->tx[i],
|
||||||
|
+ &rx_data);
|
||||||
|
+ }
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (hw->rx) {
|
||||||
|
+ int i;
|
||||||
|
+ u32 rx_data;
|
||||||
|
+ for (i = 0; i < (hw->len - 1); i++) {
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 0, 0xff, &rx_data);
|
||||||
|
+ hw->rx[i] = rx_data;
|
||||||
|
+ dev_dbg(&spi->dev,
|
||||||
|
+ "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n", i,
|
||||||
|
+ hw->rx[i]);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (t->last_in_message_list) {
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 1, 0xff, &rx_data);
|
||||||
|
+ } else {
|
||||||
|
+ cns3xxx_spi_tx_rx(spi->chip_select, 0, 0xff, &rx_data);
|
||||||
|
+ }
|
||||||
|
+ hw->rx[i] = rx_data;
|
||||||
|
+ dev_dbg(&spi->dev, "[SPI_CNS3XXX_DEBUG] hw->rx[%02d]: 0x%02x\n",
|
||||||
|
+ i, hw->rx[i]);
|
||||||
|
+ }
|
||||||
|
+done:
|
||||||
|
+ return hw->len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __init cns3xxx_spi_initial(void)
|
||||||
|
+{
|
||||||
|
+ u32 __iomem *gpiob = __io(CNS3XXX_MISC_BASE_VIRT + 0x0018);
|
||||||
|
+ u32 gpiob_pins = __raw_readl(gpiob);
|
||||||
|
+
|
||||||
|
+ /* MMC/SD pins share with GPIOA */
|
||||||
|
+ gpiob_pins |= 0xf80;
|
||||||
|
+ __raw_writel(gpiob_pins, gpiob);
|
||||||
|
+
|
||||||
|
+ /* share pin config. */
|
||||||
|
+ //PM_PLL_HM_PD_CTRL_REG &= ~(0x1 << 5);
|
||||||
|
+ //HAL_MISC_ENABLE_SPI_PINS();
|
||||||
|
+ cns3xxx_pwr_clk_en(CNS3XXX_PWR_CLK_EN(SPI_PCM_I2C));
|
||||||
|
+ cns3xxx_pwr_soft_rst(CNS3XXX_PWR_SOFTWARE_RST(SPI_PCM_I2C));
|
||||||
|
+
|
||||||
|
+ SPI_CONFIGURATION_REG = (((0x0 & 0x3) << 0) | /* 8bits shift length */
|
||||||
|
+ (0x0 << 9) | /* SPI mode */
|
||||||
|
+ (0x0 << 10) | /* disable FIFO */
|
||||||
|
+ (0x1 << 11) | /* SPI master mode */
|
||||||
|
+ (0x0 << 12) | /* disable SPI loopback mode */
|
||||||
|
+ (0x1 << 13) | /* clock phase */
|
||||||
|
+ (0x1 << 14) | /* clock polarity */
|
||||||
|
+ (0x0 << 24) | /* disable - SPI data swap */
|
||||||
|
+ (0x1 << 29) | /* enable - 2IO Read mode */
|
||||||
|
+ (0x0 << 30) | /* disable - SPI high speed read for system boot up */
|
||||||
|
+ (0x0 << 31)); /* disable - SPI */
|
||||||
|
+
|
||||||
|
+ /* Set SPI bit rate PCLK/2 */
|
||||||
|
+ SPI_BIT_RATE_CONTROL_REG = 0x1;
|
||||||
|
+
|
||||||
|
+ /* Set SPI Tx channel 0 */
|
||||||
|
+ SPI_TRANSMIT_CONTROL_REG = 0x0;
|
||||||
|
+
|
||||||
|
+ /* Set Tx FIFO Threshold, Tx FIFO has 2 words */
|
||||||
|
+ SPI_FIFO_TRANSMIT_CONFIG_REG &= ~(0x03 << 4);
|
||||||
|
+ SPI_FIFO_TRANSMIT_CONFIG_REG |= ((0x0 & 0x03) << 4);
|
||||||
|
+
|
||||||
|
+ /* Set Rx FIFO Threshold, Rx FIFO has 2 words */
|
||||||
|
+ SPI_FIFO_RECEIVE_CONFIG_REG &= ~(0x03 << 4);
|
||||||
|
+ SPI_FIFO_RECEIVE_CONFIG_REG |= ((0x0 & 0x03) << 4);
|
||||||
|
+
|
||||||
|
+ /* Disable all interrupt */
|
||||||
|
+ SPI_INTERRUPT_ENABLE_REG = 0x0;
|
||||||
|
+
|
||||||
|
+ /* Clear spurious interrupt sources */
|
||||||
|
+ SPI_INTERRUPT_STATUS_REG = (0x0F << 4);
|
||||||
|
+
|
||||||
|
+ /* Enable SPI */
|
||||||
|
+ SPI_CONFIGURATION_REG |= (0x1 << 31);
|
||||||
|
+
|
||||||
|
+ return;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __init cns3xxx_spi_probe(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct spi_master *master;
|
||||||
|
+ struct cns3xxx_spi *hw;
|
||||||
|
+ int err = 0;
|
||||||
|
+
|
||||||
|
+ printk("%s: setup CNS3XXX SPI Controller\n", __FUNCTION__);
|
||||||
|
+
|
||||||
|
+ /* Allocate master with space for cns3xxx_spi */
|
||||||
|
+ master = spi_alloc_master(&pdev->dev, sizeof(struct cns3xxx_spi));
|
||||||
|
+ if (master == NULL) {
|
||||||
|
+ dev_err(&pdev->dev, "No memory for spi_master\n");
|
||||||
|
+ err = -ENOMEM;
|
||||||
|
+ goto err_nomem;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ hw = spi_master_get_devdata(master);
|
||||||
|
+ memset(hw, 0, sizeof(struct cns3xxx_spi));
|
||||||
|
+
|
||||||
|
+ hw->master = spi_master_get(master);
|
||||||
|
+ hw->dev = &pdev->dev;
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(pdev, hw);
|
||||||
|
+ init_completion(&hw->done);
|
||||||
|
+
|
||||||
|
+ /* setup the master state. */
|
||||||
|
+
|
||||||
|
+ master->num_chipselect = 4;
|
||||||
|
+ master->bus_num = 1;
|
||||||
|
+
|
||||||
|
+ /* setup the state for the bitbang driver */
|
||||||
|
+
|
||||||
|
+ hw->bitbang.master = hw->master;
|
||||||
|
+ hw->bitbang.setup_transfer = cns3xxx_spi_setup_transfer;
|
||||||
|
+ hw->bitbang.chipselect = cns3xxx_spi_chipselect;
|
||||||
|
+ hw->bitbang.txrx_bufs = cns3xxx_spi_txrx;
|
||||||
|
+ hw->bitbang.master->setup = cns3xxx_spi_setup;
|
||||||
|
+
|
||||||
|
+ dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
|
||||||
|
+
|
||||||
|
+ /* SPI controller initializations */
|
||||||
|
+ cns3xxx_spi_initial();
|
||||||
|
+
|
||||||
|
+ /* register SPI controller */
|
||||||
|
+
|
||||||
|
+ err = spi_bitbang_start(&hw->bitbang);
|
||||||
|
+ if (err) {
|
||||||
|
+ dev_err(&pdev->dev, "Failed to register SPI master\n");
|
||||||
|
+ goto err_register;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+err_register:
|
||||||
|
+ spi_master_put(hw->master);;
|
||||||
|
+
|
||||||
|
+err_nomem:
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __devexit cns3xxx_spi_remove(struct platform_device *dev)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_spi *hw = platform_get_drvdata(dev);
|
||||||
|
+
|
||||||
|
+ platform_set_drvdata(dev, NULL);
|
||||||
|
+
|
||||||
|
+ spi_unregister_master(hw->master);
|
||||||
|
+
|
||||||
|
+ spi_master_put(hw->master);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef CONFIG_PM
|
||||||
|
+
|
||||||
|
+static int cns3xxx_spi_suspend(struct platform_device *pdev, pm_message_t msg)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_spi *hw = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_spi_resume(struct platform_device *pdev)
|
||||||
|
+{
|
||||||
|
+ struct cns3xxx_spi *hw = platform_get_drvdata(pdev);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+#define cns3xxx_spi_suspend NULL
|
||||||
|
+#define cns3xxx_spi_resume NULL
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static struct platform_driver cns3xxx_spi_driver = {
|
||||||
|
+ .probe = cns3xxx_spi_probe,
|
||||||
|
+ .remove = __devexit_p(cns3xxx_spi_remove),
|
||||||
|
+ .suspend = cns3xxx_spi_suspend,
|
||||||
|
+ .resume = cns3xxx_spi_resume,
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "cns3xxx_spi",
|
||||||
|
+ .owner = THIS_MODULE,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int __init cns3xxx_spi_init(void)
|
||||||
|
+{
|
||||||
|
+ return platform_driver_register(&cns3xxx_spi_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit cns3xxx_spi_exit(void)
|
||||||
|
+{
|
||||||
|
+ platform_driver_unregister(&cns3xxx_spi_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(cns3xxx_spi_init);
|
||||||
|
+module_exit(cns3xxx_spi_exit);
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Cavium Networks");
|
||||||
|
+MODULE_DESCRIPTION("CNS3XXX SPI Controller Driver");
|
||||||
|
+MODULE_LICENSE("GPL");
|
||||||
|
+MODULE_ALIAS("platform:cns3xxx_spi");
|
||||||
|
+
|
||||||
|
+EXPORT_SYMBOL_GPL(cns3xxx_spi_tx_rx);
|
||||||
|
--- a/include/linux/spi/spi.h
|
||||||
|
+++ b/include/linux/spi/spi.h
|
||||||
|
@@ -446,6 +446,13 @@ struct spi_transfer {
|
||||||
|
u32 speed_hz;
|
||||||
|
|
||||||
|
struct list_head transfer_list;
|
||||||
|
+
|
||||||
|
+#ifdef CONFIG_ARCH_CNS3XXX
|
||||||
|
+ unsigned last_in_message_list;
|
||||||
|
+#ifdef CONFIG_SPI_CNS3XXX_2IOREAD
|
||||||
|
+ u8 dio_read;
|
||||||
|
+#endif
|
||||||
|
+#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
--- a/drivers/spi/spi_bitbang.c
|
||||||
|
+++ b/drivers/spi/spi_bitbang.c
|
||||||
|
@@ -329,6 +329,12 @@ 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)
|
77
target/linux/cns3xxx/patches-3.0/053-cns3xxx_wdt.patch
Normal file
77
target/linux/cns3xxx/patches-3.0/053-cns3xxx_wdt.patch
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
--- a/drivers/watchdog/Kconfig
|
||||||
|
+++ b/drivers/watchdog/Kconfig
|
||||||
|
@@ -188,7 +188,7 @@ config SA1100_WATCHDOG
|
||||||
|
|
||||||
|
config MPCORE_WATCHDOG
|
||||||
|
tristate "MPcore watchdog"
|
||||||
|
- depends on HAVE_ARM_TWD
|
||||||
|
+ depends on ARCH_CNS3XXX
|
||||||
|
help
|
||||||
|
Watchdog timer embedded into the MPcore system.
|
||||||
|
|
||||||
|
--- a/drivers/watchdog/mpcore_wdt.c
|
||||||
|
+++ b/drivers/watchdog/mpcore_wdt.c
|
||||||
|
@@ -32,11 +32,14 @@
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
+#include <linux/jiffies.h>
|
||||||
|
+#include <linux/delay.h>
|
||||||
|
|
||||||
|
#include <asm/smp_twd.h>
|
||||||
|
|
||||||
|
struct mpcore_wdt {
|
||||||
|
unsigned long timer_alive;
|
||||||
|
+ unsigned long timer_rate;
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
|
int irq;
|
||||||
|
@@ -98,14 +101,12 @@ static void mpcore_wdt_keepalive(struct
|
||||||
|
unsigned long count;
|
||||||
|
|
||||||
|
spin_lock(&wdt_lock);
|
||||||
|
- /* Assume prescale is set to 256 */
|
||||||
|
- count = __raw_readl(wdt->base + TWD_WDOG_COUNTER);
|
||||||
|
- count = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||||
|
- count = (count / 256) * mpcore_margin;
|
||||||
|
+ count = (wdt->timer_rate / 256) * mpcore_margin;
|
||||||
|
|
||||||
|
/* Reload the counter */
|
||||||
|
writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
|
||||||
|
wdt->perturb = wdt->perturb ? 0 : 1;
|
||||||
|
+
|
||||||
|
spin_unlock(&wdt_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -329,6 +330,8 @@ static int __devinit mpcore_wdt_probe(st
|
||||||
|
struct mpcore_wdt *wdt;
|
||||||
|
struct resource *res;
|
||||||
|
int ret;
|
||||||
|
+ unsigned long count;
|
||||||
|
+ u64 waitjiffies;
|
||||||
|
|
||||||
|
/* We only accept one device, and it must have an id of -1 */
|
||||||
|
if (dev->id != -1)
|
||||||
|
@@ -375,6 +378,22 @@ static int __devinit mpcore_wdt_probe(st
|
||||||
|
goto err_irq;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ waitjiffies = get_jiffies_64() + 1;
|
||||||
|
+ while (get_jiffies_64() < waitjiffies)
|
||||||
|
+ udelay(10);
|
||||||
|
+
|
||||||
|
+ waitjiffies += 5;
|
||||||
|
+
|
||||||
|
+ __raw_writel(0x00000001, wdt->base + TWD_WDOG_CONTROL);
|
||||||
|
+ __raw_writel(0xFFFFFFFFU, wdt->base + TWD_WDOG_LOAD);
|
||||||
|
+
|
||||||
|
+ while (get_jiffies_64() < waitjiffies)
|
||||||
|
+ udelay(10);
|
||||||
|
+
|
||||||
|
+ count = __raw_readl(wdt->base + TWD_WDOG_COUNTER);
|
||||||
|
+
|
||||||
|
+ wdt->timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
|
||||||
|
+
|
||||||
|
mpcore_wdt_stop(wdt);
|
||||||
|
platform_set_drvdata(dev, wdt);
|
||||||
|
mpcore_wdt_dev = dev;
|
@ -0,0 +1,11 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/pcie.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/pcie.c
|
||||||
|
@@ -375,8 +375,6 @@ static int __init cns3xxx_pcie_init(void
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
|
||||||
|
iotable_init(cns3xxx_pcie[i].cfg_bases,
|
||||||
|
ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
|
||||||
|
- cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
|
||||||
|
- cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
|
||||||
|
cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
|
||||||
|
cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
|
||||||
|
pci_common_init(&cns3xxx_pcie[i].hw_pci);
|
993
target/linux/cns3xxx/patches-3.0/100-laguna_support.patch
Normal file
993
target/linux/cns3xxx/patches-3.0/100-laguna_support.patch
Normal file
@ -0,0 +1,993 @@
|
|||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/laguna.c
|
||||||
|
@@ -0,0 +1,761 @@
|
||||||
|
+/*
|
||||||
|
+ * Gateworks Corporation Laguna Platform
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2000 Deep Blue Solutions Ltd
|
||||||
|
+ * Copyright 2008 ARM Limited
|
||||||
|
+ * Copyright 2008 Cavium Networks
|
||||||
|
+ * Scott Shu
|
||||||
|
+ * Copyright 2010 MontaVista Software, LLC.
|
||||||
|
+ * Anton Vorontsov <avorontsov@mvista.com>
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * 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/kernel.h>
|
||||||
|
+#include <linux/compiler.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <linux/dma-mapping.h>
|
||||||
|
+#include <linux/serial_core.h>
|
||||||
|
+#include <linux/serial_8250.h>
|
||||||
|
+#include <linux/platform_device.h>
|
||||||
|
+#include <linux/mtd/mtd.h>
|
||||||
|
+#include <linux/mtd/physmap.h>
|
||||||
|
+#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/leds.h>
|
||||||
|
+#include <linux/i2c.h>
|
||||||
|
+#include <linux/i2c/at24.h>
|
||||||
|
+#include <linux/i2c/pca953x.h>
|
||||||
|
+#include <linux/spi/spi.h>
|
||||||
|
+#include <linux/spi/flash.h>
|
||||||
|
+#include <linux/if_ether.h>
|
||||||
|
+#include <asm/setup.h>
|
||||||
|
+#include <asm/mach-types.h>
|
||||||
|
+#include <asm/mach/arch.h>
|
||||||
|
+#include <asm/mach/map.h>
|
||||||
|
+#include <asm/mach/time.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <mach/cns3xxx.h>
|
||||||
|
+#include <mach/irqs.h>
|
||||||
|
+#include <mach/pm.h>
|
||||||
|
+#include "core.h"
|
||||||
|
+#include "devices.h"
|
||||||
|
+
|
||||||
|
+// Config 1 Bitmap
|
||||||
|
+#define ETH0_LOAD BIT(0)
|
||||||
|
+#define ETH1_LOAD BIT(1)
|
||||||
|
+#define ETH2_LOAD BIT(2)
|
||||||
|
+#define SATA0_LOAD BIT(3)
|
||||||
|
+#define SATA1_LOAD BIT(4)
|
||||||
|
+#define PCM_LOAD BIT(5)
|
||||||
|
+#define I2S_LOAD BIT(6)
|
||||||
|
+#define SPI0_LOAD BIT(7)
|
||||||
|
+#define SPI1_LOAD BIT(8)
|
||||||
|
+#define PCIE0_LOAD BIT(9)
|
||||||
|
+#define PCIE1_LOAD BIT(10)
|
||||||
|
+#define USB0_LOAD BIT(11)
|
||||||
|
+#define USB1_LOAD BIT(12)
|
||||||
|
+#define USB1_ROUTE BIT(13)
|
||||||
|
+#define SD_LOAD BIT(14)
|
||||||
|
+#define UART0_LOAD BIT(15)
|
||||||
|
+#define UART1_LOAD BIT(16)
|
||||||
|
+#define UART2_LOAD BIT(17)
|
||||||
|
+#define MPCI0_LOAD BIT(18)
|
||||||
|
+#define MPCI1_LOAD BIT(19)
|
||||||
|
+#define MPCI2_LOAD BIT(20)
|
||||||
|
+#define MPCI3_LOAD BIT(21)
|
||||||
|
+#define FP_BUT_LOAD BIT(22)
|
||||||
|
+#define FP_BUT_HEADER_LOAD BIT(23)
|
||||||
|
+#define FP_LED_LOAD BIT(24)
|
||||||
|
+#define FP_LED_HEADER_LOAD BIT(25)
|
||||||
|
+#define FP_TAMPER_LOAD BIT(26)
|
||||||
|
+#define HEADER_33V_LOAD BIT(27)
|
||||||
|
+#define SATA_POWER_LOAD BIT(28)
|
||||||
|
+#define FP_POWER_LOAD BIT(29)
|
||||||
|
+#define GPIO_HEADER_LOAD BIT(30)
|
||||||
|
+#define GSP_BAT_LOAD BIT(31)
|
||||||
|
+
|
||||||
|
+// Config 2 Bitmap
|
||||||
|
+#define FAN_LOAD BIT(0)
|
||||||
|
+#define SPI_FLASH_LOAD BIT(1)
|
||||||
|
+#define NOR_FLASH_LOAD BIT(2)
|
||||||
|
+#define GPS_LOAD BIT(3)
|
||||||
|
+#define SUPPLY_5V_LOAD BIT(6)
|
||||||
|
+#define SUPPLY_33V_LOAD BIT(7)
|
||||||
|
+
|
||||||
|
+struct laguna_board_info {
|
||||||
|
+ char model[16];
|
||||||
|
+ u32 config_bitmap;
|
||||||
|
+ u32 config2_bitmap;
|
||||||
|
+ u8 nor_flash_size;
|
||||||
|
+ u8 spi_flash_size;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct laguna_board_info laguna_info __initdata;
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * NOR Flash
|
||||||
|
+ */
|
||||||
|
+static struct mtd_partition laguna_nor_partitions[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "uboot",
|
||||||
|
+ .size = SZ_256K,
|
||||||
|
+ .offset = 0,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "params",
|
||||||
|
+ .size = SZ_128K,
|
||||||
|
+ .offset = SZ_256K,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "kernel",
|
||||||
|
+ .size = SZ_2M,
|
||||||
|
+ .offset = SZ_256K + SZ_128K,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "rootfs",
|
||||||
|
+ .size = SZ_16M - SZ_256K - SZ_128K - SZ_2M,
|
||||||
|
+ .offset = SZ_256K + SZ_128K + SZ_2M,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct physmap_flash_data laguna_nor_pdata = {
|
||||||
|
+ .width = 2,
|
||||||
|
+ .parts = laguna_nor_partitions,
|
||||||
|
+ .nr_parts = ARRAY_SIZE(laguna_nor_partitions),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct resource laguna_nor_res = {
|
||||||
|
+ .start = CNS3XXX_FLASH_BASE,
|
||||||
|
+ .end = CNS3XXX_FLASH_BASE + SZ_128M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_nor_pdev = {
|
||||||
|
+ .name = "physmap-flash",
|
||||||
|
+ .id = 0,
|
||||||
|
+ .resource = &laguna_nor_res,
|
||||||
|
+ .num_resources = 1,
|
||||||
|
+ .dev = {
|
||||||
|
+ .platform_data = &laguna_nor_pdata,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * SPI
|
||||||
|
+ */
|
||||||
|
+static struct mtd_partition laguna_spi_partitions[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "uboot",
|
||||||
|
+ .size = SZ_256K,
|
||||||
|
+ .offset = 0,
|
||||||
|
+ .mask_flags = MTD_WRITEABLE,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "params",
|
||||||
|
+ .size = SZ_256K,
|
||||||
|
+ .offset = SZ_256K,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "kernel",
|
||||||
|
+ .size = SZ_1M + SZ_512K,
|
||||||
|
+ .offset = SZ_512K,
|
||||||
|
+ }, {
|
||||||
|
+ .name = "rootfs",
|
||||||
|
+ .size = SZ_16M - SZ_2M,
|
||||||
|
+ .offset = SZ_2M,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct flash_platform_data laguna_spi_pdata = {
|
||||||
|
+ .parts = laguna_spi_partitions,
|
||||||
|
+ .nr_parts = ARRAY_SIZE(laguna_spi_partitions),
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct spi_board_info __initdata laguna_spi_devices[] = {
|
||||||
|
+ {
|
||||||
|
+ .modalias = "m25p80",
|
||||||
|
+ .platform_data = &laguna_spi_pdata,
|
||||||
|
+ .max_speed_hz = 50000000,
|
||||||
|
+ .bus_num = 1,
|
||||||
|
+ .chip_select = 0,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_spi_controller = {
|
||||||
|
+ .name = "cns3xxx_spi",
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * LED's
|
||||||
|
+ */
|
||||||
|
+static struct gpio_led laguna_gpio_leds[] = {
|
||||||
|
+ {
|
||||||
|
+ .name = "user1", /* Green Led */
|
||||||
|
+ .gpio = 115,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "user2", /* Red Led */
|
||||||
|
+ .gpio = 114,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "pwr1", /* Green Led */
|
||||||
|
+ .gpio = 116,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "pwr2", /* Yellow Led */
|
||||||
|
+ .gpio = 117,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "txd1", /* Green Led */
|
||||||
|
+ .gpio = 118,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "txd2", /* Yellow Led */
|
||||||
|
+ .gpio = 119,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "rxd1", /* Green Led */
|
||||||
|
+ .gpio = 120,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "rxd2", /* Yellow Led */
|
||||||
|
+ .gpio = 121,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "ser1", /* Green Led */
|
||||||
|
+ .gpio = 122,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "ser2", /* Yellow Led */
|
||||||
|
+ .gpio = 123,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "enet1", /* Green Led */
|
||||||
|
+ .gpio = 124,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "enet2", /* Yellow Led */
|
||||||
|
+ .gpio = 125,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig1_1", /* Green Led */
|
||||||
|
+ .gpio = 126,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig1_2", /* Yellow Led */
|
||||||
|
+ .gpio = 127,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig2_1", /* Green Led */
|
||||||
|
+ .gpio = 128,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig2_2", /* Yellow Led */
|
||||||
|
+ .gpio = 129,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig3_1", /* Green Led */
|
||||||
|
+ .gpio = 130,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "sig3_2", /* Yellow Led */
|
||||||
|
+ .gpio = 131,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "net1", /*Green Led */
|
||||||
|
+ .gpio = 109,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "net2", /* Red Led */
|
||||||
|
+ .gpio = 110,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "mod1", /* Green Led */
|
||||||
|
+ .gpio = 111,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },{
|
||||||
|
+ .name = "mod2", /* Red Led */
|
||||||
|
+ .gpio = 112,
|
||||||
|
+ .active_low = 1,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct gpio_led_platform_data laguna_gpio_leds_data = {
|
||||||
|
+ .num_leds = 22,
|
||||||
|
+ .leds = laguna_gpio_leds,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_gpio_leds_device = {
|
||||||
|
+ .name = "leds-gpio",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .dev.platform_data = &laguna_gpio_leds_data,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Ethernet
|
||||||
|
+ */
|
||||||
|
+static struct cns3xxx_plat_info laguna_net_data = {
|
||||||
|
+ .ports = 0,
|
||||||
|
+ .phy = {
|
||||||
|
+ 0,
|
||||||
|
+ 1,
|
||||||
|
+ 2,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_net_device = {
|
||||||
|
+ .name = "cns3xxx_eth",
|
||||||
|
+ .id = 0,
|
||||||
|
+ .dev.platform_data = &laguna_net_data,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * UART
|
||||||
|
+ */
|
||||||
|
+static void __init laguna_early_serial_setup(void)
|
||||||
|
+{
|
||||||
|
+#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||||
|
+ static struct uart_port laguna_serial_port = {
|
||||||
|
+ .membase = (void __iomem *)CNS3XXX_UART0_BASE_VIRT,
|
||||||
|
+ .mapbase = CNS3XXX_UART0_BASE,
|
||||||
|
+ .irq = IRQ_CNS3XXX_UART0,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .uartclk = 24000000,
|
||||||
|
+ .line = 0,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ .fifosize = 16,
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ early_serial_setup(&laguna_serial_port);
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct resource laguna_uart_resources[] = {
|
||||||
|
+ {
|
||||||
|
+ .start = CNS3XXX_UART0_BASE,
|
||||||
|
+ .end = CNS3XXX_UART0_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM
|
||||||
|
+ },{
|
||||||
|
+ .start = CNS3XXX_UART2_BASE,
|
||||||
|
+ .end = CNS3XXX_UART2_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM
|
||||||
|
+ },{
|
||||||
|
+ .start = CNS3XXX_UART2_BASE,
|
||||||
|
+ .end = CNS3XXX_UART2_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct plat_serial8250_port laguna_uart_data[] = {
|
||||||
|
+ {
|
||||||
|
+ .membase = (char*) (CNS3XXX_UART0_BASE_VIRT),
|
||||||
|
+ .mapbase = (CNS3XXX_UART0_BASE),
|
||||||
|
+ .irq = IRQ_CNS3XXX_UART0,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .uartclk = 24000000,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ },{
|
||||||
|
+ .membase = (char*) (CNS3XXX_UART1_BASE_VIRT),
|
||||||
|
+ .mapbase = (CNS3XXX_UART1_BASE),
|
||||||
|
+ .irq = IRQ_CNS3XXX_UART1,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .uartclk = 24000000,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ },{
|
||||||
|
+ .membase = (char*) (CNS3XXX_UART2_BASE_VIRT),
|
||||||
|
+ .mapbase = (CNS3XXX_UART2_BASE),
|
||||||
|
+ .irq = IRQ_CNS3XXX_UART2,
|
||||||
|
+ .iotype = UPIO_MEM,
|
||||||
|
+ .flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE | UPF_NO_TXEN_TEST,
|
||||||
|
+ .regshift = 2,
|
||||||
|
+ .uartclk = 24000000,
|
||||||
|
+ .type = PORT_16550A,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_uart = {
|
||||||
|
+ .name = "serial8250",
|
||||||
|
+ .id = PLAT8250_DEV_PLATFORM,
|
||||||
|
+ .dev.platform_data = laguna_uart_data,
|
||||||
|
+ .num_resources = 3,
|
||||||
|
+ .resource = laguna_uart_resources
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * USB
|
||||||
|
+ */
|
||||||
|
+static struct resource cns3xxx_usb_ehci_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS3XXX_USB_BASE,
|
||||||
|
+ .end = CNS3XXX_USB_BASE + SZ_16M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = IRQ_CNS3XXX_USB_EHCI,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u64 cns3xxx_usb_ehci_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
+
|
||||||
|
+static struct platform_device cns3xxx_usb_ehci_device = {
|
||||||
|
+ .name = "cns3xxx-ehci",
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns3xxx_usb_ehci_resources),
|
||||||
|
+ .resource = cns3xxx_usb_ehci_resources,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns3xxx_usb_ehci_dma_mask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct resource cns3xxx_usb_ohci_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS3XXX_USB_OHCI_BASE,
|
||||||
|
+ .end = CNS3XXX_USB_OHCI_BASE + SZ_16M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = IRQ_CNS3XXX_USB_OHCI,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u64 cns3xxx_usb_ohci_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
+
|
||||||
|
+static struct platform_device cns3xxx_usb_ohci_device = {
|
||||||
|
+ .name = "cns3xxx-ohci",
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns3xxx_usb_ohci_resources),
|
||||||
|
+ .resource = cns3xxx_usb_ohci_resources,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns3xxx_usb_ohci_dma_mask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct resource cns3xxx_usb_otg_resources[] = {
|
||||||
|
+ [0] = {
|
||||||
|
+ .start = CNS3XXX_USBOTG_BASE,
|
||||||
|
+ .end = CNS3XXX_USBOTG_BASE + SZ_16M - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },
|
||||||
|
+ [1] = {
|
||||||
|
+ .start = IRQ_CNS3XXX_USB_OTG,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static u64 cns3xxx_usb_otg_dma_mask = DMA_BIT_MASK(32);
|
||||||
|
+
|
||||||
|
+static struct platform_device cns3xxx_usb_otg_device = {
|
||||||
|
+ .name = "dwc_otg",
|
||||||
|
+ .num_resources = ARRAY_SIZE(cns3xxx_usb_otg_resources),
|
||||||
|
+ .resource = cns3xxx_usb_otg_resources,
|
||||||
|
+ .dev = {
|
||||||
|
+ .dma_mask = &cns3xxx_usb_otg_dma_mask,
|
||||||
|
+ .coherent_dma_mask = DMA_BIT_MASK(32),
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * I2C
|
||||||
|
+ */
|
||||||
|
+static struct resource laguna_i2c_resource[] = {
|
||||||
|
+ {
|
||||||
|
+ .start = CNS3XXX_SSP_BASE + 0x20,
|
||||||
|
+ .end = 0x7100003f,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },{
|
||||||
|
+ .start = IRQ_CNS3XXX_I2C,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_i2c_controller = {
|
||||||
|
+ .name = "cns3xxx-i2c",
|
||||||
|
+ .num_resources = 2,
|
||||||
|
+ .resource = laguna_i2c_resource,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct memory_accessor *at24_mem_acc;
|
||||||
|
+
|
||||||
|
+static void at24_setup(struct memory_accessor *mem_acc, void *context)
|
||||||
|
+{
|
||||||
|
+ char buf[8];
|
||||||
|
+
|
||||||
|
+ at24_mem_acc = mem_acc;
|
||||||
|
+
|
||||||
|
+ /* Read MAC addresses */
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x100, 6) == 6)
|
||||||
|
+ memcpy(&laguna_net_data.hwaddr[0], buf, ETH_ALEN);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x106, 6) == 6)
|
||||||
|
+ memcpy(&laguna_net_data.hwaddr[1], buf, ETH_ALEN);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x10C, 6) == 6)
|
||||||
|
+ memcpy(&laguna_net_data.hwaddr[2], buf, ETH_ALEN);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x112, 6) == 6)
|
||||||
|
+ memcpy(&laguna_net_data.hwaddr[3], buf, ETH_ALEN);
|
||||||
|
+
|
||||||
|
+ /* Read out Model Information */
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x130, 16) == 16)
|
||||||
|
+ memcpy(&laguna_info.model, buf, 16);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x140, 1) == 1)
|
||||||
|
+ memcpy(&laguna_info.nor_flash_size, buf, 1);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x141, 1) == 1)
|
||||||
|
+ memcpy(&laguna_info.spi_flash_size, buf, 1);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x142, 4) == 4)
|
||||||
|
+ memcpy(&laguna_info.config_bitmap, buf, 4);
|
||||||
|
+ if (at24_mem_acc->read(at24_mem_acc, buf, 0x146, 4) == 4)
|
||||||
|
+ memcpy(&laguna_info.config2_bitmap, buf, 4);
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct at24_platform_data laguna_eeprom_info = {
|
||||||
|
+ .byte_len = 1024,
|
||||||
|
+ .page_size = 16,
|
||||||
|
+ .flags = AT24_FLAG_READONLY,
|
||||||
|
+ .setup = at24_setup,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct pca953x_platform_data laguna_pca_data = {
|
||||||
|
+ .gpio_base = 100,
|
||||||
|
+ .irq_base = -1,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct pca953x_platform_data laguna_pca2_data = {
|
||||||
|
+ .gpio_base = 116,
|
||||||
|
+ .irq_base = -1,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct i2c_board_info __initdata laguna_i2c_devices[] = {
|
||||||
|
+ {
|
||||||
|
+ I2C_BOARD_INFO("pca9555", 0x23),
|
||||||
|
+ .platform_data = &laguna_pca_data,
|
||||||
|
+ },{
|
||||||
|
+ I2C_BOARD_INFO("pca9555", 0x27),
|
||||||
|
+ .platform_data = &laguna_pca2_data,
|
||||||
|
+ },{
|
||||||
|
+ I2C_BOARD_INFO("gsp", 0x29),
|
||||||
|
+ },{
|
||||||
|
+ I2C_BOARD_INFO ("24c08",0x50),
|
||||||
|
+ .platform_data = &laguna_eeprom_info,
|
||||||
|
+ },{
|
||||||
|
+ I2C_BOARD_INFO("ds1672", 0x68),
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Watchdog
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+static struct resource laguna_watchdog_resource[] = {
|
||||||
|
+ {
|
||||||
|
+ .start = CNS3XXX_TC11MP_TWD_BASE,
|
||||||
|
+ .end = CNS3XXX_TC11MP_TWD_BASE + SZ_4K - 1,
|
||||||
|
+ .flags = IORESOURCE_MEM,
|
||||||
|
+ },{
|
||||||
|
+ .start = IRQ_LOCALWDOG,
|
||||||
|
+ .end = IRQ_LOCALWDOG,
|
||||||
|
+ .flags = IORESOURCE_IRQ,
|
||||||
|
+ }
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static struct platform_device laguna_watchdog = {
|
||||||
|
+ .name = "mpcore_wdt",
|
||||||
|
+ .id = -1,
|
||||||
|
+ .num_resources = ARRAY_SIZE(laguna_watchdog_resource),
|
||||||
|
+ .resource = laguna_watchdog_resource,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Initialization
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+static void __init laguna_init(void)
|
||||||
|
+{
|
||||||
|
+ platform_device_register(&laguna_watchdog);
|
||||||
|
+
|
||||||
|
+ platform_device_register(&laguna_i2c_controller);
|
||||||
|
+
|
||||||
|
+ i2c_register_board_info(0, laguna_i2c_devices,
|
||||||
|
+ ARRAY_SIZE(laguna_i2c_devices));
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ pm_power_off = cns3xxx_power_off;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct map_desc laguna_io_desc[] __initdata = {
|
||||||
|
+ {
|
||||||
|
+ .virtual = CNS3XXX_UART0_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_UART0_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
+ },{
|
||||||
|
+ .virtual = CNS3XXX_UART1_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_UART1_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
+ },{
|
||||||
|
+ .virtual = CNS3XXX_UART2_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_UART2_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
+ },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void __init laguna_map_io(void)
|
||||||
|
+{
|
||||||
|
+ cns3xxx_map_io();
|
||||||
|
+ iotable_init(laguna_io_desc, ARRAY_SIZE(laguna_io_desc));
|
||||||
|
+
|
||||||
|
+ laguna_early_serial_setup();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static int __init laguna_model_setup(void)
|
||||||
|
+{
|
||||||
|
+ u32 __iomem *mem;
|
||||||
|
+ u32 reg;
|
||||||
|
+ u8 pcie_bitmap = 0;
|
||||||
|
+
|
||||||
|
+ printk("Running on Gateworks Laguna %s\n", laguna_info.model);
|
||||||
|
+
|
||||||
|
+ if (strncmp(laguna_info.model, "GW", 2) == 0) {
|
||||||
|
+ if (laguna_info.config_bitmap & ETH0_LOAD)
|
||||||
|
+ laguna_net_data.ports |= BIT(0);
|
||||||
|
+ if (laguna_info.config_bitmap & ETH1_LOAD)
|
||||||
|
+ laguna_net_data.ports |= BIT(1);
|
||||||
|
+ if (laguna_info.config_bitmap & ETH2_LOAD)
|
||||||
|
+ laguna_net_data.ports |= BIT(2);
|
||||||
|
+ if (laguna_net_data.ports)
|
||||||
|
+ platform_device_register(&laguna_net_device);
|
||||||
|
+
|
||||||
|
+ if ((laguna_info.config_bitmap & SATA0_LOAD) ||
|
||||||
|
+ (laguna_info.config_bitmap & SATA1_LOAD))
|
||||||
|
+ cns3xxx_ahci_init();
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (PCIE0_LOAD))
|
||||||
|
+ pcie_bitmap |= 0x1;
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (PCIE1_LOAD))
|
||||||
|
+ pcie_bitmap |= 0x2;
|
||||||
|
+
|
||||||
|
+ cns3xxx_pcie_init(pcie_bitmap);
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (USB0_LOAD)) {
|
||||||
|
+ cns3xxx_pwr_power_up(1 << PM_PLL_HM_PD_CTRL_REG_OFFSET_PLL_USB);
|
||||||
|
+
|
||||||
|
+ /* DRVVBUS pins share with GPIOA */
|
||||||
|
+ mem = (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0014);
|
||||||
|
+ reg = __raw_readl(mem);
|
||||||
|
+ reg |= 0x8;
|
||||||
|
+ __raw_writel(reg, mem);
|
||||||
|
+
|
||||||
|
+ /* Enable OTG */
|
||||||
|
+ mem = (void __iomem *)(CNS3XXX_MISC_BASE_VIRT + 0x0808);
|
||||||
|
+ reg = __raw_readl(mem);
|
||||||
|
+ reg &= ~(1 << 10);
|
||||||
|
+ __raw_writel(reg, mem);
|
||||||
|
+
|
||||||
|
+ platform_device_register(&cns3xxx_usb_otg_device);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (USB1_LOAD)) {
|
||||||
|
+ platform_device_register(&cns3xxx_usb_ehci_device);
|
||||||
|
+ platform_device_register(&cns3xxx_usb_ohci_device);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (SD_LOAD))
|
||||||
|
+ cns3xxx_sdhci_init();
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config_bitmap & (UART0_LOAD))
|
||||||
|
+ laguna_uart.num_resources = 1;
|
||||||
|
+ if (laguna_info.config_bitmap & (UART1_LOAD))
|
||||||
|
+ laguna_uart.num_resources = 2;
|
||||||
|
+ if (laguna_info.config_bitmap & (UART2_LOAD))
|
||||||
|
+ laguna_uart.num_resources = 3;
|
||||||
|
+ platform_device_register(&laguna_uart);
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config2_bitmap & (NOR_FLASH_LOAD)) {
|
||||||
|
+ switch (laguna_info.nor_flash_size) {
|
||||||
|
+ case 1:
|
||||||
|
+ laguna_nor_partitions[3].size = SZ_8M - SZ_256K - SZ_128K - SZ_2M;
|
||||||
|
+ laguna_nor_res.end = CNS3XXX_FLASH_BASE + SZ_8M - 1;
|
||||||
|
+ break;
|
||||||
|
+ case 2:
|
||||||
|
+ laguna_nor_partitions[3].size = SZ_16M - SZ_256K - SZ_128K - SZ_2M;
|
||||||
|
+ laguna_nor_res.end = CNS3XXX_FLASH_BASE + SZ_16M - 1;
|
||||||
|
+ break;
|
||||||
|
+ case 3:
|
||||||
|
+ laguna_nor_partitions[3].size = SZ_32M - SZ_256K - SZ_128K - SZ_2M;
|
||||||
|
+ laguna_nor_res.end = CNS3XXX_FLASH_BASE + SZ_32M - 1;
|
||||||
|
+ break;
|
||||||
|
+ case 4:
|
||||||
|
+ laguna_nor_partitions[3].size = SZ_64M - SZ_256K - SZ_128K - SZ_2M;
|
||||||
|
+ laguna_nor_res.end = CNS3XXX_FLASH_BASE + SZ_64M - 1;
|
||||||
|
+ break;
|
||||||
|
+ case 5:
|
||||||
|
+ laguna_nor_partitions[3].size = SZ_128M - SZ_256K - SZ_128K - SZ_2M;
|
||||||
|
+ laguna_nor_res.end = CNS3XXX_FLASH_BASE + SZ_128M - 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ platform_device_register(&laguna_nor_pdev);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (laguna_info.config2_bitmap & (SPI_FLASH_LOAD)) {
|
||||||
|
+ switch (laguna_info.spi_flash_size) {
|
||||||
|
+ case 1:
|
||||||
|
+ laguna_spi_partitions[3].size = SZ_4M - SZ_2M;
|
||||||
|
+ break;
|
||||||
|
+ case 2:
|
||||||
|
+ laguna_spi_partitions[3].size = SZ_8M - SZ_2M;
|
||||||
|
+ break;
|
||||||
|
+ case 3:
|
||||||
|
+ laguna_spi_partitions[3].size = SZ_16M - SZ_2M;
|
||||||
|
+ break;
|
||||||
|
+ case 4:
|
||||||
|
+ laguna_spi_partitions[3].size = SZ_32M - SZ_2M;
|
||||||
|
+ break;
|
||||||
|
+ case 5:
|
||||||
|
+ laguna_spi_partitions[3].size = SZ_64M - SZ_2M;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ spi_register_board_info(laguna_spi_devices, ARRAY_SIZE(laguna_spi_devices));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if ((laguna_info.config_bitmap & SPI0_LOAD) ||
|
||||||
|
+ (laguna_info.config_bitmap & SPI1_LOAD))
|
||||||
|
+ platform_device_register(&laguna_spi_controller);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Do any model specific setup not known by the bitmap by matching
|
||||||
|
+ * the first 6 characters of the model name
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ if (strncmp(laguna_info.model, "GW2388", 6) == 0) {
|
||||||
|
+ laguna_gpio_leds_data.num_leds = 2;
|
||||||
|
+ } else if (strncmp(laguna_info.model, "GW2380", 6) == 0) {
|
||||||
|
+ laguna_gpio_leds[0].gpio = 107;
|
||||||
|
+ laguna_gpio_leds[1].gpio = 106;
|
||||||
|
+ laguna_gpio_leds_data.num_leds = 2;
|
||||||
|
+ }
|
||||||
|
+ platform_device_register(&laguna_gpio_leds_device);
|
||||||
|
+ } else {
|
||||||
|
+ // Do some defaults here, not sure what yet
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+late_initcall(laguna_model_setup);
|
||||||
|
+
|
||||||
|
+MACHINE_START(GW2388, "Gateworks Corporation Laguna Platform")
|
||||||
|
+ .boot_params = 0x00000100,
|
||||||
|
+ .map_io = laguna_map_io,
|
||||||
|
+ .init_irq = cns3xxx_init_irq,
|
||||||
|
+ .timer = &cns3xxx_timer,
|
||||||
|
+ .init_machine = laguna_init,
|
||||||
|
+MACHINE_END
|
||||||
|
--- a/arch/arm/mach-cns3xxx/Kconfig
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/Kconfig
|
||||||
|
@@ -10,4 +10,13 @@ config MACH_CNS3420VB
|
||||||
|
This is a platform with an on-board ARM11 MPCore and has support
|
||||||
|
for USB, USB-OTG, MMC/SD/SDIO, SATA, PCI-E, etc.
|
||||||
|
|
||||||
|
+config MACH_GW2388
|
||||||
|
+ bool "Support for Gateworks Laguna Platform"
|
||||||
|
+ select MIGHT_HAVE_PCI
|
||||||
|
+ help
|
||||||
|
+ Include support for the Gateworks Laguna Platform
|
||||||
|
+
|
||||||
|
+ This is a platform with an on-board ARM11 MPCore and has support
|
||||||
|
+ for USB, USB-OTG, MMC/SD/SDIO, SATA, PCI-E, I2C, GIG, etc.
|
||||||
|
+
|
||||||
|
endmenu
|
||||||
|
--- a/arch/arm/mach-cns3xxx/core.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.c
|
||||||
|
@@ -16,6 +16,7 @@
|
||||||
|
#include <asm/mach/time.h>
|
||||||
|
#include <asm/mach/irq.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
+#include <asm/smp_twd.h>
|
||||||
|
#include <mach/cns3xxx.h>
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
@@ -60,11 +61,24 @@ static struct map_desc cns3xxx_io_desc[]
|
||||||
|
.pfn = __phys_to_pfn(CNS3XXX_PM_BASE),
|
||||||
|
.length = SZ_4K,
|
||||||
|
.type = MT_DEVICE,
|
||||||
|
+ }, {
|
||||||
|
+ .virtual = CNS3XXX_SWITCH_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_SWITCH_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
+ }, {
|
||||||
|
+ .virtual = CNS3XXX_SSP_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_SSP_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init cns3xxx_map_io(void)
|
||||||
|
{
|
||||||
|
+#ifdef CONFIG_LOCAL_TIMERS
|
||||||
|
+ twd_base = (void __iomem *) CNS3XXX_TC11MP_TWD_BASE_VIRT;
|
||||||
|
+#endif
|
||||||
|
iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -322,6 +322,7 @@ config ARCH_CLPS711X
|
||||||
|
config ARCH_CNS3XXX
|
||||||
|
bool "Cavium Networks CNS3XXX family"
|
||||||
|
select CPU_V6
|
||||||
|
+ select ARCH_WANT_OPTIONAL_GPIOLIB
|
||||||
|
select GENERIC_CLOCKEVENTS
|
||||||
|
select ARM_GIC
|
||||||
|
select MIGHT_HAVE_PCI
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/include/mach/gpio.h
|
||||||
|
@@ -0,0 +1,98 @@
|
||||||
|
+/*
|
||||||
|
+ * arch/arm/mach-cns3xxx/include/mach/gpio.h
|
||||||
|
+ *
|
||||||
|
+ * CNS3xxx GPIO wrappers for arch-neutral GPIO calls
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2011 Gateworks Corporation
|
||||||
|
+ * Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * Based on IXP implementation by Milan Svoboda <msvoboda@ra.rockwell.com>
|
||||||
|
+ * Based on PXA implementation by Philipp Zabel <philipp.zabel@gmail.com>
|
||||||
|
+ *
|
||||||
|
+ * 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.
|
||||||
|
+ *
|
||||||
|
+ * This program is distributed in the hope that it will be useful,
|
||||||
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
+ * GNU General Public License for more details.
|
||||||
|
+ *
|
||||||
|
+ * You should have received a copy of the GNU General Public License
|
||||||
|
+ * along with this program; if not, write to the Free Software
|
||||||
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef __ASM_ARCH_CNS3XXX_GPIO_H
|
||||||
|
+#define __ASM_ARCH_CNS3XXX_GPIO_H
|
||||||
|
+
|
||||||
|
+#include <linux/kernel.h>
|
||||||
|
+#include <linux/io.h>
|
||||||
|
+#include <mach/hardware.h>
|
||||||
|
+#include <asm-generic/gpio.h> /* cansleep wrappers */
|
||||||
|
+
|
||||||
|
+#define NR_BUILTIN_GPIO 64
|
||||||
|
+
|
||||||
|
+#define CNS3XXX_GPIO_IN 0x0
|
||||||
|
+#define CNS3XXX_GPIO_OUT 0x1
|
||||||
|
+
|
||||||
|
+#define CNS3XXX_GPIO_LO 0
|
||||||
|
+#define CNS3XXX_GPIO_HI 1
|
||||||
|
+
|
||||||
|
+#define CNS3XXX_GPIO_OUTPUT 0x00
|
||||||
|
+#define CNS3XXX_GPIO_INPUT 0x04
|
||||||
|
+#define CNS3XXX_GPIO_DIR 0x08
|
||||||
|
+#define CNS3XXX_GPIO_SET 0x10
|
||||||
|
+#define CNS3XXX_GPIO_CLEAR 0x14
|
||||||
|
+
|
||||||
|
+static inline void gpio_line_get(u8 line, int *value)
|
||||||
|
+{
|
||||||
|
+ if (line < 32)
|
||||||
|
+ *value = ((__raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> line) & 0x1);
|
||||||
|
+ else
|
||||||
|
+ *value = ((__raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_INPUT) >> (line - 32)) & 0x1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void gpio_line_set(u8 line, int value)
|
||||||
|
+{
|
||||||
|
+ if (line < 32) {
|
||||||
|
+ if (value)
|
||||||
|
+ __raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_SET);
|
||||||
|
+ else
|
||||||
|
+ __raw_writel((1 << line), CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_CLEAR);
|
||||||
|
+ } else {
|
||||||
|
+ if (value)
|
||||||
|
+ __raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_SET);
|
||||||
|
+ else
|
||||||
|
+ __raw_writel((1 << line), CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_CLEAR);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline int gpio_get_value(unsigned gpio)
|
||||||
|
+{
|
||||||
|
+ if (gpio < NR_BUILTIN_GPIO)
|
||||||
|
+ {
|
||||||
|
+ int value;
|
||||||
|
+ gpio_line_get(gpio, &value);
|
||||||
|
+ return value;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ return __gpio_get_value(gpio);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void gpio_set_value(unsigned gpio, int value)
|
||||||
|
+{
|
||||||
|
+ if (gpio < NR_BUILTIN_GPIO)
|
||||||
|
+ gpio_line_set(gpio, value);
|
||||||
|
+ else
|
||||||
|
+ __gpio_set_value(gpio, value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define gpio_cansleep __gpio_cansleep
|
||||||
|
+
|
||||||
|
+extern int gpio_to_irq(int gpio);
|
||||||
|
+extern int irq_to_gpio(int gpio);
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
--- a/arch/arm/mach-cns3xxx/Makefile
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/Makefile
|
||||||
|
@@ -1,6 +1,7 @@
|
||||||
|
obj-$(CONFIG_ARCH_CNS3XXX) += core.o pm.o devices.o
|
||||||
|
obj-$(CONFIG_PCI) += pcie.o
|
||||||
|
obj-$(CONFIG_MACH_CNS3420VB) += cns3420vb.o
|
||||||
|
+obj-$(CONFIG_MACH_GW2388) += laguna.o
|
||||||
|
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
|
||||||
|
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
|
||||||
|
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
|
||||||
|
--- a/arch/arm/tools/mach-types
|
||||||
|
+++ b/arch/arm/tools/mach-types
|
||||||
|
@@ -444,6 +444,7 @@ icontrol MACH_ICONTROL ICONTROL 2624
|
||||||
|
qsd8x50a_st1_5 MACH_QSD8X50A_ST1_5 QSD8X50A_ST1_5 2627
|
||||||
|
mx23evk MACH_MX23EVK MX23EVK 2629
|
||||||
|
ap4evb MACH_AP4EVB AP4EVB 2630
|
||||||
|
+gw2388 MACH_GW2388 GW2388 2635
|
||||||
|
mityomapl138 MACH_MITYOMAPL138 MITYOMAPL138 2650
|
||||||
|
guruplug MACH_GURUPLUG GURUPLUG 2659
|
||||||
|
spear310 MACH_SPEAR310 SPEAR310 2660
|
||||||
|
--- a/arch/arm/mach-cns3xxx/pcie.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/pcie.c
|
||||||
|
@@ -365,7 +365,7 @@ static int cns3xxx_pcie_abort_handler(un
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int __init cns3xxx_pcie_init(void)
|
||||||
|
+int cns3xxx_pcie_init(u8 bitmap)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
@@ -373,6 +373,9 @@ static int __init cns3xxx_pcie_init(void
|
||||||
|
"imprecise external abort");
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
|
||||||
|
+ if (!(bitmap & (1 << i)))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
iotable_init(cns3xxx_pcie[i].cfg_bases,
|
||||||
|
ARRAY_SIZE(cns3xxx_pcie[i].cfg_bases));
|
||||||
|
cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
|
||||||
|
@@ -384,4 +387,3 @@ static int __init cns3xxx_pcie_init(void
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-device_initcall(cns3xxx_pcie_init);
|
||||||
|
--- a/arch/arm/mach-cns3xxx/cns3420vb.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/cns3420vb.c
|
||||||
|
@@ -175,6 +175,8 @@ static void __init cns3420_init(void)
|
||||||
|
cns3xxx_ahci_init();
|
||||||
|
cns3xxx_sdhci_init();
|
||||||
|
|
||||||
|
+ cns3xxx_pcie_init(0x3);
|
||||||
|
+
|
||||||
|
pm_power_off = cns3xxx_power_off;
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/arch/arm/mach-cns3xxx/include/mach/platform.h
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/include/mach/platform.h
|
||||||
|
@@ -22,5 +22,7 @@ struct cns3xxx_plat_info {
|
||||||
|
u32 phy[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
+extern int cns3xxx_pcie_init(u8 bitmap);
|
||||||
|
+
|
||||||
|
#endif /* __ASM_ARCH_PLATFORM_H */
|
||||||
|
#endif
|
@ -0,0 +1,14 @@
|
|||||||
|
--- a/drivers/mmc/host/sdhci-cns3xxx.c
|
||||||
|
+++ b/drivers/mmc/host/sdhci-cns3xxx.c
|
||||||
|
@@ -90,8 +90,9 @@ struct sdhci_pltfm_data sdhci_cns3xxx_pd
|
||||||
|
.ops = &sdhci_cns3xxx_ops,
|
||||||
|
.quirks = SDHCI_QUIRK_BROKEN_DMA |
|
||||||
|
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
|
||||||
|
- SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
|
||||||
|
+ //SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
|
||||||
|
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
|
||||||
|
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
|
||||||
|
- SDHCI_QUIRK_NONSTANDARD_CLOCK,
|
||||||
|
+ SDHCI_QUIRK_NONSTANDARD_CLOCK |
|
||||||
|
+ SDHCI_QUIRK_BROKEN_CARD_DETECTION,
|
||||||
|
};
|
109
target/linux/cns3xxx/patches-3.0/102-cns3xxx_timers.patch
Normal file
109
target/linux/cns3xxx/patches-3.0/102-cns3xxx_timers.patch
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/core.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.c
|
||||||
|
@@ -117,12 +117,13 @@ static void cns3xxx_timer_set_mode(enum
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case CLOCK_EVT_MODE_PERIODIC:
|
||||||
|
- reload = pclk * 20 / (3 * HZ) * 0x25000;
|
||||||
|
+ reload = pclk * 1000000 / HZ;
|
||||||
|
writel(reload, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
|
||||||
|
ctrl |= (1 << 0) | (1 << 2) | (1 << 9);
|
||||||
|
break;
|
||||||
|
case CLOCK_EVT_MODE_ONESHOT:
|
||||||
|
/* period set, and timer enabled in 'next_event' hook */
|
||||||
|
+ writel(0, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
|
||||||
|
ctrl |= (1 << 2) | (1 << 9);
|
||||||
|
break;
|
||||||
|
case CLOCK_EVT_MODE_UNUSED:
|
||||||
|
@@ -147,11 +148,11 @@ static int cns3xxx_timer_set_next_event(
|
||||||
|
|
||||||
|
static struct clock_event_device cns3xxx_tmr1_clockevent = {
|
||||||
|
.name = "cns3xxx timer1",
|
||||||
|
- .shift = 8,
|
||||||
|
+ .shift = 32,
|
||||||
|
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
||||||
|
.set_mode = cns3xxx_timer_set_mode,
|
||||||
|
.set_next_event = cns3xxx_timer_set_next_event,
|
||||||
|
- .rating = 350,
|
||||||
|
+ .rating = 300,
|
||||||
|
.cpumask = cpu_all_mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -193,6 +194,35 @@ static struct irqaction cns3xxx_timer_ir
|
||||||
|
.handler = cns3xxx_timer_interrupt,
|
||||||
|
};
|
||||||
|
|
||||||
|
+static cycle_t cns3xxx_get_cycles(struct clocksource *cs)
|
||||||
|
+{
|
||||||
|
+ u64 val;
|
||||||
|
+
|
||||||
|
+ val = readl(cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
|
||||||
|
+ val &= 0xffff;
|
||||||
|
+
|
||||||
|
+ return ((val << 32) | readl(cns3xxx_tmr1 + TIMER_FREERUN_OFFSET));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct clocksource clocksource_cns3xxx = {
|
||||||
|
+ .name = "freerun",
|
||||||
|
+ .rating = 200,
|
||||||
|
+ .read = cns3xxx_get_cycles,
|
||||||
|
+ .mask = CLOCKSOURCE_MASK(48),
|
||||||
|
+ .shift = 16,
|
||||||
|
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static void __init cns3xxx_clocksource_init(void)
|
||||||
|
+{
|
||||||
|
+ /* Reset the FreeRunning counter */
|
||||||
|
+ writel((1 << 16), cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
|
||||||
|
+
|
||||||
|
+ clocksource_cns3xxx.mult =
|
||||||
|
+ clocksource_khz2mult(100, clocksource_cns3xxx.shift);
|
||||||
|
+ clocksource_register(&clocksource_cns3xxx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Set up the clock source and clock events devices
|
||||||
|
*/
|
||||||
|
@@ -210,13 +240,12 @@ static void __init __cns3xxx_timer_init(
|
||||||
|
/* stop free running timer3 */
|
||||||
|
writel(0, cns3xxx_tmr1 + TIMER_FREERUN_CONTROL_OFFSET);
|
||||||
|
|
||||||
|
- /* timer1 */
|
||||||
|
- writel(0x5C800, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
|
||||||
|
- writel(0x5C800, cns3xxx_tmr1 + TIMER1_AUTO_RELOAD_OFFSET);
|
||||||
|
-
|
||||||
|
writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V1_OFFSET);
|
||||||
|
writel(0, cns3xxx_tmr1 + TIMER1_MATCH_V2_OFFSET);
|
||||||
|
|
||||||
|
+ val = (cns3xxx_cpu_clock() >> 3) * 1000000 / HZ;
|
||||||
|
+ writel(val, cns3xxx_tmr1 + TIMER1_COUNTER_OFFSET);
|
||||||
|
+
|
||||||
|
/* mask irq, non-mask timer1 overflow */
|
||||||
|
irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
|
||||||
|
irq_mask &= ~(1 << 2);
|
||||||
|
@@ -228,23 +257,9 @@ static void __init __cns3xxx_timer_init(
|
||||||
|
val |= (1 << 9);
|
||||||
|
writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
|
||||||
|
|
||||||
|
- /* timer2 */
|
||||||
|
- writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V1_OFFSET);
|
||||||
|
- writel(0, cns3xxx_tmr1 + TIMER2_MATCH_V2_OFFSET);
|
||||||
|
-
|
||||||
|
- /* mask irq */
|
||||||
|
- irq_mask = readl(cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
|
||||||
|
- irq_mask |= ((1 << 3) | (1 << 4) | (1 << 5));
|
||||||
|
- writel(irq_mask, cns3xxx_tmr1 + TIMER1_2_INTERRUPT_MASK_OFFSET);
|
||||||
|
-
|
||||||
|
- /* down counter */
|
||||||
|
- val = readl(cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
|
||||||
|
- val |= (1 << 10);
|
||||||
|
- writel(val, cns3xxx_tmr1 + TIMER1_2_CONTROL_OFFSET);
|
||||||
|
-
|
||||||
|
- /* Make irqs happen for the system timer */
|
||||||
|
setup_irq(timer_irq, &cns3xxx_timer_irq);
|
||||||
|
|
||||||
|
+ cns3xxx_clocksource_init();
|
||||||
|
cns3xxx_clockevents_init(timer_irq);
|
||||||
|
}
|
||||||
|
|
61
target/linux/cns3xxx/patches-3.0/103-cns3xxx_l2cache.patch
Normal file
61
target/linux/cns3xxx/patches-3.0/103-cns3xxx_l2cache.patch
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/core.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.c
|
||||||
|
@@ -15,6 +15,7 @@
|
||||||
|
#include <asm/mach/map.h>
|
||||||
|
#include <asm/mach/time.h>
|
||||||
|
#include <asm/mach/irq.h>
|
||||||
|
+#include <asm/hardware/cache-l2x0.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
#include <asm/smp_twd.h>
|
||||||
|
#include <mach/cns3xxx.h>
|
||||||
|
@@ -71,15 +72,29 @@ static struct map_desc cns3xxx_io_desc[]
|
||||||
|
.pfn = __phys_to_pfn(CNS3XXX_SSP_BASE),
|
||||||
|
.length = SZ_4K,
|
||||||
|
.type = MT_DEVICE,
|
||||||
|
+ }, {
|
||||||
|
+ .virtual = CNS3XXX_L2C_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_L2C_BASE),
|
||||||
|
+ .length = SZ_4K,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
void __init cns3xxx_map_io(void)
|
||||||
|
{
|
||||||
|
+ iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
|
||||||
|
+#ifdef CONFIG_CACHE_L2X0
|
||||||
|
+ void __iomem *l2x0_base = (void __iomem *) CNS3XXX_L2C_BASE_VIRT;
|
||||||
|
+
|
||||||
|
+ /* set RAM latencies to 1 cycle for this core tile. */
|
||||||
|
+ writel(0, l2x0_base + L2X0_TAG_LATENCY_CTRL);
|
||||||
|
+ writel(0, l2x0_base + L2X0_DATA_LATENCY_CTRL);
|
||||||
|
+
|
||||||
|
+ l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
|
||||||
|
+#endif
|
||||||
|
#ifdef CONFIG_LOCAL_TIMERS
|
||||||
|
twd_base = (void __iomem *) CNS3XXX_TC11MP_TWD_BASE_VIRT;
|
||||||
|
#endif
|
||||||
|
- iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used by entry-macro.S */
|
||||||
|
--- a/arch/arm/mm/Kconfig
|
||||||
|
+++ b/arch/arm/mm/Kconfig
|
||||||
|
@@ -821,7 +821,7 @@ config CACHE_L2X0
|
||||||
|
depends on REALVIEW_EB_ARM11MP || MACH_REALVIEW_PB11MP || MACH_REALVIEW_PB1176 || \
|
||||||
|
REALVIEW_EB_A9MP || SOC_IMX35 || SOC_IMX31 || MACH_REALVIEW_PBX || \
|
||||||
|
ARCH_NOMADIK || ARCH_OMAP4 || ARCH_EXYNOS4 || ARCH_TEGRA || \
|
||||||
|
- ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE
|
||||||
|
+ ARCH_U8500 || ARCH_VEXPRESS_CA9X4 || ARCH_SHMOBILE || ARCH_CNS3XXX
|
||||||
|
default y
|
||||||
|
select OUTER_CACHE
|
||||||
|
select OUTER_CACHE_SYNC
|
||||||
|
@@ -866,7 +866,7 @@ config ARM_L1_CACHE_SHIFT
|
||||||
|
config ARM_DMA_MEM_BUFFERABLE
|
||||||
|
bool "Use non-cacheable memory for DMA" if (CPU_V6 || CPU_V6K) && !CPU_V7
|
||||||
|
depends on !(MACH_REALVIEW_PB1176 || REALVIEW_EB_ARM11MP || \
|
||||||
|
- MACH_REALVIEW_PB11MP)
|
||||||
|
+ MACH_REALVIEW_PB11MP || ARCH_CNS3XXX)
|
||||||
|
default y if CPU_V6 || CPU_V6K || CPU_V7
|
||||||
|
help
|
||||||
|
Historically, the kernel has used strongly ordered mappings to
|
142
target/linux/cns3xxx/patches-3.0/104-cns3xxx_gpio.patch
Normal file
142
target/linux/cns3xxx/patches-3.0/104-cns3xxx_gpio.patch
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/cns3420vb.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/cns3420vb.c
|
||||||
|
@@ -191,7 +191,7 @@ static struct map_desc cns3420_io_desc[]
|
||||||
|
|
||||||
|
static void __init cns3420_map_io(void)
|
||||||
|
{
|
||||||
|
- cns3xxx_map_io();
|
||||||
|
+ cns3xxx_common_init();
|
||||||
|
iotable_init(cns3420_io_desc, ARRAY_SIZE(cns3420_io_desc));
|
||||||
|
|
||||||
|
cns3420_early_serial_setup();
|
||||||
|
--- a/arch/arm/mach-cns3xxx/core.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.c
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
#include <asm/hardware/cache-l2x0.h>
|
||||||
|
#include <asm/hardware/gic.h>
|
||||||
|
#include <asm/smp_twd.h>
|
||||||
|
+#include <asm/gpio.h>
|
||||||
|
#include <mach/cns3xxx.h>
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
@@ -80,7 +81,89 @@ static struct map_desc cns3xxx_io_desc[]
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-void __init cns3xxx_map_io(void)
|
||||||
|
+int gpio_to_irq(int gpio)
|
||||||
|
+{
|
||||||
|
+ if (gpio > 63)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (gpio < 32)
|
||||||
|
+ return IRQ_CNS3XXX_GPIOA;
|
||||||
|
+ else
|
||||||
|
+ return IRQ_CNS3XXX_GPIOB;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(gpio_to_irq);
|
||||||
|
+
|
||||||
|
+int irq2gpio(int irq)
|
||||||
|
+{
|
||||||
|
+ if (irq == IRQ_CNS3XXX_GPIOA)
|
||||||
|
+ return 0;
|
||||||
|
+ else if (irq == IRQ_CNS3XXX_GPIOB)
|
||||||
|
+ return 32;
|
||||||
|
+ else
|
||||||
|
+ return -EINVAL;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(irq2gpio);
|
||||||
|
+
|
||||||
|
+static inline void gpio_line_config(u8 line, u32 direction)
|
||||||
|
+{
|
||||||
|
+ u32 reg;
|
||||||
|
+ if (direction) {
|
||||||
|
+ if (line < 32) {
|
||||||
|
+ reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ reg |= (1 << line);
|
||||||
|
+ __raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ } else {
|
||||||
|
+ reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ reg |= (1 << (line - 32));
|
||||||
|
+ __raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ if (line < 32) {
|
||||||
|
+ reg = __raw_readl(CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ reg &= ~(1 << line);
|
||||||
|
+ __raw_writel(reg, CNS3XXX_GPIOA_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ } else {
|
||||||
|
+ reg = __raw_readl(CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ reg &= ~(1 << (line - 32));
|
||||||
|
+ __raw_writel(reg, CNS3XXX_GPIOB_BASE_VIRT + CNS3XXX_GPIO_DIR);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
+{
|
||||||
|
+ gpio_line_config(gpio, CNS3XXX_GPIO_IN);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int level)
|
||||||
|
+{
|
||||||
|
+ gpio_line_set(gpio, level);
|
||||||
|
+ gpio_line_config(gpio, CNS3XXX_GPIO_OUT);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int cns3xxx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
|
||||||
|
+{
|
||||||
|
+ return gpio_get_value(gpio);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void cns3xxx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
|
||||||
|
+{
|
||||||
|
+ gpio_set_value(gpio, value);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct gpio_chip cns3xxx_gpio_chip = {
|
||||||
|
+ .label = "CNS3XXX_GPIO_CHIP",
|
||||||
|
+ .direction_input = cns3xxx_gpio_direction_input,
|
||||||
|
+ .direction_output = cns3xxx_gpio_direction_output,
|
||||||
|
+ .get = cns3xxx_gpio_get_value,
|
||||||
|
+ .set = cns3xxx_gpio_set_value,
|
||||||
|
+ .base = 0,
|
||||||
|
+ .ngpio = 64,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+void __init cns3xxx_common_init(void)
|
||||||
|
{
|
||||||
|
iotable_init(cns3xxx_io_desc, ARRAY_SIZE(cns3xxx_io_desc));
|
||||||
|
#ifdef CONFIG_CACHE_L2X0
|
||||||
|
@@ -95,6 +178,7 @@ void __init cns3xxx_map_io(void)
|
||||||
|
#ifdef CONFIG_LOCAL_TIMERS
|
||||||
|
twd_base = (void __iomem *) CNS3XXX_TC11MP_TWD_BASE_VIRT;
|
||||||
|
#endif
|
||||||
|
+ gpiochip_add(&cns3xxx_gpio_chip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* used by entry-macro.S */
|
||||||
|
--- a/arch/arm/mach-cns3xxx/core.h
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.h
|
||||||
|
@@ -13,7 +13,7 @@
|
||||||
|
|
||||||
|
extern struct sys_timer cns3xxx_timer;
|
||||||
|
|
||||||
|
-void __init cns3xxx_map_io(void);
|
||||||
|
+void __init cns3xxx_common_init(void);
|
||||||
|
void __init cns3xxx_init_irq(void);
|
||||||
|
void cns3xxx_power_off(void);
|
||||||
|
|
||||||
|
--- a/arch/arm/mach-cns3xxx/laguna.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/laguna.c
|
||||||
|
@@ -609,7 +609,7 @@ static struct map_desc laguna_io_desc[]
|
||||||
|
|
||||||
|
static void __init laguna_map_io(void)
|
||||||
|
{
|
||||||
|
- cns3xxx_map_io();
|
||||||
|
+ cns3xxx_common_init();
|
||||||
|
iotable_init(laguna_io_desc, ARRAY_SIZE(laguna_io_desc));
|
||||||
|
|
||||||
|
laguna_early_serial_setup();
|
88
target/linux/cns3xxx/patches-3.0/105-cns3xxx_pcie_io.patch
Normal file
88
target/linux/cns3xxx/patches-3.0/105-cns3xxx_pcie_io.patch
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/core.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/core.c
|
||||||
|
@@ -78,6 +78,16 @@ static struct map_desc cns3xxx_io_desc[]
|
||||||
|
.pfn = __phys_to_pfn(CNS3XXX_L2C_BASE),
|
||||||
|
.length = SZ_4K,
|
||||||
|
.type = MT_DEVICE,
|
||||||
|
+ }, {
|
||||||
|
+ .virtual = CNS3XXX_PCIE0_IO_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_PCIE0_IO_BASE),
|
||||||
|
+ .length = SZ_16M,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
+ }, {
|
||||||
|
+ .virtual = CNS3XXX_PCIE1_IO_BASE_VIRT,
|
||||||
|
+ .pfn = __phys_to_pfn(CNS3XXX_PCIE1_IO_BASE),
|
||||||
|
+ .length = SZ_16M,
|
||||||
|
+ .type = MT_DEVICE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -184,13 +194,13 @@ void __init cns3xxx_common_init(void)
|
||||||
|
/* used by entry-macro.S */
|
||||||
|
void __init cns3xxx_init_irq(void)
|
||||||
|
{
|
||||||
|
- gic_init(0, 29, __io(CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT),
|
||||||
|
- __io(CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT));
|
||||||
|
+ gic_init(0, 29, (void __iomem *) CNS3XXX_TC11MP_GIC_DIST_BASE_VIRT,
|
||||||
|
+ (void __iomem *) CNS3XXX_TC11MP_GIC_CPU_BASE_VIRT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cns3xxx_power_off(void)
|
||||||
|
{
|
||||||
|
- u32 __iomem *pm_base = __io(CNS3XXX_PM_BASE_VIRT);
|
||||||
|
+ u32 __iomem *pm_base = (void __iomem *) CNS3XXX_PM_BASE_VIRT;
|
||||||
|
u32 clkctrl;
|
||||||
|
|
||||||
|
printk(KERN_INFO "powering system down...\n");
|
||||||
|
@@ -364,7 +374,7 @@ static void __init __cns3xxx_timer_init(
|
||||||
|
|
||||||
|
static void __init cns3xxx_timer_init(void)
|
||||||
|
{
|
||||||
|
- cns3xxx_tmr1 = __io(CNS3XXX_TIMER1_2_3_BASE_VIRT);
|
||||||
|
+ cns3xxx_tmr1 = (void __iomem *) CNS3XXX_TIMER1_2_3_BASE_VIRT;
|
||||||
|
|
||||||
|
__cns3xxx_timer_init(IRQ_CNS3XXX_TIMER0);
|
||||||
|
}
|
||||||
|
--- a/arch/arm/mach-cns3xxx/devices.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/devices.c
|
||||||
|
@@ -98,7 +98,7 @@ static struct platform_device cns3xxx_sd
|
||||||
|
|
||||||
|
void __init cns3xxx_sdhci_init(void)
|
||||||
|
{
|
||||||
|
- u32 __iomem *gpioa = __io(CNS3XXX_MISC_BASE_VIRT + 0x0014);
|
||||||
|
+ u32 __iomem *gpioa = (void __iomem *) (CNS3XXX_MISC_BASE_VIRT + 0x0014);
|
||||||
|
u32 gpioa_pins = __raw_readl(gpioa);
|
||||||
|
|
||||||
|
/* MMC/SD pins share with GPIOA */
|
||||||
|
--- a/arch/arm/mach-cns3xxx/include/mach/io.h
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/include/mach/io.h
|
||||||
|
@@ -9,9 +9,17 @@
|
||||||
|
#ifndef __MACH_IO_H
|
||||||
|
#define __MACH_IO_H
|
||||||
|
|
||||||
|
+#include "cns3xxx.h"
|
||||||
|
+
|
||||||
|
#define IO_SPACE_LIMIT 0xffffffff
|
||||||
|
|
||||||
|
-#define __io(a) __typesafe_io(a)
|
||||||
|
+static inline void __iomem *__io(unsigned long addr)
|
||||||
|
+{
|
||||||
|
+ return (void __iomem *)((addr - CNS3XXX_PCIE0_IO_BASE)
|
||||||
|
+ + CNS3XXX_PCIE0_IO_BASE_VIRT);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#define __io(a) __io(a)
|
||||||
|
#define __mem_pci(a) (a)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
--- a/drivers/spi/spi_cns3xxx.c
|
||||||
|
+++ b/drivers/spi/spi_cns3xxx.c
|
||||||
|
@@ -273,7 +273,7 @@ done:
|
||||||
|
|
||||||
|
static void __init cns3xxx_spi_initial(void)
|
||||||
|
{
|
||||||
|
- u32 __iomem *gpiob = __io(CNS3XXX_MISC_BASE_VIRT + 0x0018);
|
||||||
|
+ u32 __iomem *gpiob = (void __iomem *) (CNS3XXX_MISC_BASE_VIRT + 0x0018);
|
||||||
|
u32 gpiob_pins = __raw_readl(gpiob);
|
||||||
|
|
||||||
|
/* MMC/SD pins share with GPIOA */
|
190
target/linux/cns3xxx/patches-3.0/106-cns3xxx_sata_support.patch
Normal file
190
target/linux/cns3xxx/patches-3.0/106-cns3xxx_sata_support.patch
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
--- a/arch/arm/mach-cns3xxx/devices.c
|
||||||
|
+++ b/arch/arm/mach-cns3xxx/devices.c
|
||||||
|
@@ -41,7 +41,7 @@ static struct resource cns3xxx_ahci_reso
|
||||||
|
static u64 cns3xxx_ahci_dmamask = DMA_BIT_MASK(32);
|
||||||
|
|
||||||
|
static struct platform_device cns3xxx_ahci_pdev = {
|
||||||
|
- .name = "ahci",
|
||||||
|
+ .name = "ahci-cns3xxx",
|
||||||
|
.id = 0,
|
||||||
|
.resource = cns3xxx_ahci_resource,
|
||||||
|
.num_resources = ARRAY_SIZE(cns3xxx_ahci_resource),
|
||||||
|
--- a/drivers/ata/Kconfig
|
||||||
|
+++ b/drivers/ata/Kconfig
|
||||||
|
@@ -83,6 +83,17 @@ config SATA_AHCI_PLATFORM
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
+config SATA_AHCI_CNS3XXX
|
||||||
|
+ bool "AHCI Support on the Cavium Networks CNS3xxx SOC"
|
||||||
|
+ depends on ARCH_CNS3XXX
|
||||||
|
+ depends on SATA_AHCI_PLATFORM
|
||||||
|
+ help
|
||||||
|
+ This option enables AHCI platform driver to support CNS3xxx
|
||||||
|
+ System-on-Chip devices. This is only needed when using CNS3xxx AHCI
|
||||||
|
+ controller.
|
||||||
|
+
|
||||||
|
+ If unsure, say N.
|
||||||
|
+
|
||||||
|
config SATA_FSL
|
||||||
|
tristate "Freescale 3.0Gbps SATA support"
|
||||||
|
depends on FSL_SOC
|
||||||
|
--- a/drivers/ata/Makefile
|
||||||
|
+++ b/drivers/ata/Makefile
|
||||||
|
@@ -4,7 +4,10 @@ obj-$(CONFIG_ATA) += libata.o
|
||||||
|
# non-SFF interface
|
||||||
|
obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
|
||||||
|
obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
|
||||||
|
-obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o
|
||||||
|
+obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platforms.o libahci.o
|
||||||
|
+ahci_platforms-y += ahci_platform.o
|
||||||
|
+ahci_platforms-$(CONFIG_SATA_AHCI_CNS3XXX) += ahci_cns3xxx.o
|
||||||
|
+
|
||||||
|
obj-$(CONFIG_SATA_FSL) += sata_fsl.o
|
||||||
|
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
|
||||||
|
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/ata/ahci_cns3xxx.c
|
||||||
|
@@ -0,0 +1,52 @@
|
||||||
|
+/*
|
||||||
|
+ * AHCI support for CNS3xxx SoC
|
||||||
|
+ *
|
||||||
|
+ * Copyright 2010 MontaVista Software, LLC.
|
||||||
|
+ * Copyright 2010 Cavium Networks
|
||||||
|
+ *
|
||||||
|
+ * Authors: Anton Vorontsov <avorontsov@xxxxxxxxxx>
|
||||||
|
+ * Mac Lin <mkl0301@xxxxxxxxx>
|
||||||
|
+ *
|
||||||
|
+ * 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/libata.h>
|
||||||
|
+#include <linux/ahci_platform.h>
|
||||||
|
+#include "ahci.h"
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * TODO: move cns3xxx_ahci_init to here after cns3xxx_pwr*() calls are
|
||||||
|
+ * thread-safe
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+static int cns3xxx_ahci_softreset(struct ata_link *link, unsigned int *class,
|
||||||
|
+ unsigned long deadline)
|
||||||
|
+{
|
||||||
|
+ int pmp = sata_srst_pmp(link);
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ ret = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
|
||||||
|
+ if (pmp && ret)
|
||||||
|
+ return ahci_do_softreset(link, class, 0, deadline,
|
||||||
|
+ ahci_check_ready);
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct ata_port_operations cns3xxx_ahci_ops = {
|
||||||
|
+ .inherits = &ahci_ops,
|
||||||
|
+ .softreset = cns3xxx_ahci_softreset,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct ata_port_info cns3xxx_ata_port_info = {
|
||||||
|
+ .flags = AHCI_FLAG_COMMON,
|
||||||
|
+ .pio_mask = ATA_PIO4,
|
||||||
|
+ .udma_mask = ATA_UDMA6,
|
||||||
|
+ .port_ops = &cns3xxx_ahci_ops,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct ahci_platform_data cns3xxx_ahci_platform_data = {
|
||||||
|
+ .ata_port_info = &cns3xxx_ata_port_info,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
--- a/drivers/ata/ahci_platform.c
|
||||||
|
+++ b/drivers/ata/ahci_platform.c
|
||||||
|
@@ -19,9 +19,11 @@
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
+#include <linux/mod_devicetable.h>
|
||||||
|
#include <linux/libata.h>
|
||||||
|
#include <linux/ahci_platform.h>
|
||||||
|
#include "ahci.h"
|
||||||
|
+#include "ahci_platform.h"
|
||||||
|
|
||||||
|
static struct scsi_host_template ahci_platform_sht = {
|
||||||
|
AHCI_SHT("ahci_platform"),
|
||||||
|
@@ -29,6 +31,7 @@ static struct scsi_host_template ahci_pl
|
||||||
|
|
||||||
|
static int __init ahci_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct ahci_platform_data *pdata = dev->platform_data;
|
||||||
|
struct ata_port_info pi = {
|
||||||
|
@@ -46,6 +49,9 @@ static int __init ahci_probe(struct plat
|
||||||
|
int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
+ if (!pdata && platid && platid->driver_data)
|
||||||
|
+ pdata = (void *)platid->driver_data;
|
||||||
|
+
|
||||||
|
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!mem) {
|
||||||
|
dev_err(dev, "no mmio space\n");
|
||||||
|
@@ -171,17 +177,28 @@ static int __devexit ahci_remove(struct
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static const struct platform_device_id ahci_platform_ids[] = {
|
||||||
|
+ { "ahci", },
|
||||||
|
+#ifdef CONFIG_SATA_AHCI_CNS3XXX
|
||||||
|
+ { "ahci-cns3xxx", (kernel_ulong_t)&cns3xxx_ahci_platform_data},
|
||||||
|
+#endif
|
||||||
|
+ { },
|
||||||
|
+};
|
||||||
|
+MODULE_DEVICE_TABLE(platform, ahci_platform_ids);
|
||||||
|
+
|
||||||
|
static struct platform_driver ahci_driver = {
|
||||||
|
- .remove = __devexit_p(ahci_remove),
|
||||||
|
.driver = {
|
||||||
|
.name = "ahci",
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
+ .probe = ahci_probe,
|
||||||
|
+ .remove = __devexit_p(ahci_remove),
|
||||||
|
+ .id_table = ahci_platform_ids,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init ahci_init(void)
|
||||||
|
{
|
||||||
|
- return platform_driver_probe(&ahci_driver, ahci_probe);
|
||||||
|
+ return platform_driver_register(&ahci_driver);
|
||||||
|
}
|
||||||
|
module_init(ahci_init);
|
||||||
|
|
||||||
|
@@ -194,4 +211,3 @@ module_exit(ahci_exit);
|
||||||
|
MODULE_DESCRIPTION("AHCI SATA platform driver");
|
||||||
|
MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
-MODULE_ALIAS("platform:ahci");
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/ata/ahci_platform.h
|
||||||
|
@@ -0,0 +1,19 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright 2010 MontaVista Software, LLC.
|
||||||
|
+ * Copyright 2010 Cavium Networks
|
||||||
|
+ *
|
||||||
|
+ * Authors: Anton Vorontsov <avorontsov@xxxxxxxxxx>
|
||||||
|
+ * Mac Lin <mkl0301@xxxxxxxxx>
|
||||||
|
+ *
|
||||||
|
+ * 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.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef _DRIVERS_SATA_AHCI_PLATFORMS_H
|
||||||
|
+#define _DRIVERS_SATA_AHCI_PLATFORMS_H
|
||||||
|
+
|
||||||
|
+extern struct ahci_platform_data cns3xxx_ahci_platform_data;
|
||||||
|
+
|
||||||
|
+#endif /*_DRIVERS_SATA_AHCI_PLATFORMS_H*/
|
||||||
|
+
|
339
target/linux/cns3xxx/patches-3.0/110-gateworks_gsp_support.patch
Normal file
339
target/linux/cns3xxx/patches-3.0/110-gateworks_gsp_support.patch
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
--- a/drivers/hwmon/Kconfig
|
||||||
|
+++ b/drivers/hwmon/Kconfig
|
||||||
|
@@ -401,6 +401,15 @@ config SENSORS_GL520SM
|
||||||
|
This driver can also be built as a module. If so, the module
|
||||||
|
will be called gl520sm.
|
||||||
|
|
||||||
|
+config SENSORS_GSP
|
||||||
|
+ tristate "Gateworks System Peripheral"
|
||||||
|
+ depends on I2C && EXPERIMENTAL
|
||||||
|
+ help
|
||||||
|
+ If you say yes here you get support for the Gateworks System Peripherals.
|
||||||
|
+
|
||||||
|
+ This driver can also be built as a module. If so, the module
|
||||||
|
+ will be called gsp.
|
||||||
|
+
|
||||||
|
config SENSORS_GPIO_FAN
|
||||||
|
tristate "GPIO fan"
|
||||||
|
depends on GENERIC_GPIO
|
||||||
|
--- a/drivers/hwmon/Makefile
|
||||||
|
+++ b/drivers/hwmon/Makefile
|
||||||
|
@@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l7
|
||||||
|
obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
|
||||||
|
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
|
||||||
|
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
|
||||||
|
+obj-$(CONFIG_SENSORS_GSP) += gsp.o
|
||||||
|
|
||||||
|
# PMBus drivers
|
||||||
|
obj-$(CONFIG_PMBUS) += pmbus_core.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/drivers/hwmon/gsp.c
|
||||||
|
@@ -0,0 +1,308 @@
|
||||||
|
+/*
|
||||||
|
+ * A hwmon driver for the Gateworks System Peripheral
|
||||||
|
+ * Copyright (C) 2009 Gateworks Corporation
|
||||||
|
+ *
|
||||||
|
+ * Author: Chris Lang <clang@gateworks.com>
|
||||||
|
+ *
|
||||||
|
+ * This program is free software; you can redistribute it and/or modify
|
||||||
|
+ * it under the terms of the GNU General Public License,
|
||||||
|
+ * as published by the Free Software Foundation - version 2.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/i2c.h>
|
||||||
|
+#include <linux/hwmon.h>
|
||||||
|
+#include <linux/hwmon-sysfs.h>
|
||||||
|
+#include <linux/err.h>
|
||||||
|
+#include <linux/slab.h>
|
||||||
|
+
|
||||||
|
+#define DRV_VERSION "0.2"
|
||||||
|
+
|
||||||
|
+enum chips { gsp };
|
||||||
|
+
|
||||||
|
+/* AD7418 registers */
|
||||||
|
+#define GSP_REG_TEMP_IN 0x00
|
||||||
|
+#define GSP_REG_VIN 0x02
|
||||||
|
+#define GSP_REG_3P3 0x05
|
||||||
|
+#define GSP_REG_BAT 0x08
|
||||||
|
+#define GSP_REG_5P0 0x0b
|
||||||
|
+#define GSP_REG_CORE 0x0e
|
||||||
|
+#define GSP_REG_CPU1 0x11
|
||||||
|
+#define GSP_REG_CPU2 0x14
|
||||||
|
+#define GSP_REG_DRAM 0x17
|
||||||
|
+#define GSP_REG_EXT_BAT 0x1a
|
||||||
|
+#define GSP_REG_IO1 0x1d
|
||||||
|
+#define GSP_REG_IO2 0x20
|
||||||
|
+#define GSP_REG_PCIE 0x23
|
||||||
|
+#define GSP_REG_CURRENT 0x26
|
||||||
|
+#define GSP_FAN_0 0x2C
|
||||||
|
+#define GSP_FAN_1 0x2E
|
||||||
|
+#define GSP_FAN_2 0x30
|
||||||
|
+#define GSP_FAN_3 0x32
|
||||||
|
+#define GSP_FAN_4 0x34
|
||||||
|
+#define GSP_FAN_5 0x36
|
||||||
|
+
|
||||||
|
+struct gsp_sensor_info {
|
||||||
|
+ const char* name;
|
||||||
|
+ int reg;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static const struct gsp_sensor_info gsp_sensors[] = {
|
||||||
|
+ {"temp", GSP_REG_TEMP_IN},
|
||||||
|
+ {"vin", GSP_REG_VIN},
|
||||||
|
+ {"3p3", GSP_REG_3P3},
|
||||||
|
+ {"bat", GSP_REG_BAT},
|
||||||
|
+ {"5p0", GSP_REG_5P0},
|
||||||
|
+ {"core", GSP_REG_CORE},
|
||||||
|
+ {"cpu1", GSP_REG_CPU1},
|
||||||
|
+ {"cpu2", GSP_REG_CPU2},
|
||||||
|
+ {"dram", GSP_REG_DRAM},
|
||||||
|
+ {"ext_bat", GSP_REG_EXT_BAT},
|
||||||
|
+ {"io1", GSP_REG_IO1},
|
||||||
|
+ {"io2", GSP_REG_IO2},
|
||||||
|
+ {"pci2", GSP_REG_PCIE},
|
||||||
|
+ {"current", GSP_REG_CURRENT},
|
||||||
|
+ {"fan_point0", GSP_FAN_0},
|
||||||
|
+ {"fan_point1", GSP_FAN_1},
|
||||||
|
+ {"fan_point2", GSP_FAN_2},
|
||||||
|
+ {"fan_point3", GSP_FAN_3},
|
||||||
|
+ {"fan_point4", GSP_FAN_4},
|
||||||
|
+ {"fan_point5", GSP_FAN_5},
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+struct gsp_data {
|
||||||
|
+ struct device *hwmon_dev;
|
||||||
|
+ struct attribute_group attrs;
|
||||||
|
+ enum chips type;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+static int gsp_probe(struct i2c_client *client,
|
||||||
|
+ const struct i2c_device_id *id);
|
||||||
|
+static int gsp_remove(struct i2c_client *client);
|
||||||
|
+
|
||||||
|
+static const struct i2c_device_id gsp_id[] = {
|
||||||
|
+ { "gsp", 0 },
|
||||||
|
+ { }
|
||||||
|
+};
|
||||||
|
+MODULE_DEVICE_TABLE(i2c, gsp_id);
|
||||||
|
+
|
||||||
|
+static struct i2c_driver gsp_driver = {
|
||||||
|
+ .driver = {
|
||||||
|
+ .name = "gsp",
|
||||||
|
+ },
|
||||||
|
+ .probe = gsp_probe,
|
||||||
|
+ .remove = gsp_remove,
|
||||||
|
+ .id_table = gsp_id,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* All registers are word-sized, except for the configuration registers.
|
||||||
|
+ * AD7418 uses a high-byte first convention. Do NOT use those functions to
|
||||||
|
+ * access the configuration registers CONF and CONF2, as they are byte-sized.
|
||||||
|
+ */
|
||||||
|
+static inline int gsp_read(struct i2c_client *client, u8 reg)
|
||||||
|
+{
|
||||||
|
+ unsigned int adc = 0;
|
||||||
|
+ if (reg == GSP_REG_TEMP_IN || reg > GSP_REG_CURRENT)
|
||||||
|
+ {
|
||||||
|
+ adc |= i2c_smbus_read_byte_data(client, reg);
|
||||||
|
+ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||||
|
+ return adc;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ adc |= i2c_smbus_read_byte_data(client, reg);
|
||||||
|
+ adc |= i2c_smbus_read_byte_data(client, reg + 1) << 8;
|
||||||
|
+ adc |= i2c_smbus_read_byte_data(client, reg + 2) << 16;
|
||||||
|
+ return adc;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline int gsp_write(struct i2c_client *client, u8 reg, u16 value)
|
||||||
|
+{
|
||||||
|
+ i2c_smbus_write_byte_data(client, reg, value & 0xff);
|
||||||
|
+ i2c_smbus_write_byte_data(client, reg + 1, ((value >> 8) & 0xff));
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t show_adc(struct device *dev, struct device_attribute *devattr,
|
||||||
|
+ char *buf)
|
||||||
|
+{
|
||||||
|
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
|
+ struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
+ return sprintf(buf, "%d\n", gsp_read(client, gsp_sensors[attr->index].reg));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t show_label(struct device *dev,
|
||||||
|
+ struct device_attribute *devattr, char *buf)
|
||||||
|
+{
|
||||||
|
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
|
+
|
||||||
|
+ return sprintf(buf, "%s\n", gsp_sensors[attr->index].name);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static ssize_t store_fan(struct device *dev,
|
||||||
|
+ struct device_attribute *devattr, const char *buf, size_t count)
|
||||||
|
+{
|
||||||
|
+ u16 val;
|
||||||
|
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
|
||||||
|
+ struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
+ val = simple_strtoul(buf, NULL, 10);
|
||||||
|
+ gsp_write(client, gsp_sensors[attr->index].reg, val);
|
||||||
|
+ return count;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static SENSOR_DEVICE_ATTR(temp0_input, S_IRUGO, show_adc, NULL, 0);
|
||||||
|
+static SENSOR_DEVICE_ATTR(temp0_label, S_IRUGO, show_label, NULL, 0);
|
||||||
|
+
|
||||||
|
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_adc, NULL, 1);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL, 1);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_adc, NULL, 2);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in1_label, S_IRUGO, show_label, NULL, 2);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_adc, NULL, 3);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in2_label, S_IRUGO, show_label, NULL, 3);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_adc, NULL, 4);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 4);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_adc, NULL, 5);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL, 5);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_adc, NULL, 6);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL, 6);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_adc, NULL, 7);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL, 7);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_adc, NULL, 8);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 8);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_adc, NULL, 9);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 9);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_adc, NULL, 10);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 10);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_adc, NULL, 11);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in10_label, S_IRUGO, show_label, NULL, 11);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_adc, NULL, 12);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in11_label, S_IRUGO, show_label, NULL, 12);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_adc, NULL, 13);
|
||||||
|
+static SENSOR_DEVICE_ATTR(in12_label, S_IRUGO, show_label, NULL, 13);
|
||||||
|
+
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point0, S_IRUGO | S_IWUSR, show_adc, store_fan, 14);
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point1, S_IRUGO | S_IWUSR, show_adc, store_fan, 15);
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point2, S_IRUGO | S_IWUSR, show_adc, store_fan, 16);
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point3, S_IRUGO | S_IWUSR, show_adc, store_fan, 17);
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point4, S_IRUGO | S_IWUSR, show_adc, store_fan, 18);
|
||||||
|
+static SENSOR_DEVICE_ATTR(fan0_point5, S_IRUGO | S_IWUSR, show_adc, store_fan, 19);
|
||||||
|
+
|
||||||
|
+static struct attribute *gsp_attributes[] = {
|
||||||
|
+ &sensor_dev_attr_temp0_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in0_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in1_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in2_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in3_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in4_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in5_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in6_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in7_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in8_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in9_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in10_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in11_input.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in12_input.dev_attr.attr,
|
||||||
|
+
|
||||||
|
+ &sensor_dev_attr_temp0_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in0_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in1_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in2_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in3_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in4_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in5_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in6_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in7_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in8_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in9_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in10_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in11_label.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_in12_label.dev_attr.attr,
|
||||||
|
+
|
||||||
|
+ &sensor_dev_attr_fan0_point0.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_fan0_point1.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_fan0_point2.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_fan0_point3.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_fan0_point4.dev_attr.attr,
|
||||||
|
+ &sensor_dev_attr_fan0_point5.dev_attr.attr,
|
||||||
|
+ NULL
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static int gsp_probe(struct i2c_client *client,
|
||||||
|
+ const struct i2c_device_id *id)
|
||||||
|
+{
|
||||||
|
+ struct i2c_adapter *adapter = client->adapter;
|
||||||
|
+ struct gsp_data *data;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||||
|
+ I2C_FUNC_SMBUS_WORD_DATA)) {
|
||||||
|
+ err = -EOPNOTSUPP;
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!(data = kzalloc(sizeof(struct gsp_data), GFP_KERNEL))) {
|
||||||
|
+ err = -ENOMEM;
|
||||||
|
+ goto exit;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i2c_set_clientdata(client, data);
|
||||||
|
+
|
||||||
|
+ data->type = id->driver_data;
|
||||||
|
+
|
||||||
|
+ switch (data->type) {
|
||||||
|
+ case 0:
|
||||||
|
+ data->attrs.attrs = gsp_attributes;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ dev_info(&client->dev, "%s chip found\n", client->name);
|
||||||
|
+
|
||||||
|
+ /* Register sysfs hooks */
|
||||||
|
+ if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs)))
|
||||||
|
+ goto exit_free;
|
||||||
|
+
|
||||||
|
+ data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||||
|
+ if (IS_ERR(data->hwmon_dev)) {
|
||||||
|
+ err = PTR_ERR(data->hwmon_dev);
|
||||||
|
+ goto exit_remove;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+exit_remove:
|
||||||
|
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
|
+exit_free:
|
||||||
|
+ kfree(data);
|
||||||
|
+exit:
|
||||||
|
+ return err;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int gsp_remove(struct i2c_client *client)
|
||||||
|
+{
|
||||||
|
+ struct gsp_data *data = i2c_get_clientdata(client);
|
||||||
|
+ hwmon_device_unregister(data->hwmon_dev);
|
||||||
|
+ sysfs_remove_group(&client->dev.kobj, &data->attrs);
|
||||||
|
+ kfree(data);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static int __init gsp_init(void)
|
||||||
|
+{
|
||||||
|
+ return i2c_add_driver(&gsp_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __exit gsp_exit(void)
|
||||||
|
+{
|
||||||
|
+ i2c_del_driver(&gsp_driver);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+module_init(gsp_init);
|
||||||
|
+module_exit(gsp_exit);
|
||||||
|
+
|
||||||
|
+MODULE_AUTHOR("Chris Lang <clang@gateworks.com>");
|
||||||
|
+MODULE_DESCRIPTION("GSP HWMON driver");
|
||||||
|
+MODULE_LICENSE("GPL");
|
||||||
|
+MODULE_VERSION(DRV_VERSION);
|
||||||
|
+
|
22669
target/linux/cns3xxx/patches-3.0/200-dwc_otg.patch
Normal file
22669
target/linux/cns3xxx/patches-3.0/200-dwc_otg.patch
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user