[lantiq] get ready for 3.0
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@27496 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
622243009f
commit
111e5605f9
|
@ -0,0 +1,37 @@
|
|||
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
|
||||
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
|
||||
# CONFIG_ATH79 is not set
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_ATTRS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
|
||||
CONFIG_HAVE_GENERIC_HARDIRQS=y
|
||||
CONFIG_HAVE_IRQ_WORK=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
# CONFIG_INPUT_GPIO_BUTTONS is not set
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
# CONFIG_ISDN is not set
|
||||
CONFIG_LANTIQ_ETOP=y
|
||||
CONFIG_LANTIQ_MACH_EASY50601=y
|
||||
CONFIG_MACH_NO_WESTBRIDGE=y
|
||||
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
|
||||
# CONFIG_MTD_LATCH_ADDR is not set
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_PER_CPU_KM=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
# CONFIG_PREEMPT_RCU is not set
|
||||
# CONFIG_QUOTACTL is not set
|
||||
CONFIG_SOC_AMAZON_SE=y
|
||||
# CONFIG_SOC_FALCON is not set
|
||||
CONFIG_SOC_TYPE_XWAY=y
|
||||
# CONFIG_SOC_XWAY is not set
|
||||
CONFIG_XZ_DEC=y
|
|
@ -0,0 +1,112 @@
|
|||
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
|
||||
# CONFIG_ARCH_HAS_ILOG2_U32 is not set
|
||||
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
|
||||
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
|
||||
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
|
||||
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||
CONFIG_ARCH_REQUIRE_GPIOLIB=y
|
||||
# CONFIG_ARCH_SUPPORTS_MSI is not set
|
||||
CONFIG_ARCH_SUPPORTS_OPROFILE=y
|
||||
CONFIG_ARCH_SUSPEND_POSSIBLE=y
|
||||
# CONFIG_ATH79 is not set
|
||||
CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_BRCMUTIL is not set
|
||||
CONFIG_CEVT_R4K=y
|
||||
CONFIG_CEVT_R4K_LIB=y
|
||||
CONFIG_CPU_BIG_ENDIAN=y
|
||||
CONFIG_CPU_HAS_PREFETCH=y
|
||||
CONFIG_CPU_HAS_SYNC=y
|
||||
CONFIG_CPU_MIPS32=y
|
||||
# CONFIG_CPU_MIPS32_R1 is not set
|
||||
CONFIG_CPU_MIPS32_R2=y
|
||||
CONFIG_CPU_MIPSR2=y
|
||||
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
|
||||
CONFIG_CPU_SUPPORTS_HIGHMEM=y
|
||||
CONFIG_CSRC_R4K=y
|
||||
CONFIG_CSRC_R4K_LIB=y
|
||||
CONFIG_DECOMPRESS_LZMA=y
|
||||
CONFIG_DMA_NONCOHERENT=y
|
||||
CONFIG_EARLY_PRINTK=y
|
||||
# CONFIG_FSNOTIFY is not set
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS=y
|
||||
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
|
||||
CONFIG_GENERIC_CMOS_UPDATE=y
|
||||
CONFIG_GENERIC_GPIO=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_HARDWARE_WATCHPOINTS=y
|
||||
CONFIG_HAS_DMA=y
|
||||
CONFIG_HAS_IOMEM=y
|
||||
CONFIG_HAS_IOPORT=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_ARCH_KGDB=y
|
||||
CONFIG_HAVE_CLK=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_ATTRS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
|
||||
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
|
||||
CONFIG_HAVE_GENERIC_HARDIRQS=y
|
||||
CONFIG_HAVE_IDE=y
|
||||
CONFIG_HAVE_IRQ_WORK=y
|
||||
CONFIG_HAVE_OPROFILE=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HW_RANDOM=y
|
||||
CONFIG_HZ=250
|
||||
# CONFIG_HZ_100 is not set
|
||||
CONFIG_HZ_250=y
|
||||
CONFIG_IFX_UDP_REDIRECT=y
|
||||
CONFIG_IMAGE_CMDLINE_HACK=y
|
||||
CONFIG_INITRAMFS_SOURCE=""
|
||||
CONFIG_IRQ_CPU=y
|
||||
CONFIG_LANTIQ=y
|
||||
CONFIG_LANTIQ_MACH_95C3AM1=y
|
||||
CONFIG_LANTIQ_MACH_EASY98000=y
|
||||
CONFIG_LANTIQ_MACH_EASY98020=y
|
||||
CONFIG_LANTIQ_WDT=y
|
||||
CONFIG_LEDS_GPIO=y
|
||||
CONFIG_MACH_NO_WESTBRIDGE=y
|
||||
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
|
||||
CONFIG_MIPS=y
|
||||
CONFIG_MIPS_L1_CACHE_SHIFT=5
|
||||
CONFIG_MIPS_MACHINE=y
|
||||
CONFIG_MIPS_MT_DISABLED=y
|
||||
# CONFIG_MIPS_MT_SMP is not set
|
||||
# CONFIG_MIPS_MT_SMTC is not set
|
||||
# CONFIG_MIPS_VPE_LOADER is not set
|
||||
CONFIG_MTD_CFI_ADV_OPTIONS=y
|
||||
CONFIG_MTD_CFI_GEOMETRY=y
|
||||
CONFIG_MTD_CMDLINE_PARTS=y
|
||||
CONFIG_MTD_LANTIQ=y
|
||||
CONFIG_MTD_UIMAGE_SPLIT=y
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_PER_CPU_KM=y
|
||||
CONFIG_NLS=y
|
||||
CONFIG_PAGEFLAGS_EXTENDED=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
CONFIG_PHYLIB=y
|
||||
# CONFIG_PREEMPT_RCU is not set
|
||||
# CONFIG_QUOTACTL is not set
|
||||
# CONFIG_RTC_CLASS is not set
|
||||
CONFIG_RTL8366RB_PHY=y
|
||||
CONFIG_RTL8366_SMI=y
|
||||
# CONFIG_SCSI_DMA is not set
|
||||
# CONFIG_SERIAL_8250 is not set
|
||||
CONFIG_SERIAL_LANTIQ=y
|
||||
CONFIG_SWAP_IO_SPACE=y
|
||||
CONFIG_SWCONFIG=y
|
||||
CONFIG_SYS_HAS_CPU_MIPS32_R1=y
|
||||
CONFIG_SYS_HAS_CPU_MIPS32_R2=y
|
||||
CONFIG_SYS_HAS_EARLY_PRINTK=y
|
||||
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
|
||||
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
|
||||
CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
|
||||
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
|
||||
CONFIG_XZ_DEC=y
|
||||
CONFIG_ZONE_DMA_FLAG=0
|
|
@ -0,0 +1,25 @@
|
|||
CONFIG_CPU_MIPSR2_IRQ_EI=y
|
||||
CONFIG_CPU_MIPSR2_IRQ_VI=y
|
||||
CONFIG_IFX_VPE_CACHE_SPLIT=y
|
||||
CONFIG_IFX_VPE_EXT=y
|
||||
CONFIG_M25PXX_USE_FAST_READ=y
|
||||
CONFIG_MIPS_MT=y
|
||||
# CONFIG_MIPS_VPE_APSP_API is not set
|
||||
CONFIG_MIPS_VPE_LOADER=y
|
||||
CONFIG_MIPS_VPE_LOADER_TOM=y
|
||||
CONFIG_MTD_M25P80=y
|
||||
CONFIG_MTD_NAND=y
|
||||
CONFIG_MTD_NAND_ECC=y
|
||||
CONFIG_MTD_NAND_PLATFORM=y
|
||||
# CONFIG_MTD_SM_COMMON is not set
|
||||
CONFIG_MTSCHED=y
|
||||
# CONFIG_PERFCTRS is not set
|
||||
# CONFIG_SOC_AMAZON_SE is not set
|
||||
CONFIG_SOC_FALCON=y
|
||||
# CONFIG_SOC_TYPE_XWAY is not set
|
||||
# CONFIG_SOC_XWAY is not set
|
||||
CONFIG_SPI=y
|
||||
# CONFIG_SPI_BITBANG is not set
|
||||
CONFIG_SPI_FALCON=y
|
||||
# CONFIG_SPI_GPIO is not set
|
||||
CONFIG_SPI_MASTER=y
|
|
@ -0,0 +1,20 @@
|
|||
--- a/arch/mips/lantiq/xway/gpio_ebu.c
|
||||
+++ b/arch/mips/lantiq/xway/gpio_ebu.c
|
||||
@@ -63,7 +63,6 @@ static struct gpio_chip ltq_ebu_chip = {
|
||||
.set = ltq_ebu_set,
|
||||
.base = 72,
|
||||
.ngpio = 16,
|
||||
- .can_sleep = 1,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
--- a/arch/mips/lantiq/xway/gpio_stp.c
|
||||
+++ b/arch/mips/lantiq/xway/gpio_stp.c
|
||||
@@ -72,7 +72,6 @@ static struct gpio_chip ltq_stp_chip = {
|
||||
.set = ltq_stp_set,
|
||||
.base = 48,
|
||||
.ngpio = 24,
|
||||
- .can_sleep = 1,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
--- a/arch/mips/lantiq/xway/mach-easy50601.c
|
||||
+++ b/arch/mips/lantiq/xway/mach-easy50601.c
|
||||
@@ -32,12 +32,7 @@
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x20000,
|
||||
- .size = 0xE0000,
|
||||
- },
|
||||
- {
|
||||
- .name = "rootfs",
|
||||
- .offset = 0x100000,
|
||||
- .size = 0x300000,
|
||||
+ .size = 0x3d0000,
|
||||
},
|
||||
};
|
||||
|
||||
--- a/arch/mips/lantiq/xway/mach-easy50712.c
|
||||
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
|
||||
@@ -34,12 +34,7 @@
|
||||
{
|
||||
.name = "linux",
|
||||
.offset = 0x20000,
|
||||
- .size = 0xe0000,
|
||||
- },
|
||||
- {
|
||||
- .name = "rootfs",
|
||||
- .offset = 0x100000,
|
||||
- .size = 0x300000,
|
||||
+ .size = 0x3d0000,
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
--- a/drivers/mtd/maps/lantiq-flash.c
|
||||
+++ b/drivers/mtd/maps/lantiq-flash.c
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
||||
+#include "../mtdcore.h"
|
||||
+
|
||||
#include <lantiq_soc.h>
|
||||
#include <lantiq_platform.h>
|
||||
|
||||
--- a/arch/mips/lantiq/clk.c
|
||||
+++ b/arch/mips/lantiq/clk.c
|
||||
@@ -100,6 +100,17 @@
|
||||
}
|
||||
EXPORT_SYMBOL(clk_put);
|
||||
|
||||
+int clk_enable(struct clk *clk)
|
||||
+{
|
||||
+ /* clocks are always enabled*/
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void clk_disable(struct clk *clk)
|
||||
+{
|
||||
+ /* clocks are always enabled*/
|
||||
+}
|
||||
+
|
||||
static inline u32 ltq_get_counter_resolution(void)
|
||||
{
|
||||
u32 res;
|
||||
--- a/arch/mips/lantiq/irq.c
|
||||
+++ b/arch/mips/lantiq/irq.c
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
+#include <linux/module.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq_cpu.h>
|
||||
@@ -105,6 +106,7 @@
|
||||
ltq_icu_w32(ltq_icu_r32(ier) & ~(1 << irq_nr), ier);
|
||||
ltq_icu_w32((1 << irq_nr), isr);
|
||||
}
|
||||
+EXPORT_SYMBOL(ltq_mask_and_ack_irq);
|
||||
|
||||
static void ltq_ack_irq(struct irq_data *d)
|
||||
{
|
||||
--- a/arch/mips/lantiq/setup.c
|
||||
+++ b/arch/mips/lantiq/setup.c
|
||||
@@ -18,6 +18,8 @@
|
||||
#include "devices.h"
|
||||
#include "prom.h"
|
||||
|
||||
+unsigned long physical_memsize = 0L;
|
||||
+
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
/* assume 16M as default incase uboot fails to pass proper ramsize */
|
||||
@@ -40,8 +42,8 @@
|
||||
}
|
||||
envp++;
|
||||
}
|
||||
- memsize *= 1024 * 1024;
|
||||
- add_memory_region(0x00000000, memsize, BOOT_MEM_RAM);
|
||||
+ physical_memsize = memsize * 1024 * 1024;
|
||||
+ add_memory_region(0x00000000, physical_memsize, BOOT_MEM_RAM);
|
||||
}
|
||||
|
||||
static int __init
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,828 @@
|
|||
--- a/drivers/i2c/busses/Makefile
|
||||
+++ b/drivers/i2c/busses/Makefile
|
||||
@@ -82,5 +82,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
|
||||
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
|
||||
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
|
||||
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
|
||||
+obj-$(CONFIG_I2C_FALCON) += i2c-falcon.o
|
||||
|
||||
ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG
|
||||
--- a/drivers/i2c/busses/Kconfig
|
||||
+++ b/drivers/i2c/busses/Kconfig
|
||||
@@ -282,6 +282,10 @@ config I2C_POWERMAC
|
||||
|
||||
comment "I2C system bus drivers (mostly embedded / system-on-chip)"
|
||||
|
||||
+config I2C_FALCON
|
||||
+ tristate "Falcon I2C interface"
|
||||
+# depends on SOC_FALCON
|
||||
+
|
||||
config I2C_AT91
|
||||
tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
|
||||
depends on ARCH_AT91 && EXPERIMENTAL && BROKEN
|
||||
--- /dev/null
|
||||
+++ b/drivers/i2c/busses/i2c-falcon.c
|
||||
@@ -0,0 +1,803 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+/* #define DEBUG */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/ioport.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+/* CURRENT ISSUES:
|
||||
+ * - no high speed support
|
||||
+ * - rx issue with "address mode" & "tx end" interrupts
|
||||
+ * - ten bit mode is not tested
|
||||
+ */
|
||||
+
|
||||
+/* mapping for access macros */
|
||||
+#define reg_r32(reg) __raw_readl(reg)
|
||||
+#define reg_w32(val, reg) __raw_writel(val, reg)
|
||||
+#define reg_w32_mask(clear, set, reg) \
|
||||
+ reg_w32((reg_r32(reg) & ~(clear)) | (set), reg)
|
||||
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx])
|
||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx])
|
||||
+#define i2c (priv->membase)
|
||||
+#include <falcon/i2c_reg.h>
|
||||
+
|
||||
+/* enable hacks to overcome current issue */
|
||||
+#define FALCON_FIX_ME
|
||||
+
|
||||
+#define FALCON_I2C_ADDR 0x00
|
||||
+#define FALCON_I2C_READY_TIMEOUT 1000
|
||||
+#define FALCON_I2C_WAIT_TIMEOUT 10
|
||||
+
|
||||
+#define DRV_NAME "i2c-falcon"
|
||||
+
|
||||
+#if defined(DEBUG)
|
||||
+#define static /* no static functions for better debugging */
|
||||
+#endif
|
||||
+
|
||||
+#define FALCON_I2C_ARB_LOST (1 << 0)
|
||||
+#define FALCON_I2C_NACK (1 << 1)
|
||||
+#define FALCON_I2C_RX_UFL (1 << 2)
|
||||
+#define FALCON_I2C_RX_OFL (1 << 3)
|
||||
+#define FALCON_I2C_TX_UFL (1 << 4)
|
||||
+#define FALCON_I2C_TX_OFL (1 << 5)
|
||||
+#define FALCON_I2C_BURST_REQ (1 << 6)
|
||||
+#define FALCON_I2C_RX (1 << 7)
|
||||
+#define FALCON_I2C_TX_END (1 << 8)
|
||||
+#define FALCON_I2C_ADDR_MATCH (1 << 9) /* doesn't trigger */
|
||||
+
|
||||
+struct falcon_i2c {
|
||||
+ spinlock_t lock;
|
||||
+
|
||||
+ enum {
|
||||
+ FALCON_I2C_MODE_100 = 1,
|
||||
+ FALCON_I2C_MODE_400 = 2,
|
||||
+ FALCON_I2C_MODE_3400 = 3
|
||||
+ } mode; /* current speed mode */
|
||||
+
|
||||
+ int ten_bit; /* current address mode */
|
||||
+ unsigned long status; /* bus events holder */
|
||||
+ struct clk *clk; /* clock input for i2c hardware block */
|
||||
+ struct gpon_reg_i2c __iomem *membase; /* base of mapped registers */
|
||||
+ int irq_lb, irq_b, irq_err, irq_p; /* last burst, burst, error,
|
||||
+ protocol IRQs */
|
||||
+ struct completion done;
|
||||
+ struct i2c_adapter adap;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+#define FALCON_I2C_ERROR_MASK (FALCON_I2C_NACK \
|
||||
+ | FALCON_I2C_ARB_LOST \
|
||||
+ | FALCON_I2C_RX_OFL \
|
||||
+ | FALCON_I2C_RX_UFL \
|
||||
+ | FALCON_I2C_TX_OFL \
|
||||
+ | FALCON_I2C_TX_UFL)
|
||||
+
|
||||
+#define FALCON_I2C_ERROR(priv) (priv->status & FALCON_I2C_ERROR_MASK)
|
||||
+#define FALCON_I2C_ERROR_CLEAR(priv) do { \
|
||||
+ priv->status &= \
|
||||
+ ~FALCON_I2C_ERROR_MASK; \
|
||||
+ } while (0)
|
||||
+
|
||||
+static void falcon_addr_configure(struct falcon_i2c *priv, int ten_bit)
|
||||
+{
|
||||
+ u32 ten_bit_mask = ten_bit ? I2C_ADDR_CFG_TBAM_10bit : 0;
|
||||
+
|
||||
+ /* configure address */
|
||||
+ i2c_w32(I2C_ADDR_CFG_SOPE_EN /* generate stop when no more data in the
|
||||
+ fifo */
|
||||
+ | I2C_ADDR_CFG_SONA_EN /* generate stop when NA received */
|
||||
+ | I2C_ADDR_CFG_MnS_EN /* we are master device */
|
||||
+ | ten_bit_mask
|
||||
+ | FALCON_I2C_ADDR, /* our address */
|
||||
+ addr_cfg);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t falcon_i2c_isr(int irq, void *dev_id)
|
||||
+{
|
||||
+ u32 i_raw, i_pro, i_err;
|
||||
+ struct falcon_i2c *priv = dev_id;
|
||||
+ unsigned long flags;
|
||||
+ unsigned int old_status;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ old_status = (unsigned int)priv->status;
|
||||
+
|
||||
+ i_raw = i2c_r32(mis);
|
||||
+
|
||||
+ /* protocol interrupt */
|
||||
+ if (i_raw & I2C_RIS_I2C_P_INT_INTOCC) {
|
||||
+ i_pro = i2c_r32(p_irqss);
|
||||
+
|
||||
+ /* tx -> rx switch */
|
||||
+ if (i_pro & I2C_P_IRQSS_RX)
|
||||
+ priv->status |= FALCON_I2C_RX;
|
||||
+
|
||||
+ /* tx end */
|
||||
+ if (i_pro & I2C_P_IRQSS_TX_END)
|
||||
+ priv->status |= FALCON_I2C_TX_END;
|
||||
+
|
||||
+ /* not acknowledge */
|
||||
+ if (i_pro & I2C_P_IRQSS_NACK)
|
||||
+ priv->status |= FALCON_I2C_NACK;
|
||||
+
|
||||
+ /* arbitration lost */
|
||||
+ if (i_pro & I2C_P_IRQSS_AL)
|
||||
+ priv->status |= FALCON_I2C_ARB_LOST;
|
||||
+
|
||||
+ /* address match */
|
||||
+ if (i_pro & I2C_P_IRQSS_AM)
|
||||
+ priv->status |= FALCON_I2C_ADDR_MATCH;
|
||||
+
|
||||
+ i2c_w32(i_pro, p_irqsc);
|
||||
+ }
|
||||
+
|
||||
+ /* error interrupt */
|
||||
+ if (i_raw & I2C_RIS_I2C_ERR_INT_INTOCC) {
|
||||
+ i_err = i2c_r32(err_irqss);
|
||||
+
|
||||
+ /* tx fifo overflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_TXF_OFL)
|
||||
+ priv->status |= FALCON_I2C_TX_OFL;
|
||||
+
|
||||
+ /* tx fifo underflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_TXF_UFL)
|
||||
+ priv->status |= FALCON_I2C_TX_UFL;
|
||||
+
|
||||
+ /* rx fifo overflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_RXF_OFL)
|
||||
+ priv->status |= FALCON_I2C_RX_OFL;
|
||||
+
|
||||
+ /* rx fifo underflow */
|
||||
+ if (i_err & I2C_ERR_IRQSS_RXF_UFL)
|
||||
+ priv->status |= FALCON_I2C_RX_UFL;
|
||||
+
|
||||
+ i2c_w32(i_err, err_irqsc);
|
||||
+ }
|
||||
+
|
||||
+ /* burst request */
|
||||
+ if (i_raw & I2C_RIS_BREQ_INT_INTOCC) {
|
||||
+ i2c_w32_mask(I2C_IMSC_BREQ_INT_EN, 0, imsc);
|
||||
+ i2c_w32_mask(0, I2C_ICR_BREQ_INT_CLR, icr);
|
||||
+
|
||||
+ priv->status |= FALCON_I2C_BURST_REQ;
|
||||
+ }
|
||||
+
|
||||
+ /* last burst request */
|
||||
+ if (i_raw & I2C_RIS_LBREQ_INT_INTOCC) {
|
||||
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN, 0, imsc);
|
||||
+ i2c_w32_mask(0, I2C_ICR_LBREQ_INT_CLR, icr);
|
||||
+
|
||||
+ priv->status |= FALCON_I2C_BURST_REQ;
|
||||
+ }
|
||||
+
|
||||
+ if (old_status != (unsigned int)priv->status)
|
||||
+ complete(&priv->done);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_ready(struct falcon_i2c *priv)
|
||||
+{
|
||||
+ int timeout;
|
||||
+ u32 bus_stat;
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ for (timeout = 0; timeout < FALCON_I2C_READY_TIMEOUT; timeout++) {
|
||||
+ bus_stat = i2c_r32(bus_stat);
|
||||
+
|
||||
+ if (bus_stat & I2C_BUS_STAT_BS_SC) {
|
||||
+ cpu_relax();
|
||||
+ } else {
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ if (FALCON_I2C_ERROR(priv)) {
|
||||
+ ret = priv->status;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "bus ready wait error 0x%08lx\n", priv->status);
|
||||
+
|
||||
+ FALCON_I2C_ERROR_CLEAR(priv);
|
||||
+ } else {
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(priv->dev, "bus ready wait timeout\n");
|
||||
+
|
||||
+ return -ETIME;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_wait(struct falcon_i2c *priv, unsigned long status)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ unsigned long flags;
|
||||
+ unsigned int timeout;
|
||||
+
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ priv->status &= FALCON_I2C_BURST_REQ;
|
||||
+
|
||||
+ /* check if the event already occurred */
|
||||
+ if ((priv->status & status) == status) {
|
||||
+ priv->status &= ~status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* unmask burst interrupts */
|
||||
+ i2c_w32_mask(0, I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, imsc);
|
||||
+
|
||||
+ for (timeout = 0; timeout < FALCON_I2C_WAIT_TIMEOUT; timeout++) {
|
||||
+ /* wait for the data request */
|
||||
+ wait_for_completion_timeout(&priv->done, HZ / 10);
|
||||
+
|
||||
+ /* handle errors */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+
|
||||
+ if (FALCON_I2C_ERROR(priv)) {
|
||||
+ dev_dbg(priv->dev, "wait error 0x%08lx (waiting for 0x%08lx)\n",
|
||||
+ priv->status,
|
||||
+ status);
|
||||
+
|
||||
+ if (priv->status & FALCON_I2C_NACK)
|
||||
+ ret = -ENXIO;
|
||||
+ else
|
||||
+ ret = -EREMOTEIO;
|
||||
+
|
||||
+ FALCON_I2C_ERROR_CLEAR(priv);
|
||||
+ } else {
|
||||
+ if ((priv->status & status) == status) {
|
||||
+ priv->status &= ~status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(priv->dev, "wait timeout error 0x%08lx (waiting for 0x%08lx)\n",
|
||||
+ priv->status,
|
||||
+ status);
|
||||
+
|
||||
+ return -ETIME;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_tx(struct falcon_i2c *priv, int ten_bit, u16 addr,
|
||||
+ u8 *buf, int len)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s\n", __func__);
|
||||
+
|
||||
+ /* tell fifo the number of bytes we are going to send */
|
||||
+ i2c_w32(len + (ten_bit ? 2 : 1), tps_ctrl);
|
||||
+
|
||||
+ /* wait for the data request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* send slave address */
|
||||
+ if (ten_bit) {
|
||||
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
|
||||
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 0, txd);
|
||||
+ } else {
|
||||
+ i2c_w32((addr << 1) | 0, txd);
|
||||
+ }
|
||||
+
|
||||
+ /* fill fifo */
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ i2c_w32(buf[i], txd);
|
||||
+ }
|
||||
+
|
||||
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_rx(struct falcon_i2c *priv, int ten_bit, u16 addr,
|
||||
+ u8 *buf, int len)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s\n", __func__);
|
||||
+
|
||||
+ /* we need to transmit address only */
|
||||
+ i2c_w32(ten_bit ? 2 : 1, tps_ctrl);
|
||||
+
|
||||
+ /* set maximum received packet size */
|
||||
+ i2c_w32(len, mrps_ctrl);
|
||||
+
|
||||
+ /* wait for the data request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* write down the address */
|
||||
+ if (ten_bit) {
|
||||
+ i2c_w32(0x78 | ((addr >> 7) & 0x7), txd);
|
||||
+ i2c_w32(0x78 | ((addr & 0x7f) << 1) | 1, txd);
|
||||
+ } else {
|
||||
+ i2c_w32((addr << 1) | 1, txd);
|
||||
+ }
|
||||
+
|
||||
+ /* wait for the read request */
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_TX_END
|
||||
+#ifndef FALCON_FIX_ME
|
||||
+ | FALCON_I2C_ADDR_MATCH
|
||||
+#endif
|
||||
+ | FALCON_I2C_RX);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* read bytes */
|
||||
+ for (i = 0; i < len; i++) {
|
||||
+#ifdef FALCON_FIX_ME
|
||||
+ while (i2c_r32(rps_stat) == 0)
|
||||
+ cpu_relax();
|
||||
+#else
|
||||
+ ret = falcon_i2c_wait(priv, FALCON_I2C_BURST_REQ);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+#endif
|
||||
+
|
||||
+ buf[i] = i2c_r32(rxd);
|
||||
+ }
|
||||
+
|
||||
+#ifndef FALCON_FIX_ME
|
||||
+ /* wait for transmission end */
|
||||
+ return falcon_i2c_wait(priv, FALCON_I2C_TX_END);
|
||||
+#else
|
||||
+ return 0;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_xfer_msg(struct falcon_i2c *priv, struct i2c_msg *msg)
|
||||
+{
|
||||
+ int ret;
|
||||
+ int ten_bit;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ dev_dbg(priv->dev, "%s %u byte(s) %s 0x%02x\n",
|
||||
+ (msg->flags & I2C_M_RD) ? "read" : "write", msg->len,
|
||||
+ (msg->flags & I2C_M_RD) ? "from" : "to", msg->addr);
|
||||
+
|
||||
+ if (msg->flags & I2C_M_TEN)
|
||||
+ ten_bit = 1;
|
||||
+ else
|
||||
+ ten_bit = 0;
|
||||
+
|
||||
+ /* reconfigure bus if need to send message in different address mode */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ if (ten_bit != priv->ten_bit) {
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* reconfigure address */
|
||||
+ falcon_addr_configure(priv, ten_bit);
|
||||
+
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+
|
||||
+ priv->ten_bit = ten_bit;
|
||||
+ }
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* read/write actual message */
|
||||
+ if (msg->flags & I2C_M_RD)
|
||||
+ ret = falcon_i2c_rx(priv, ten_bit, msg->addr, msg->buf,
|
||||
+ msg->len);
|
||||
+ else
|
||||
+ ret = falcon_i2c_tx(priv, ten_bit, msg->addr, msg->buf,
|
||||
+ msg->len);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
|
||||
+ int num)
|
||||
+{
|
||||
+ int i;
|
||||
+ int ret;
|
||||
+ unsigned long flags;
|
||||
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
|
||||
+
|
||||
+ dev_dbg(priv->dev, "xfer %u messages\n", num);
|
||||
+
|
||||
+ /* transfer each message */
|
||||
+ for (i = 0; i < num; i++) {
|
||||
+#ifdef FALCON_FIX_ME
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+#endif
|
||||
+
|
||||
+ /* clear bus status */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ priv->status = 0;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ /* wait for the bus to become ready */
|
||||
+ ret = falcon_i2c_ready(priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* transfer message */
|
||||
+ ret = falcon_i2c_xfer_msg(priv, &msg[i]);
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* check for unhandled errors */
|
||||
+ spin_lock_irqsave(&priv->lock, flags);
|
||||
+ if (FALCON_I2C_ERROR(priv))
|
||||
+ ret = priv->status;
|
||||
+ spin_unlock_irqrestore(&priv->lock, flags);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ dev_warn(priv->dev, "message %u unhandled error 0x%x\n",
|
||||
+ i, ret);
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static u32 falcon_i2c_func(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL;
|
||||
+}
|
||||
+
|
||||
+static struct i2c_algorithm falcon_i2c_algorithm = {
|
||||
+ .master_xfer = falcon_i2c_xfer,
|
||||
+ .functionality = falcon_i2c_func,
|
||||
+};
|
||||
+
|
||||
+static int falcon_i2c_hw_init(struct i2c_adapter *adap)
|
||||
+{
|
||||
+ struct falcon_i2c *priv = i2c_get_adapdata(adap);
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* set normal operation clock divider */
|
||||
+ i2c_w32(1 << I2C_CLC_RMC_OFFSET, clc);
|
||||
+
|
||||
+ /* set frequency */
|
||||
+ if (priv->mode == FALCON_I2C_MODE_100) {
|
||||
+ dev_dbg(priv->dev, "set standard mode (100 kHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_high_cfg);
|
||||
+
|
||||
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (499 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_cfg);
|
||||
+ } else if (priv->mode == FALCON_I2C_MODE_400) {
|
||||
+ dev_dbg(priv->dev, "set fast mode (400 kHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_high_cfg);
|
||||
+
|
||||
+ i2c_w32((1 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (124 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_cfg);
|
||||
+ } else if (priv->mode == FALCON_I2C_MODE_3400) {
|
||||
+ dev_dbg(priv->dev, "set high mode (3.4 MHz)\n");
|
||||
+
|
||||
+ i2c_w32(0, fdiv_cfg);
|
||||
+
|
||||
+ /* TODO recalculate value for 100MHz input */
|
||||
+ i2c_w32((41 << I2C_FDIV_CFG_INC_OFFSET)
|
||||
+ | (152 << I2C_FDIV_CFG_DEC_OFFSET),
|
||||
+ fdiv_high_cfg);
|
||||
+ } else {
|
||||
+ dev_warn(priv->dev, "unknown mode\n");
|
||||
+
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* configure fifo */
|
||||
+ i2c_w32(I2C_FIFO_CFG_TXFC /* tx fifo as flow controller */
|
||||
+ | I2C_FIFO_CFG_RXFC /* rx fifo as flow controller */
|
||||
+ | I2C_FIFO_CFG_TXFA_TXFA2 /* tx fifo 4-byte aligned */
|
||||
+ | I2C_FIFO_CFG_RXFA_RXFA2 /* rx fifo 4-byte aligned */
|
||||
+ | I2C_FIFO_CFG_TXBS_TXBS0 /* tx fifo burst size is 1 word */
|
||||
+ | I2C_FIFO_CFG_RXBS_RXBS0, /* rx fifo burst size is 1 word */
|
||||
+ fifo_cfg);
|
||||
+
|
||||
+ /* configure address */
|
||||
+ falcon_addr_configure(priv, priv->ten_bit);
|
||||
+
|
||||
+ /* enable bus */
|
||||
+ i2c_w32_mask(0, I2C_RUN_CTRL_RUN_EN, run_ctrl);
|
||||
+
|
||||
+ /* mask burst interrupts */
|
||||
+ i2c_w32_mask(I2C_IMSC_LBREQ_INT_EN | I2C_IMSC_BREQ_INT_EN, 0, imsc);
|
||||
+
|
||||
+ /* enable interrupts */
|
||||
+ i2c_w32(I2C_IMSC_LBREQ_INT_EN
|
||||
+ | I2C_IMSC_BREQ_INT_EN
|
||||
+ | I2C_IMSC_I2C_P_INT_EN
|
||||
+ | I2C_IMSC_I2C_ERR_INT_EN,
|
||||
+ imsc);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int __devinit falcon_i2c_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ struct falcon_i2c *priv;
|
||||
+ struct i2c_adapter *adap;
|
||||
+ struct resource *mmres, *ioarea,
|
||||
+ *irqres_lb, *irqres_b, *irqres_err, *irqres_p;
|
||||
+ struct clk *clk;
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "probing\n");
|
||||
+
|
||||
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ irqres_lb = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
+ "i2c_lb");
|
||||
+ irqres_b = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_b");
|
||||
+ irqres_err = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
||||
+ "i2c_err");
|
||||
+ irqres_p = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "i2c_p");
|
||||
+
|
||||
+ if (!mmres || !irqres_lb || !irqres_b || !irqres_err || !irqres_p) {
|
||||
+ dev_err(&pdev->dev, "no resources\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ clk = clk_get(&pdev->dev, "fpi");
|
||||
+ if (IS_ERR(clk)) {
|
||||
+ dev_err(&pdev->dev, "failed to get fpi clk\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ if (clk_get_rate(clk) != 100000000) {
|
||||
+ dev_err(&pdev->dev, "input clock is not 100MHz\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ /* allocate private data */
|
||||
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
+ if (!priv) {
|
||||
+ dev_err(&pdev->dev, "can't allocate private data\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ adap = &priv->adap;
|
||||
+ i2c_set_adapdata(adap, priv);
|
||||
+ adap->owner = THIS_MODULE;
|
||||
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
|
||||
+ strlcpy(adap->name, DRV_NAME "-adapter", sizeof(adap->name));
|
||||
+ adap->algo = &falcon_i2c_algorithm;
|
||||
+
|
||||
+ priv->ten_bit = 0;
|
||||
+ priv->mode = FALCON_I2C_MODE_100;
|
||||
+ priv->clk = clk;
|
||||
+ priv->dev = &pdev->dev;
|
||||
+
|
||||
+ spin_lock_init(&priv->lock);
|
||||
+
|
||||
+ ioarea = request_mem_region(mmres->start, resource_size(mmres),
|
||||
+ pdev->name);
|
||||
+
|
||||
+ if (ioarea == NULL) {
|
||||
+ dev_err(&pdev->dev, "I2C region already claimed\n");
|
||||
+ ret = -ENXIO;
|
||||
+ goto err_free_priv;
|
||||
+ }
|
||||
+
|
||||
+ /* map memory */
|
||||
+ priv->membase = ioremap_nocache(mmres->start & ~KSEG1,
|
||||
+ resource_size(mmres));
|
||||
+ if (priv->membase == NULL) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto err_release_region;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_lb = irqres_lb->start;
|
||||
+ ret = request_irq(priv->irq_lb, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_lb->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get last burst IRQ %d\n", irqres_lb->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_unmap_mem;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_b = irqres_b->start;
|
||||
+ ret = request_irq(priv->irq_b, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_b->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get burst IRQ %d\n", irqres_b->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_lb_irq;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_err = irqres_err->start;
|
||||
+ ret = request_irq(priv->irq_err, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_err->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get error IRQ %d\n", irqres_err->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_b_irq;
|
||||
+ }
|
||||
+
|
||||
+ priv->irq_p = irqres_p->start;
|
||||
+ ret = request_irq(priv->irq_p, falcon_i2c_isr, IRQF_DISABLED,
|
||||
+ irqres_p->name, priv);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't get protocol IRQ %d\n", irqres_p->start);
|
||||
+ ret = -ENODEV;
|
||||
+ goto err_free_err_irq;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "mapped io-space to %p\n", priv->membase);
|
||||
+ dev_dbg(&pdev->dev, "use IRQs %d, %d, %d, %d\n", irqres_lb->start,
|
||||
+ irqres_b->start, irqres_err->start, irqres_p->start);
|
||||
+
|
||||
+ /* add our adapter to the i2c stack */
|
||||
+ ret = i2c_add_numbered_adapter(adap);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't register I2C adapter\n");
|
||||
+ goto err_free_p_irq;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+ i2c_set_adapdata(adap, priv);
|
||||
+
|
||||
+ /* print module version information */
|
||||
+ dev_dbg(&pdev->dev, "module id=%u revision=%u\n",
|
||||
+ (i2c_r32(id) & I2C_ID_ID_MASK) >> I2C_ID_ID_OFFSET,
|
||||
+ (i2c_r32(id) & I2C_ID_REV_MASK) >> I2C_ID_REV_OFFSET);
|
||||
+
|
||||
+ init_completion(&priv->done);
|
||||
+
|
||||
+ /* initialize HW */
|
||||
+ ret = falcon_i2c_hw_init(adap);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "can't configure adapter\n");
|
||||
+ goto err_remove_adapter;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_remove_adapter:
|
||||
+ i2c_del_adapter(adap);
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+
|
||||
+err_free_p_irq:
|
||||
+ free_irq(priv->irq_p, priv);
|
||||
+
|
||||
+err_free_err_irq:
|
||||
+ free_irq(priv->irq_err, priv);
|
||||
+
|
||||
+err_free_b_irq:
|
||||
+ free_irq(priv->irq_b, priv);
|
||||
+
|
||||
+err_free_lb_irq:
|
||||
+ free_irq(priv->irq_lb, priv);
|
||||
+
|
||||
+err_unmap_mem:
|
||||
+ iounmap(priv->membase);
|
||||
+
|
||||
+err_release_region:
|
||||
+ release_mem_region(mmres->start, resource_size(mmres));
|
||||
+
|
||||
+err_free_priv:
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit falcon_i2c_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct falcon_i2c *priv = platform_get_drvdata(pdev);
|
||||
+ struct resource *mmres;
|
||||
+
|
||||
+ /* disable bus */
|
||||
+ i2c_w32_mask(I2C_RUN_CTRL_RUN_EN, 0, run_ctrl);
|
||||
+
|
||||
+ /* remove driver */
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+ i2c_del_adapter(&priv->adap);
|
||||
+
|
||||
+ free_irq(priv->irq_lb, priv);
|
||||
+ free_irq(priv->irq_b, priv);
|
||||
+ free_irq(priv->irq_err, priv);
|
||||
+ free_irq(priv->irq_p, priv);
|
||||
+
|
||||
+ kfree(priv);
|
||||
+
|
||||
+ mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ release_mem_region(mmres->start, resource_size(mmres));
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "removed\n");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver falcon_i2c_driver = {
|
||||
+ .probe = falcon_i2c_probe,
|
||||
+ .remove = __devexit_p(falcon_i2c_remove),
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int __init falcon_i2c_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = platform_driver_register(&falcon_i2c_driver);
|
||||
+
|
||||
+ if (ret)
|
||||
+ printk(KERN_DEBUG DRV_NAME ": can't register platform driver");
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void __exit falcon_i2c_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&falcon_i2c_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(falcon_i2c_init);
|
||||
+module_exit(falcon_i2c_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Lantiq FALC(tm) ON - I2C bus adapter");
|
||||
+MODULE_ALIAS("platform:i2c_falcon");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,497 @@
|
|||
--- a/drivers/spi/Makefile
|
||||
+++ b/drivers/spi/Makefile
|
||||
@@ -55,6 +55,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_FALCON) += spi_falcon.o
|
||||
|
||||
# special build for s3c24xx spi driver with fiq support
|
||||
spi_s3c24xx_hw-y := spi_s3c24xx.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/spi/spi_falcon.c
|
||||
@@ -0,0 +1,471 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+
|
||||
+#include <lantiq.h> /* ebu_lock */
|
||||
+#include <falcon/ebu_reg.h>
|
||||
+#include <falcon/sys1_reg.h>
|
||||
+
|
||||
+#define DRV_NAME "falcon_spi"
|
||||
+
|
||||
+#define FALCON_SPI_XFER_BEGIN (1 << 0)
|
||||
+#define FALCON_SPI_XFER_END (1 << 1)
|
||||
+
|
||||
+/* mapping for access macros */
|
||||
+#define reg_r32(reg) __raw_readl(reg)
|
||||
+#define reg_w32(val, reg) __raw_writel(val, reg)
|
||||
+#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) \
|
||||
+ & ~(clear)) | (set), reg)
|
||||
+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx])
|
||||
+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx])
|
||||
+
|
||||
+#define ebu (priv->ebu_membase)
|
||||
+#define sys1 (priv->sys1_membase)
|
||||
+
|
||||
+struct falcon_spi {
|
||||
+ u32 sfcmd; /* for caching of opcode, direction, ... */
|
||||
+
|
||||
+ struct spi_master *master;
|
||||
+
|
||||
+ struct gpon_reg_ebu __iomem *ebu_membase;
|
||||
+ struct gpon_reg_sys1 __iomem *sys1_membase;
|
||||
+};
|
||||
+
|
||||
+int falcon_spi_xfer(struct spi_device *spi,
|
||||
+ struct spi_transfer *t,
|
||||
+ unsigned long flags)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ const u8 *txp = t->tx_buf;
|
||||
+ u8 *rxp = t->rx_buf;
|
||||
+ unsigned int bytelen = ((8 * t->len + 7) / 8);
|
||||
+ unsigned int len, alen, dumlen;
|
||||
+ u32 val;
|
||||
+ enum {
|
||||
+ state_init,
|
||||
+ state_command_prepare,
|
||||
+ state_write,
|
||||
+ state_read,
|
||||
+ state_disable_cs,
|
||||
+ state_end
|
||||
+ } state = state_init;
|
||||
+
|
||||
+ do {
|
||||
+ switch (state) {
|
||||
+ case state_init: /* detect phase of upper layer sequence */
|
||||
+ {
|
||||
+ /* initial write ? */
|
||||
+ if (flags & FALCON_SPI_XFER_BEGIN) {
|
||||
+ if (!txp) {
|
||||
+ dev_err(dev,
|
||||
+ "BEGIN without tx data!\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ /*
|
||||
+ * Prepare the parts of the sfcmd register,
|
||||
+ * which should not
|
||||
+ * change during a sequence!
|
||||
+ * Only exception are the length fields,
|
||||
+ * especially alen and dumlen.
|
||||
+ */
|
||||
+
|
||||
+ priv->sfcmd = ((spi->chip_select
|
||||
+ << SFCMD_CS_OFFSET)
|
||||
+ & SFCMD_CS_MASK);
|
||||
+ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ priv->sfcmd |= *txp;
|
||||
+ txp++;
|
||||
+ bytelen--;
|
||||
+ if (bytelen) {
|
||||
+ /* more data:
|
||||
+ * maybe address and/or dummy */
|
||||
+ state = state_command_prepare;
|
||||
+ break;
|
||||
+ } else {
|
||||
+ dev_dbg(dev, "write cmd %02X\n",
|
||||
+ priv->sfcmd & SFCMD_OPC_MASK);
|
||||
+ }
|
||||
+ }
|
||||
+ /* continued write ? */
|
||||
+ if (txp && bytelen) {
|
||||
+ state = state_write;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* read data? */
|
||||
+ if (rxp && bytelen) {
|
||||
+ state = state_read;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* end of sequence? */
|
||||
+ if (flags & FALCON_SPI_XFER_END)
|
||||
+ state = state_disable_cs;
|
||||
+ else
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_command_prepare: /* collect tx data for
|
||||
+ address and dummy phase */
|
||||
+ {
|
||||
+ /* txp is valid, already checked */
|
||||
+ val = 0;
|
||||
+ alen = 0;
|
||||
+ dumlen = 0;
|
||||
+ while (bytelen > 0) {
|
||||
+ if (alen < 3) {
|
||||
+ val = (val<<8)|(*txp++);
|
||||
+ alen++;
|
||||
+ } else if ((dumlen < 15) && (*txp == 0)) {
|
||||
+ /*
|
||||
+ * assume dummy bytes are set to 0
|
||||
+ * from upper layer
|
||||
+ */
|
||||
+ dumlen++;
|
||||
+ txp++;
|
||||
+ } else
|
||||
+ break;
|
||||
+ bytelen--;
|
||||
+ }
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK);
|
||||
+ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) |
|
||||
+ (dumlen << SFCMD_DUMLEN_OFFSET);
|
||||
+ if (alen > 0)
|
||||
+ ebu_w32(val, sfaddr);
|
||||
+
|
||||
+ dev_dbg(dev, "write cmd %02X, alen=%d "
|
||||
+ "(addr=%06X) dumlen=%d\n",
|
||||
+ priv->sfcmd & SFCMD_OPC_MASK,
|
||||
+ alen, val, dumlen);
|
||||
+
|
||||
+ if (bytelen > 0) {
|
||||
+ /* continue with write */
|
||||
+ state = state_write;
|
||||
+ } else if (flags & FALCON_SPI_XFER_END) {
|
||||
+ /* end of sequence? */
|
||||
+ state = state_disable_cs;
|
||||
+ } else {
|
||||
+ /* go to end and expect another
|
||||
+ * call (read or write) */
|
||||
+ state = state_end;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_write:
|
||||
+ {
|
||||
+ /* txp still valid */
|
||||
+ priv->sfcmd |= SFCMD_DIR_WRITE;
|
||||
+ len = 0;
|
||||
+ val = 0;
|
||||
+ do {
|
||||
+ if (bytelen--)
|
||||
+ val |= (*txp++) << (8 * len++);
|
||||
+ if ((flags & FALCON_SPI_XFER_END)
|
||||
+ && (bytelen == 0)) {
|
||||
+ priv->sfcmd &=
|
||||
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ }
|
||||
+ if ((len == 4) || (bytelen == 0)) {
|
||||
+ ebu_w32(val, sfdata);
|
||||
+ ebu_w32(priv->sfcmd
|
||||
+ | (len<<SFCMD_DLEN_OFFSET),
|
||||
+ sfcmd);
|
||||
+ len = 0;
|
||||
+ val = 0;
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
|
||||
+ | SFCMD_DUMLEN_MASK);
|
||||
+ }
|
||||
+ } while (bytelen);
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_read:
|
||||
+ {
|
||||
+ /* read data */
|
||||
+ priv->sfcmd &= ~SFCMD_DIR_WRITE;
|
||||
+ do {
|
||||
+ if ((flags & FALCON_SPI_XFER_END)
|
||||
+ && (bytelen <= 4)) {
|
||||
+ priv->sfcmd &=
|
||||
+ ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ }
|
||||
+ len = (bytelen > 4) ? 4 : bytelen;
|
||||
+ bytelen -= len;
|
||||
+ ebu_w32(priv->sfcmd
|
||||
+ |(len<<SFCMD_DLEN_OFFSET), sfcmd);
|
||||
+ priv->sfcmd &= ~(SFCMD_ALEN_MASK
|
||||
+ | SFCMD_DUMLEN_MASK);
|
||||
+ do {
|
||||
+ val = ebu_r32(sfstat);
|
||||
+ if (val & SFSTAT_CMD_ERR) {
|
||||
+ /* reset error status */
|
||||
+ dev_err(dev, "SFSTAT: CMD_ERR "
|
||||
+ "(%x)\n", val);
|
||||
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ } while (val & SFSTAT_CMD_PEND);
|
||||
+ val = ebu_r32(sfdata);
|
||||
+ do {
|
||||
+ *rxp = (val & 0xFF);
|
||||
+ rxp++;
|
||||
+ val >>= 8;
|
||||
+ len--;
|
||||
+ } while (len);
|
||||
+ } while (bytelen);
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_disable_cs:
|
||||
+ {
|
||||
+ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED;
|
||||
+ ebu_w32(priv->sfcmd | (0<<SFCMD_DLEN_OFFSET), sfcmd);
|
||||
+ val = ebu_r32(sfstat);
|
||||
+ if (val & SFSTAT_CMD_ERR) {
|
||||
+ /* reset error status */
|
||||
+ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val);
|
||||
+ ebu_w32(SFSTAT_CMD_ERR, sfstat);
|
||||
+ return -1;
|
||||
+ }
|
||||
+ state = state_end;
|
||||
+ break;
|
||||
+ }
|
||||
+ case state_end:
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (state != state_end);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_spi_setup(struct spi_device *spi)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ const u32 ebuclk = 100*1000*1000;
|
||||
+ unsigned int i;
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ dev_dbg(dev, "setup\n");
|
||||
+
|
||||
+ if (spi->master->bus_num > 0 || spi->chip_select > 0)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
||||
+
|
||||
+ if (ebuclk < spi->max_speed_hz) {
|
||||
+ /* set EBU clock to 100 MHz */
|
||||
+ sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, ebucc);
|
||||
+ i = 1; /* divider */
|
||||
+ } else {
|
||||
+ /* set EBU clock to 50 MHz */
|
||||
+ sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, ebucc);
|
||||
+
|
||||
+ /* search for suitable divider */
|
||||
+ for (i = 1; i < 7; i++) {
|
||||
+ if (ebuclk / i <= spi->max_speed_hz)
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* setup period of serial clock */
|
||||
+ ebu_w32_mask(SFTIME_SCKF_POS_MASK
|
||||
+ | SFTIME_SCKR_POS_MASK
|
||||
+ | SFTIME_SCK_PER_MASK,
|
||||
+ (i << SFTIME_SCKR_POS_OFFSET)
|
||||
+ | (i << (SFTIME_SCK_PER_OFFSET + 1)),
|
||||
+ sftime);
|
||||
+
|
||||
+ /* set some bits of unused_wd, to not trigger HOLD/WP
|
||||
+ * signals on non QUAD flashes */
|
||||
+ ebu_w32((SFIO_UNUSED_WD_MASK & (0x8|0x4)), sfio);
|
||||
+
|
||||
+ ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX,
|
||||
+ busrcon0);
|
||||
+ ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, buswcon0);
|
||||
+ /* set address wrap around to maximum for 24-bit addresses */
|
||||
+ ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, sfcon);
|
||||
+
|
||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int falcon_spi_transfer(struct spi_device *spi, struct spi_message *m)
|
||||
+{
|
||||
+ struct falcon_spi *priv = spi_master_get_devdata(spi->master);
|
||||
+ struct spi_transfer *t;
|
||||
+ unsigned long spi_flags;
|
||||
+ unsigned long flags;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ priv->sfcmd = 0;
|
||||
+ m->actual_length = 0;
|
||||
+
|
||||
+ spi_flags = FALCON_SPI_XFER_BEGIN;
|
||||
+ list_for_each_entry(t, &m->transfers, transfer_list) {
|
||||
+ if (list_is_last(&t->transfer_list, &m->transfers))
|
||||
+ spi_flags |= FALCON_SPI_XFER_END;
|
||||
+
|
||||
+ spin_lock_irqsave(&ebu_lock, flags);
|
||||
+ ret = falcon_spi_xfer(spi, t, spi_flags);
|
||||
+ spin_unlock_irqrestore(&ebu_lock, flags);
|
||||
+
|
||||
+ if (ret)
|
||||
+ break;
|
||||
+
|
||||
+ m->actual_length += t->len;
|
||||
+
|
||||
+ if (t->delay_usecs || t->cs_change)
|
||||
+ BUG();
|
||||
+
|
||||
+ spi_flags = 0;
|
||||
+ }
|
||||
+
|
||||
+ m->status = ret;
|
||||
+ m->complete(m->context);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void falcon_spi_cleanup(struct spi_device *spi)
|
||||
+{
|
||||
+ struct device *dev = &spi->dev;
|
||||
+
|
||||
+ dev_dbg(dev, "cleanup\n");
|
||||
+}
|
||||
+
|
||||
+static int __devinit falcon_spi_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct falcon_spi *priv;
|
||||
+ struct spi_master *master;
|
||||
+ struct resource *memres_ebu, *memres_sys1;
|
||||
+ int ret;
|
||||
+
|
||||
+ dev_dbg(dev, "probing\n");
|
||||
+
|
||||
+ memres_ebu = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ebu");
|
||||
+ memres_sys1 = platform_get_resource_byname(pdev, IORESOURCE_MEM,
|
||||
+ "sys1");
|
||||
+
|
||||
+ if (!memres_ebu || !memres_sys1) {
|
||||
+ dev_err(dev, "no resources\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ master = spi_alloc_master(&pdev->dev, sizeof(*priv));
|
||||
+ if (!master) {
|
||||
+ dev_err(dev, "no memory for spi_master\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ priv = spi_master_get_devdata(master);
|
||||
+
|
||||
+ priv->ebu_membase = ioremap_nocache(memres_ebu->start & ~KSEG1,
|
||||
+ resource_size(memres_ebu));
|
||||
+
|
||||
+ if (!priv->ebu_membase) {
|
||||
+ dev_err(dev, "can't map ebu memory\n");
|
||||
+
|
||||
+ ret = -ENOMEM;
|
||||
+ goto free_master;
|
||||
+ }
|
||||
+
|
||||
+ priv->sys1_membase = ioremap_nocache(memres_sys1->start & ~KSEG1,
|
||||
+ resource_size(memres_sys1));
|
||||
+
|
||||
+ if (!priv->sys1_membase) {
|
||||
+ dev_err(dev, "can't map sys1 memory\n");
|
||||
+
|
||||
+ ret = -ENOMEM;
|
||||
+ goto unmap_ebu;
|
||||
+ }
|
||||
+
|
||||
+ priv->master = master;
|
||||
+
|
||||
+ master->mode_bits = SPI_MODE_3;
|
||||
+ master->num_chipselect = 1;
|
||||
+ master->bus_num = 0;
|
||||
+
|
||||
+ master->setup = falcon_spi_setup;
|
||||
+ master->transfer = falcon_spi_transfer;
|
||||
+ master->cleanup = falcon_spi_cleanup;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, priv);
|
||||
+
|
||||
+ ret = spi_register_master(master);
|
||||
+ if (ret)
|
||||
+ goto unmap_sys1;
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+unmap_sys1:
|
||||
+ iounmap(priv->sys1_membase);
|
||||
+
|
||||
+unmap_ebu:
|
||||
+ iounmap(priv->ebu_membase);
|
||||
+
|
||||
+free_master:
|
||||
+ spi_master_put(master);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int __devexit falcon_spi_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct falcon_spi *priv = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ dev_dbg(dev, "removed\n");
|
||||
+
|
||||
+ spi_unregister_master(priv->master);
|
||||
+
|
||||
+ iounmap(priv->sys1_membase);
|
||||
+ iounmap(priv->ebu_membase);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver falcon_spi_driver = {
|
||||
+ .probe = falcon_spi_probe,
|
||||
+ .remove = __devexit_p(falcon_spi_remove),
|
||||
+ .driver = {
|
||||
+ .name = DRV_NAME,
|
||||
+ .owner = THIS_MODULE
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static int __init falcon_spi_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&falcon_spi_driver);
|
||||
+}
|
||||
+
|
||||
+static void __exit falcon_spi_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&falcon_spi_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(falcon_spi_init);
|
||||
+module_exit(falcon_spi_exit);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver");
|
||||
--- a/drivers/spi/Kconfig
|
||||
+++ b/drivers/spi/Kconfig
|
||||
@@ -210,6 +210,10 @@ config SPI_MPC52xx
|
||||
This drivers supports the MPC52xx SPI controller in master SPI
|
||||
mode.
|
||||
|
||||
+config SPI_FALCON
|
||||
+ tristate "Falcon SPI controller support"
|
||||
+ depends on SOC_FALCON
|
||||
+
|
||||
config SPI_MPC52xx_PSC
|
||||
tristate "Freescale MPC52xx PSC SPI controller"
|
||||
depends on PPC_MPC52xx && EXPERIMENTAL
|
|
@ -0,0 +1,193 @@
|
|||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -2,3 +2,4 @@ obj-y := clk-falcon.o devices.o gpio.o p
|
||||
obj-y += softdog_vpe.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += addon-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.c
|
||||
@@ -0,0 +1,160 @@
|
||||
+/*
|
||||
+ * EASY98000 CPLD LED driver
|
||||
+ *
|
||||
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
|
||||
+ *
|
||||
+ * 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/version.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+#include "dev-leds-easy98000-cpld.h"
|
||||
+
|
||||
+const char *led_name[8] = {
|
||||
+ "ge0_act",
|
||||
+ "ge0_link",
|
||||
+ "ge1_act",
|
||||
+ "ge1_link",
|
||||
+ "fe2_act",
|
||||
+ "fe2_link",
|
||||
+ "fe3_act",
|
||||
+ "fe3_link"
|
||||
+};
|
||||
+
|
||||
+#define cpld_base7 ((u16 *)(KSEG1 | 0x17c0000c))
|
||||
+#define cpld_base8 ((u16 *)(KSEG1 | 0x17c00012))
|
||||
+
|
||||
+#define ltq_r16(reg) __raw_readw(reg)
|
||||
+#define ltq_w16(val, reg) __raw_writew(val, reg)
|
||||
+
|
||||
+struct cpld_led_dev {
|
||||
+ struct led_classdev cdev;
|
||||
+ u8 mask;
|
||||
+ u16 *base;
|
||||
+};
|
||||
+
|
||||
+struct cpld_led_drvdata {
|
||||
+ struct cpld_led_dev *led_devs;
|
||||
+ int num_leds;
|
||||
+};
|
||||
+
|
||||
+void led_set(u8 mask, u16 *base)
|
||||
+{
|
||||
+ ltq_w16(ltq_r16(base) | mask, base);
|
||||
+}
|
||||
+
|
||||
+void led_clear(u8 mask, u16 *base)
|
||||
+{
|
||||
+ ltq_w16(ltq_r16(base) & (~mask), base);
|
||||
+}
|
||||
+
|
||||
+void led_blink_clear(u8 mask, u16 *base)
|
||||
+{
|
||||
+ led_clear(mask, base);
|
||||
+}
|
||||
+
|
||||
+static void led_brightness(struct led_classdev *led_cdev,
|
||||
+ enum led_brightness value)
|
||||
+{
|
||||
+ struct cpld_led_dev *led_dev =
|
||||
+ container_of(led_cdev, struct cpld_led_dev, cdev);
|
||||
+
|
||||
+ if (value)
|
||||
+ led_set(led_dev->mask, led_dev->base);
|
||||
+ else
|
||||
+ led_clear(led_dev->mask, led_dev->base);
|
||||
+}
|
||||
+
|
||||
+static int led_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ char name[32];
|
||||
+ struct cpld_led_drvdata *drvdata;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ drvdata = kzalloc(sizeof(struct cpld_led_drvdata) +
|
||||
+ sizeof(struct cpld_led_dev) * MAX_LED,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!drvdata)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ drvdata->led_devs = (struct cpld_led_dev *) &drvdata[1];
|
||||
+
|
||||
+ for (i = 0; i < MAX_LED; i++) {
|
||||
+ struct cpld_led_dev *led_dev = &drvdata->led_devs[i];
|
||||
+ led_dev->cdev.brightness_set = led_brightness;
|
||||
+ led_dev->cdev.default_trigger = NULL;
|
||||
+ led_dev->mask = 1 << (i % 8);
|
||||
+ if(i < 8) {
|
||||
+ sprintf(name, "easy98000-cpld:%s", led_name[i]);
|
||||
+ led_dev->base = cpld_base8;
|
||||
+ } else {
|
||||
+ sprintf(name, "easy98000-cpld:red:%d", i-8);
|
||||
+ led_dev->base = cpld_base7;
|
||||
+ }
|
||||
+ led_dev->cdev.name = name;
|
||||
+ ret = led_classdev_register(&pdev->dev, &led_dev->cdev);
|
||||
+ if (ret)
|
||||
+ goto err;
|
||||
+ }
|
||||
+ platform_set_drvdata(pdev, drvdata);
|
||||
+ return 0;
|
||||
+
|
||||
+err:
|
||||
+ printk("led_probe: 3\n");
|
||||
+ for (i = i - 1; i >= 0; i--)
|
||||
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
|
||||
+
|
||||
+ kfree(drvdata);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int led_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ int i;
|
||||
+ struct cpld_led_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
+ for (i = 0; i < MAX_LED; i++)
|
||||
+ led_classdev_unregister(&drvdata->led_devs[i].cdev);
|
||||
+ kfree(drvdata);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver led_driver = {
|
||||
+ .probe = led_probe,
|
||||
+ .remove = __devexit_p(led_remove),
|
||||
+ .driver = {
|
||||
+ .name = LED_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+int __init easy98000_cpld_led_init(void)
|
||||
+{
|
||||
+ pr_info(LED_DESC ", Version " LED_VERSION
|
||||
+ " (c) Copyright 2011, Lantiq Deutschland GmbH\n");
|
||||
+ return platform_driver_register(&led_driver);
|
||||
+}
|
||||
+
|
||||
+void __exit easy98000_cpld_led_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&led_driver);
|
||||
+}
|
||||
+
|
||||
+module_init(easy98000_cpld_led_init);
|
||||
+module_exit(easy98000_cpld_led_exit);
|
||||
+
|
||||
+MODULE_DESCRIPTION(LED_NAME);
|
||||
+MODULE_DESCRIPTION(LED_DESC);
|
||||
+MODULE_AUTHOR("Ralph Hempel <ralph.hempel@lantiq.com>");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/dev-leds-easy98000-cpld.h
|
||||
@@ -0,0 +1,20 @@
|
||||
+/*
|
||||
+ * EASY98000 CPLD LED driver
|
||||
+ *
|
||||
+ * Copyright (C) 2010 Ralph Hempel <ralph.hempel@lantiq.com>
|
||||
+ *
|
||||
+ * 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 _INCLUDE_EASY98000_CPLD_LED_H_
|
||||
+#define _INCLUDE_EASY98000_CPLD_LED_H_
|
||||
+
|
||||
+#define LED_NAME "easy98000_cpld_led"
|
||||
+#define LED_DESC "EASY98000 LED driver"
|
||||
+#define LED_VERSION "1.0.0"
|
||||
+
|
||||
+#define MAX_LED 16
|
||||
+
|
||||
+#endif /* _INCLUDE_EASY98000_CPLD_LED_H_ */
|
|
@ -0,0 +1,136 @@
|
|||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/mach-easy98020.c
|
||||
@@ -0,0 +1,113 @@
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio_buttons.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+#include <linux/spi/flash.h>
|
||||
+#include "../machtypes.h"
|
||||
+
|
||||
+#include "devices.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+#define EASY98020_GPIO_LED_0 9
|
||||
+#define EASY98020_GPIO_LED_1 10
|
||||
+#define EASY98020_GPIO_LED_2 11
|
||||
+#define EASY98020_GPIO_LED_3 12
|
||||
+#define EASY98020_GPIO_LED_GE0_ACT 110
|
||||
+#define EASY98020_GPIO_LED_GE0_LINK 109
|
||||
+#define EASY98020_GPIO_LED_GE1_ACT 106
|
||||
+#define EASY98020_GPIO_LED_GE1_LINK 105
|
||||
+
|
||||
+extern unsigned char ltq_ethaddr[6];
|
||||
+
|
||||
+static struct mtd_partition easy98020_spi_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x40000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x40000,
|
||||
+ .size = 0x40000, /* 2 sectors for redundant env. */
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x80000,
|
||||
+ .size = 0xF80000, /* map only 16 MiB */
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct flash_platform_data easy98020_spi_flash_platform_data = {
|
||||
+ .name = "sflash",
|
||||
+ .parts = easy98020_spi_partitions,
|
||||
+ .nr_parts = ARRAY_SIZE(easy98020_spi_partitions)
|
||||
+};
|
||||
+
|
||||
+static struct spi_board_info easy98020_spi_flash_data __initdata = {
|
||||
+ .modalias = "m25p80",
|
||||
+ .bus_num = 0,
|
||||
+ .chip_select = 0,
|
||||
+ .max_speed_hz = 10 * 1000 * 1000,
|
||||
+ .mode = SPI_MODE_3,
|
||||
+ .platform_data = &easy98020_spi_flash_platform_data
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led easy98020_leds_gpio[] __initdata = {
|
||||
+ {
|
||||
+ .name = "easy98020:green:0",
|
||||
+ .gpio = EASY98020_GPIO_LED_0,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:1",
|
||||
+ .gpio = EASY98020_GPIO_LED_1,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:2",
|
||||
+ .gpio = EASY98020_GPIO_LED_2,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:green:3",
|
||||
+ .gpio = EASY98020_GPIO_LED_3,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:ge0_act",
|
||||
+ .gpio = EASY98020_GPIO_LED_GE0_ACT,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:ge0_link",
|
||||
+ .gpio = EASY98020_GPIO_LED_GE0_LINK,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:ge1_act",
|
||||
+ .gpio = EASY98020_GPIO_LED_GE1_ACT,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "easy98020:ge1_link",
|
||||
+ .gpio = EASY98020_GPIO_LED_GE1_LINK,
|
||||
+ .active_low = 0,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static void __init easy98020_init(void)
|
||||
+{
|
||||
+ falcon_register_asc(0);
|
||||
+ falcon_register_gpio();
|
||||
+ falcon_register_wdt();
|
||||
+ falcon_register_i2c();
|
||||
+ falcon_register_spi_flash(&easy98020_spi_flash_data);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(easy98020_leds_gpio),
|
||||
+ easy98020_leds_gpio);
|
||||
+ falcon_register_crypto();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_EASY98020,
|
||||
+ "EASY98020",
|
||||
+ "EASY98020 Eval Board",
|
||||
+ easy98020_init);
|
||||
--- a/arch/mips/lantiq/falcon/Kconfig
|
||||
+++ b/arch/mips/lantiq/falcon/Kconfig
|
||||
@@ -6,6 +6,10 @@
|
||||
bool "Easy98000"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_EASY98020
|
||||
+ bool "Easy98020"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -3,3 +3,4 @@
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += addon-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
|
|
@ -0,0 +1,132 @@
|
|||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/falcon/mach-95C3AM1.c
|
||||
@@ -0,0 +1,99 @@
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/i2c-gpio.h>
|
||||
+#include "../machtypes.h"
|
||||
+
|
||||
+#include "devices.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+#define BOARD_95C3AM1_GPIO_LED_0 10
|
||||
+#define BOARD_95C3AM1_GPIO_LED_1 11
|
||||
+#define BOARD_95C3AM1_GPIO_LED_2 12
|
||||
+#define BOARD_95C3AM1_GPIO_LED_3 13
|
||||
+
|
||||
+extern unsigned char ltq_ethaddr[6];
|
||||
+
|
||||
+static struct mtd_partition board_95C3AM1_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x40000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x40000,
|
||||
+ .size = 0x40000, /* 2 sectors for redundant env. */
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x80000,
|
||||
+ .size = 0xF80000, /* map only 16 MiB */
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct flash_platform_data board_95C3AM1_flash_platform_data = {
|
||||
+ .name = "sflash",
|
||||
+ .parts = board_95C3AM1_partitions,
|
||||
+ .nr_parts = ARRAY_SIZE(board_95C3AM1_partitions)
|
||||
+};
|
||||
+
|
||||
+static struct spi_board_info board_95C3AM1_flash_data __initdata = {
|
||||
+ .modalias = "m25p80",
|
||||
+ .bus_num = 0,
|
||||
+ .chip_select = 0,
|
||||
+ .max_speed_hz = 10 * 1000 * 1000,
|
||||
+ .mode = SPI_MODE_3,
|
||||
+ .platform_data = &board_95C3AM1_flash_platform_data
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led board_95C3AM1_leds_gpio[] __initdata = {
|
||||
+ {
|
||||
+ .name = "power",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_0,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "optical",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_1,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "lan",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_2,
|
||||
+ .active_low = 0,
|
||||
+ }, {
|
||||
+ .name = "update",
|
||||
+ .gpio = BOARD_95C3AM1_GPIO_LED_3,
|
||||
+ .active_low = 0,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static struct i2c_gpio_platform_data board_95C3AM1_i2c_gpio_data = {
|
||||
+ .sda_pin = 107,
|
||||
+ .scl_pin = 108,
|
||||
+};
|
||||
+
|
||||
+static struct platform_device board_95C3AM1_i2c_gpio_device = {
|
||||
+ .name = "i2c-gpio",
|
||||
+ .id = 0,
|
||||
+ .dev = {
|
||||
+ .platform_data = &board_95C3AM1_i2c_gpio_data,
|
||||
+ }
|
||||
+};
|
||||
+
|
||||
+static void __init board_95C3AM1_init(void)
|
||||
+{
|
||||
+ falcon_register_asc(0);
|
||||
+ falcon_register_gpio();
|
||||
+ falcon_register_wdt();
|
||||
+ falcon_register_i2c();
|
||||
+ falcon_register_spi_flash(&board_95C3AM1_flash_data);
|
||||
+ platform_device_register(&board_95C3AM1_i2c_gpio_device);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(board_95C3AM1_leds_gpio),
|
||||
+ board_95C3AM1_leds_gpio);
|
||||
+ falcon_register_crypto();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_95C3AM1,
|
||||
+ "95C3AM1",
|
||||
+ "95C3AM1 Board",
|
||||
+ board_95C3AM1_init);
|
||||
--- a/arch/mips/lantiq/falcon/Kconfig
|
||||
+++ b/arch/mips/lantiq/falcon/Kconfig
|
||||
@@ -10,6 +10,10 @@
|
||||
bool "Easy98020"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_95C3AM1
|
||||
+ bool "95C3AM1"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/falcon/Makefile
|
||||
+++ b/arch/mips/lantiq/falcon/Makefile
|
||||
@@ -4,3 +4,4 @@
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += mach-easy98000.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98000) += dev-leds-easy98000-cpld.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY98020) += mach-easy98020.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_95C3AM1) += mach-95C3AM1.o
|
||||
--- a/arch/mips/lantiq/machtypes.h
|
||||
+++ b/arch/mips/lantiq/machtypes.h
|
||||
@@ -21,6 +21,7 @@
|
||||
LANTIQ_MACH_EASY98000SF, /* Falcon Eval Board, Serial Flash */
|
||||
LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
|
||||
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
|
||||
+ LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,117 @@
|
|||
--- a/drivers/net/dm9000.c
|
||||
+++ b/drivers/net/dm9000.c
|
||||
@@ -19,6 +19,7 @@
|
||||
* Sascha Hauer <s.hauer@pengutronix.de>
|
||||
*/
|
||||
|
||||
+#define DEBUG
|
||||
#include <linux/module.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/netdevice.h>
|
||||
@@ -125,6 +126,8 @@
|
||||
struct delayed_work phy_poll;
|
||||
struct net_device *ndev;
|
||||
|
||||
+ struct delayed_work irq_poll; /* for use in irq polling mode */
|
||||
+
|
||||
spinlock_t lock;
|
||||
|
||||
struct mii_if_info mii;
|
||||
@@ -824,6 +827,8 @@
|
||||
netif_stop_queue(dev);
|
||||
dm9000_reset(db);
|
||||
dm9000_init_dm9000(dev);
|
||||
+ dm9000_reset(db);
|
||||
+ dm9000_init_dm9000(dev);
|
||||
/* We can accept TX packets again */
|
||||
dev->trans_start = jiffies; /* prevent tx timeout */
|
||||
netif_wake_queue(dev);
|
||||
@@ -895,6 +900,12 @@
|
||||
/* free this SKB */
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
+ /* directly poll afterwards */
|
||||
+ if (dev->irq == -1) {
|
||||
+ cancel_delayed_work(&db->irq_poll);
|
||||
+ schedule_delayed_work(&db->irq_poll, 1);
|
||||
+ }
|
||||
+
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
@@ -1136,6 +1147,18 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
+static void dm9000_poll_irq(struct work_struct *w)
|
||||
+{
|
||||
+ struct delayed_work *dw = to_delayed_work(w);
|
||||
+ board_info_t *db = container_of(dw, board_info_t, irq_poll);
|
||||
+ struct net_device *ndev = db->ndev;
|
||||
+
|
||||
+ dm9000_interrupt(0, ndev);
|
||||
+
|
||||
+ if (netif_running(ndev))
|
||||
+ schedule_delayed_work(&db->irq_poll, HZ /100);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Open the interface.
|
||||
* The interface is opened whenever "ifconfig" actives it.
|
||||
@@ -1149,14 +1172,15 @@
|
||||
if (netif_msg_ifup(db))
|
||||
dev_dbg(db->dev, "enabling %s\n", dev->name);
|
||||
|
||||
- /* If there is no IRQ type specified, default to something that
|
||||
- * may work, and tell the user that this is a problem */
|
||||
+ if (dev->irq != -1) {
|
||||
+ /* If there is no IRQ type specified, default to something that
|
||||
+ * may work, and tell the user that this is a problem */
|
||||
|
||||
- if (irqflags == IRQF_TRIGGER_NONE)
|
||||
- dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
|
||||
-
|
||||
- irqflags |= IRQF_SHARED;
|
||||
+ if (irqflags == IRQF_TRIGGER_NONE)
|
||||
+ dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
|
||||
|
||||
+ irqflags |= IRQF_SHARED;
|
||||
+ }
|
||||
/* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
|
||||
iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
|
||||
mdelay(1); /* delay needs by DM9000B */
|
||||
@@ -1165,8 +1189,14 @@
|
||||
dm9000_reset(db);
|
||||
dm9000_init_dm9000(dev);
|
||||
|
||||
- if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
|
||||
- return -EAGAIN;
|
||||
+ /* testing: init a second time */
|
||||
+ dm9000_reset(db);
|
||||
+ dm9000_init_dm9000(dev);
|
||||
+
|
||||
+ if (dev->irq != -1) {
|
||||
+ if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
|
||||
/* Init driver variable */
|
||||
db->dbug_cnt = 0;
|
||||
@@ -1174,6 +1204,9 @@
|
||||
mii_check_media(&db->mii, netif_msg_link(db), 1);
|
||||
netif_start_queue(dev);
|
||||
|
||||
+ if (dev->irq == -1)
|
||||
+ schedule_delayed_work(&db->irq_poll, HZ / 100);
|
||||
+
|
||||
dm9000_schedule_poll(db);
|
||||
|
||||
return 0;
|
||||
@@ -1371,6 +1404,7 @@
|
||||
mutex_init(&db->addr_lock);
|
||||
|
||||
INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
|
||||
+ INIT_DELAYED_WORK(&db->irq_poll, dm9000_poll_irq);
|
||||
|
||||
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
|
@ -0,0 +1,163 @@
|
|||
--- a/arch/mips/lantiq/irq.c
|
||||
+++ b/arch/mips/lantiq/irq.c
|
||||
@@ -51,6 +51,7 @@
|
||||
#define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y))
|
||||
#define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x))
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static unsigned short ltq_eiu_irq[MAX_EIU] = {
|
||||
LTQ_EIU_IR0,
|
||||
LTQ_EIU_IR1,
|
||||
@@ -59,6 +60,7 @@
|
||||
LTQ_EIU_IR4,
|
||||
LTQ_EIU_IR5,
|
||||
};
|
||||
+#endif
|
||||
|
||||
static struct resource ltq_icu_resource = {
|
||||
.name = "icu",
|
||||
@@ -67,15 +69,19 @@
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static struct resource ltq_eiu_resource = {
|
||||
.name = "eiu",
|
||||
.start = LTQ_EIU_BASE_ADDR,
|
||||
.end = LTQ_EIU_BASE_ADDR + LTQ_ICU_SIZE - 1,
|
||||
.flags = IORESOURCE_MEM,
|
||||
};
|
||||
+#endif
|
||||
|
||||
static void __iomem *ltq_icu_membase;
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static void __iomem *ltq_eiu_membase;
|
||||
+#endif
|
||||
|
||||
void ltq_disable_irq(struct irq_data *d)
|
||||
{
|
||||
@@ -120,6 +126,7 @@
|
||||
ltq_icu_w32(ltq_icu_r32(ier) | (1 << irq_nr), ier);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static unsigned int ltq_startup_eiu_irq(struct irq_data *d)
|
||||
{
|
||||
int i;
|
||||
@@ -159,6 +166,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
|
||||
static struct irq_chip ltq_irq_type = {
|
||||
"icu",
|
||||
@@ -170,6 +178,7 @@
|
||||
.irq_mask_ack = ltq_mask_and_ack_irq,
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static struct irq_chip ltq_eiu_type = {
|
||||
"eiu",
|
||||
.irq_startup = ltq_startup_eiu_irq,
|
||||
@@ -181,6 +190,7 @@
|
||||
.irq_mask = ltq_disable_irq,
|
||||
.irq_mask_ack = ltq_mask_and_ack_irq,
|
||||
};
|
||||
+#endif
|
||||
|
||||
static void ltq_hw_irqdispatch(int module)
|
||||
{
|
||||
@@ -196,10 +206,12 @@
|
||||
irq = __fls(irq);
|
||||
do_IRQ((int)irq + INT_NUM_IM0_IRL0 + (INT_NUM_IM_OFFSET * module));
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
/* if this is a EBU irq, we need to ack it or get a deadlock */
|
||||
if ((irq == LTQ_ICU_EBU_IRQ) && (module == 0))
|
||||
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10,
|
||||
LTQ_EBU_PCC_ISTAT);
|
||||
+#endif
|
||||
}
|
||||
|
||||
#define DEFINE_HWx_IRQDISPATCH(x) \
|
||||
@@ -262,6 +274,7 @@
|
||||
if (!ltq_icu_membase)
|
||||
panic("Failed to remap icu memory\n");
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
if (insert_resource(&iomem_resource, <q_eiu_resource) < 0)
|
||||
panic("Failed to insert eiu memory\n");
|
||||
|
||||
@@ -273,6 +286,7 @@
|
||||
resource_size(<q_eiu_resource));
|
||||
if (!ltq_eiu_membase)
|
||||
panic("Failed to remap eiu memory\n");
|
||||
+#endif
|
||||
|
||||
/* make sure all irqs are turned off by default */
|
||||
for (i = 0; i < 5; i++)
|
||||
@@ -298,6 +312,7 @@
|
||||
|
||||
for (i = INT_NUM_IRQ0;
|
||||
i <= (INT_NUM_IRQ0 + (5 * INT_NUM_IM_OFFSET)); i++)
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
if ((i == LTQ_EIU_IR0) || (i == LTQ_EIU_IR1) ||
|
||||
(i == LTQ_EIU_IR2))
|
||||
irq_set_chip_and_handler(i, <q_eiu_type,
|
||||
@@ -308,6 +323,7 @@
|
||||
irq_set_chip_and_handler(i, <q_eiu_type,
|
||||
handle_level_irq);
|
||||
else
|
||||
+#endif
|
||||
irq_set_chip_and_handler(i, <q_irq_type,
|
||||
handle_level_irq);
|
||||
|
||||
--- a/arch/mips/lantiq/clk.c
|
||||
+++ b/arch/mips/lantiq/clk.c
|
||||
@@ -46,6 +46,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
static struct resource ltq_cgu_resource = {
|
||||
.name = "cgu",
|
||||
.start = LTQ_CGU_BASE_ADDR,
|
||||
@@ -55,6 +56,7 @@
|
||||
|
||||
/* remapped clock register range */
|
||||
void __iomem *ltq_cgu_membase;
|
||||
+#endif
|
||||
|
||||
void clk_init(void)
|
||||
{
|
||||
@@ -120,6 +122,7 @@
|
||||
{
|
||||
struct clk *clk;
|
||||
|
||||
+#ifdef CONFIG_SOC_XWAY
|
||||
if (insert_resource(&iomem_resource, <q_cgu_resource) < 0)
|
||||
panic("Failed to insert cgu memory\n");
|
||||
|
||||
@@ -133,6 +136,7 @@
|
||||
pr_err("Failed to remap cgu memory\n");
|
||||
unreachable();
|
||||
}
|
||||
+#endif
|
||||
clk = clk_get(0, "cpu");
|
||||
mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
|
||||
write_c0_compare(read_c0_count());
|
||||
--- a/arch/mips/lantiq/early_printk.c
|
||||
+++ b/arch/mips/lantiq/early_printk.c
|
||||
@@ -13,7 +13,11 @@
|
||||
#include <lantiq_soc.h>
|
||||
|
||||
/* no ioremap possible at this early stage, lets use KSEG1 instead */
|
||||
+#ifdef CONFIG_SOC_FALCON
|
||||
+#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC0_BASE_ADDR)
|
||||
+#else
|
||||
#define LTQ_ASC_BASE KSEG1ADDR(LTQ_ASC1_BASE_ADDR)
|
||||
+#endif
|
||||
#define ASC_BUF 1024
|
||||
#define LTQ_ASC_FSTAT ((u32 *)(LTQ_ASC_BASE + 0x0048))
|
||||
#define LTQ_ASC_TBUF ((u32 *)(LTQ_ASC_BASE + 0x0020))
|
|
@ -0,0 +1,43 @@
|
|||
--- /dev/null
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
|
||||
@@ -0,0 +1,40 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ *
|
||||
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
+ */
|
||||
+
|
||||
+#ifndef _LTQ_FALCON_H__
|
||||
+#define _LTQ_FALCON_H__
|
||||
+
|
||||
+#ifdef CONFIG_SOC_FALCON
|
||||
+
|
||||
+#include <lantiq.h>
|
||||
+
|
||||
+/* Chip IDs */
|
||||
+#define SOC_ID_FALCON 0x01B8
|
||||
+
|
||||
+/* SoC Types */
|
||||
+#define SOC_TYPE_FALCON 0x01
|
||||
+
|
||||
+/* ASC0/1 - serial port */
|
||||
+#define LTQ_ASC0_BASE_ADDR 0x1E100C00
|
||||
+#define LTQ_ASC1_BASE_ADDR 0x1E100B00
|
||||
+#define LTQ_ASC_SIZE 0x100
|
||||
+
|
||||
+#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
|
||||
+#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
|
||||
+#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
|
||||
+
|
||||
+/* ICU - interrupt control unit */
|
||||
+#define LTQ_ICU_BASE_ADDR 0x1F880200
|
||||
+#define LTQ_ICU_SIZE 0x100
|
||||
+
|
||||
+/* WDT */
|
||||
+#define LTQ_WDT_BASE_ADDR 0x1F8803F0
|
||||
+#define LTQ_WDT_SIZE 0x10
|
||||
+
|
||||
+#endif /* CONFIG_SOC_FALCON */
|
||||
+#endif /* _LTQ_XWAY_H__ */
|
|
@ -0,0 +1,17 @@
|
|||
--- a/drivers/net/lantiq_etop.c
|
||||
+++ b/drivers/net/lantiq_etop.c
|
||||
@@ -155,8 +155,12 @@
|
||||
|
||||
skb_put(skb, len);
|
||||
skb->dev = ch->netdev;
|
||||
- skb->protocol = eth_type_trans(skb, ch->netdev);
|
||||
- netif_receive_skb(skb);
|
||||
+ if (priv->phydev && priv->phydev->netif_receive_skb) {
|
||||
+ priv->phydev->netif_receive_skb(skb);
|
||||
+ } else {
|
||||
+ skb->protocol = eth_type_trans(skb, ch->netdev);
|
||||
+ netif_receive_skb(skb);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int
|
|
@ -0,0 +1,116 @@
|
|||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -57,6 +57,10 @@ config MTD_ROOTFS_SPLIT
|
||||
depends on MTD_PARTITIONS
|
||||
default y
|
||||
|
||||
+config MTD_UIMAGE_SPLIT
|
||||
+ bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
|
||||
+ default y
|
||||
+
|
||||
config MTD_REDBOOT_PARTS
|
||||
tristate "RedBoot partition table parsing"
|
||||
---help---
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -860,6 +860,82 @@ static int refresh_rootfs_split(struct m
|
||||
}
|
||||
#endif /* CONFIG_MTD_ROOTFS_SPLIT */
|
||||
|
||||
+
|
||||
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
|
||||
+static unsigned long find_uimage_size(struct mtd_info *mtd,
|
||||
+ unsigned long offset)
|
||||
+{
|
||||
+#define UBOOT_MAGIC 0x56190527
|
||||
+ unsigned long magic = 0;
|
||||
+ unsigned long temp;
|
||||
+ size_t len;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&magic);
|
||||
+ if (ret || len != sizeof(magic))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (le32_to_cpu(magic) != UBOOT_MAGIC)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset + 12, 4, &len, (void *)&temp);
|
||||
+ if (ret || len != sizeof(temp))
|
||||
+ return 0;
|
||||
+
|
||||
+ return temp + 0x40;
|
||||
+}
|
||||
+
|
||||
+static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
|
||||
+{
|
||||
+ unsigned long temp;
|
||||
+ size_t len;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mtd->read(mtd, offset, 4, &len, (void *)&temp);
|
||||
+ if (ret || len != sizeof(temp))
|
||||
+ return 0;
|
||||
+
|
||||
+ return le32_to_cpu(temp) == SQUASHFS_MAGIC;
|
||||
+}
|
||||
+
|
||||
+static int split_uimage(struct mtd_info *mtd,
|
||||
+ const struct mtd_partition *part)
|
||||
+{
|
||||
+ static struct mtd_partition split_partitions[] = {
|
||||
+ {
|
||||
+ .name = "kernel",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ }, {
|
||||
+ .name = "rootfs",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x0,
|
||||
+ },
|
||||
+ };
|
||||
+
|
||||
+ split_partitions[0].size = find_uimage_size(mtd, part->offset);
|
||||
+ if (!split_partitions[0].size) {
|
||||
+ printk(KERN_NOTICE "no uImage found in linux partition\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!detect_squashfs_partition(mtd,
|
||||
+ part->offset
|
||||
+ + split_partitions[0].size)) {
|
||||
+ split_partitions[0].size &= ~(mtd->erasesize - 1);
|
||||
+ split_partitions[0].size += mtd->erasesize;
|
||||
+ }
|
||||
+
|
||||
+ split_partitions[0].offset = part->offset;
|
||||
+ split_partitions[1].offset = part->offset + split_partitions[0].size;
|
||||
+ split_partitions[1].size = part->size - split_partitions[0].size;
|
||||
+
|
||||
+ add_mtd_partitions(mtd, split_partitions, 2);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* This function, given a master MTD object and a partition table, creates
|
||||
* and registers slave MTD objects which are bound to the master according to
|
||||
@@ -893,6 +969,17 @@ int add_mtd_partitions(struct mtd_info *
|
||||
|
||||
add_mtd_device(&slave->mtd);
|
||||
|
||||
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
|
||||
+ if (!strcmp(parts[i].name, "linux")) {
|
||||
+ ret = split_uimage(master, &parts[i]);
|
||||
+
|
||||
+ if (ret) {
|
||||
+ printk(KERN_WARNING
|
||||
+ "Can't split linux partition\n");
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
if (!strcmp(parts[i].name, "rootfs")) {
|
||||
#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
|
||||
if (ROOT_DEV == 0) {
|
|
@ -0,0 +1,42 @@
|
|||
--- a/arch/mips/mm/cache.c
|
||||
+++ b/arch/mips/mm/cache.c
|
||||
@@ -52,6 +52,8 @@ void (*_dma_cache_wback)(unsigned long s
|
||||
void (*_dma_cache_inv)(unsigned long start, unsigned long size);
|
||||
|
||||
EXPORT_SYMBOL(_dma_cache_wback_inv);
|
||||
+EXPORT_SYMBOL(_dma_cache_wback);
|
||||
+EXPORT_SYMBOL(_dma_cache_inv);
|
||||
|
||||
#endif /* CONFIG_DMA_NONCOHERENT */
|
||||
|
||||
--- a/net/atm/proc.c
|
||||
+++ b/net/atm/proc.c
|
||||
@@ -154,7 +154,7 @@ static void *vcc_seq_next(struct seq_fil
|
||||
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
|
||||
{
|
||||
static const char *const class_name[] = {
|
||||
- "off", "UBR", "CBR", "VBR", "ABR"};
|
||||
+ "off","UBR","CBR","NTR-VBR","ABR","ANY","RT-VBR","UBR+","GFR"};
|
||||
static const char *const aal_name[] = {
|
||||
"---", "1", "2", "3/4", /* 0- 3 */
|
||||
"???", "5", "???", "???", /* 4- 7 */
|
||||
--- a/net/atm/common.c
|
||||
+++ b/net/atm/common.c
|
||||
@@ -62,11 +62,17 @@ static void vcc_remove_socket(struct soc
|
||||
write_unlock_irq(&vcc_sklist_lock);
|
||||
}
|
||||
|
||||
+struct sk_buff* (*ifx_atm_alloc_tx)(struct atm_vcc *, unsigned int) = NULL;
|
||||
+EXPORT_SYMBOL(ifx_atm_alloc_tx);
|
||||
+
|
||||
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
|
||||
+ if (ifx_atm_alloc_tx != NULL)
|
||||
+ return ifx_atm_alloc_tx(vcc, size);
|
||||
+
|
||||
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
|
||||
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
|
||||
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
|
|
@ -0,0 +1,45 @@
|
|||
--- a/arch/mips/lantiq/prom.c
|
||||
+++ b/arch/mips/lantiq/prom.c
|
||||
@@ -39,6 +39,34 @@ void prom_free_prom_memory(void)
|
||||
{
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
|
||||
+extern char __image_cmdline[];
|
||||
+
|
||||
+static void __init
|
||||
+prom_init_image_cmdline(void)
|
||||
+{
|
||||
+ char *p = __image_cmdline;
|
||||
+ int replace = 0;
|
||||
+
|
||||
+ if (*p == '-') {
|
||||
+ replace = 1;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ if (*p == '\0')
|
||||
+ return;
|
||||
+
|
||||
+ if (replace) {
|
||||
+ strlcpy(arcs_cmdline, p, sizeof(arcs_cmdline));
|
||||
+ } else {
|
||||
+ strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
|
||||
+ strlcat(arcs_cmdline, p, sizeof(arcs_cmdline));
|
||||
+ }
|
||||
+}
|
||||
+#else
|
||||
+static void __init prom_init_image_cmdline(void) { return; }
|
||||
+#endif
|
||||
+
|
||||
static void __init prom_init_cmdline(void)
|
||||
{
|
||||
int argc = fw_arg0;
|
||||
@@ -53,6 +81,7 @@ static void __init prom_init_cmdline(voi
|
||||
strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline));
|
||||
}
|
||||
}
|
||||
+ prom_init_image_cmdline();
|
||||
}
|
||||
|
||||
void __init prom_init(void)
|
|
@ -0,0 +1,348 @@
|
|||
--- /dev/null
|
||||
+++ b/include/linux/udp_redirect.h
|
||||
@@ -0,0 +1,57 @@
|
||||
+#ifndef _UDP_REDIRECT_H
|
||||
+#define _UDP_REDIRECT_H
|
||||
+
|
||||
+/******************************************************************************
|
||||
+
|
||||
+ Copyright (c) 2006
|
||||
+ Infineon Technologies AG
|
||||
+ Am Campeon 1-12; 81726 Munich, Germany
|
||||
+
|
||||
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
|
||||
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
|
||||
+ SOFTWARE IS FREE OF CHARGE.
|
||||
+
|
||||
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
|
||||
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
|
||||
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
|
||||
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
|
||||
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
|
||||
+ PROPERTY INFRINGEMENT.
|
||||
+
|
||||
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
|
||||
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
|
||||
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
+ DEALINGS IN THE SOFTWARE.
|
||||
+
|
||||
+******************************************************************************/
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Includes */
|
||||
+/* ============================= */
|
||||
+#ifndef _LINUX_TYPES_H
|
||||
+#include <linux/types.h>
|
||||
+#endif
|
||||
+
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Definitions */
|
||||
+/* ============================= */
|
||||
+#define UDP_REDIRECT_MAGIC (void*)0x55445052L
|
||||
+
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Global variable declaration */
|
||||
+/* ============================= */
|
||||
+extern int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb);
|
||||
+extern int (*udpredirect_getfrag_fn)(void *p, char * to,
|
||||
+ int offset, int fraglen, int odd,
|
||||
+ struct sk_buff *skb);
|
||||
+/* ============================= */
|
||||
+/* Global function declaration */
|
||||
+/* ============================= */
|
||||
+
|
||||
+extern int udpredirect_getfrag(void *p, char * to, int offset,
|
||||
+ int fraglen, int odd, struct sk_buff *skb);
|
||||
+#endif
|
||||
--- /dev/null
|
||||
+++ b/net/ipv4/udp_redirect_symb.c
|
||||
@@ -0,0 +1,186 @@
|
||||
+/******************************************************************************
|
||||
+
|
||||
+ Copyright (c) 2006
|
||||
+ Infineon Technologies AG
|
||||
+ Am Campeon 1-12; 81726 Munich, Germany
|
||||
+
|
||||
+ THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
|
||||
+ WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
|
||||
+ SOFTWARE IS FREE OF CHARGE.
|
||||
+
|
||||
+ THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
|
||||
+ ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
|
||||
+ WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
|
||||
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
|
||||
+ OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
|
||||
+ PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
|
||||
+ PROPERTY INFRINGEMENT.
|
||||
+
|
||||
+ EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
|
||||
+ FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
|
||||
+ OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
+ DEALINGS IN THE SOFTWARE.
|
||||
+
|
||||
+******************************************************************************/
|
||||
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
||||
+/* ============================= */
|
||||
+/* Includes */
|
||||
+/* ============================= */
|
||||
+#include <net/checksum.h>
|
||||
+#include <net/udp.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+#include <linux/udp_redirect.h>
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Global variable definition */
|
||||
+/* ============================= */
|
||||
+int (*udpredirect_getfrag_fn) (void *p, char * to, int offset,
|
||||
+ int fraglen, int odd, struct sk_buff *skb) = NULL;
|
||||
+int (*udp_do_redirect_fn)(struct sock *sk, struct sk_buff *skb) = NULL;
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Local type definitions */
|
||||
+/* ============================= */
|
||||
+struct udpfakehdr
|
||||
+{
|
||||
+ struct udphdr uh;
|
||||
+ u32 saddr;
|
||||
+ u32 daddr;
|
||||
+ struct iovec *iov;
|
||||
+ u32 wcheck;
|
||||
+};
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Local function declaration */
|
||||
+/* ============================= */
|
||||
+static int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata,
|
||||
+ struct iovec *iov, int offset, unsigned int len, __wsum *csump);
|
||||
+
|
||||
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
|
||||
+ int len);
|
||||
+
|
||||
+/* ============================= */
|
||||
+/* Global function definition */
|
||||
+/* ============================= */
|
||||
+
|
||||
+/*
|
||||
+ Copy of udp_getfrag() from udp.c
|
||||
+ This function exists because no copy_from_user() is needed for udpredirect.
|
||||
+*/
|
||||
+
|
||||
+int
|
||||
+udpredirect_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct iovec *iov = from;
|
||||
+
|
||||
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
+ if (udpredirect_memcpy_fromiovecend(to, iov, offset, len) < 0)
|
||||
+ return -EFAULT;
|
||||
+ } else {
|
||||
+ __wsum csum = 0;
|
||||
+ if (udpredirect_csum_partial_copy_fromiovecend(to, iov, offset, len, &csum) < 0)
|
||||
+ return -EFAULT;
|
||||
+ skb->csum = csum_block_add(skb->csum, csum, odd);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int udpredirect_memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset,
|
||||
+ int len)
|
||||
+{
|
||||
+ /* Skip over the finished iovecs */
|
||||
+ while (offset >= iov->iov_len) {
|
||||
+ offset -= iov->iov_len;
|
||||
+ iov++;
|
||||
+ }
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ u8 __user *base = iov->iov_base + offset;
|
||||
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
||||
+
|
||||
+ offset = 0;
|
||||
+ memcpy(kdata, base, copy);
|
||||
+ len -= copy;
|
||||
+ kdata += copy;
|
||||
+ iov++;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ Copy of csum_partial_copy_fromiovecend() from iovec.c
|
||||
+ This function exists because no copy_from_user() is needed for udpredirect.
|
||||
+*/
|
||||
+
|
||||
+int udpredirect_csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
|
||||
+ int offset, unsigned int len, __wsum *csump)
|
||||
+{
|
||||
+ __wsum csum = *csump;
|
||||
+ int partial_cnt = 0, err = 0;
|
||||
+
|
||||
+ /* Skip over the finished iovecs */
|
||||
+ while (offset >= iov->iov_len) {
|
||||
+ offset -= iov->iov_len;
|
||||
+ iov++;
|
||||
+ }
|
||||
+
|
||||
+ while (len > 0) {
|
||||
+ u8 __user *base = iov->iov_base + offset;
|
||||
+ int copy = min_t(unsigned int, len, iov->iov_len - offset);
|
||||
+
|
||||
+ offset = 0;
|
||||
+
|
||||
+ /* There is a remnant from previous iov. */
|
||||
+ if (partial_cnt) {
|
||||
+ int par_len = 4 - partial_cnt;
|
||||
+
|
||||
+ /* iov component is too short ... */
|
||||
+ if (par_len > copy) {
|
||||
+ memcpy(kdata, base, copy);
|
||||
+ kdata += copy;
|
||||
+ base += copy;
|
||||
+ partial_cnt += copy;
|
||||
+ len -= copy;
|
||||
+ iov++;
|
||||
+ if (len)
|
||||
+ continue;
|
||||
+ *csump = csum_partial(kdata - partial_cnt,
|
||||
+ partial_cnt, csum);
|
||||
+ goto out;
|
||||
+ }
|
||||
+ memcpy(kdata, base, par_len);
|
||||
+ csum = csum_partial(kdata - partial_cnt, 4, csum);
|
||||
+ kdata += par_len;
|
||||
+ base += par_len;
|
||||
+ copy -= par_len;
|
||||
+ len -= par_len;
|
||||
+ partial_cnt = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (len > copy) {
|
||||
+ partial_cnt = copy % 4;
|
||||
+ if (partial_cnt) {
|
||||
+ copy -= partial_cnt;
|
||||
+ memcpy(kdata + copy, base + copy, partial_cnt);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (copy) {
|
||||
+ csum = csum_partial_copy_nocheck(base, kdata, copy, csum);
|
||||
+ }
|
||||
+ len -= copy + partial_cnt;
|
||||
+ kdata += copy + partial_cnt;
|
||||
+ iov++;
|
||||
+ }
|
||||
+ *csump = csum;
|
||||
+out:
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+EXPORT_SYMBOL(udpredirect_getfrag);
|
||||
+EXPORT_SYMBOL(udp_do_redirect_fn);
|
||||
+EXPORT_SYMBOL(udpredirect_getfrag_fn);
|
||||
+#endif /* CONFIG_IFX_UDP_REDIRECT* */
|
||||
--- a/net/ipv4/Makefile
|
||||
+++ b/net/ipv4/Makefile
|
||||
@@ -14,6 +14,9 @@ obj-y := route.o inetpeer.o protocol
|
||||
inet_fragment.o
|
||||
|
||||
obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
|
||||
+ifneq ($(CONFIG_IFX_UDP_REDIRECT),)
|
||||
+obj-$(CONFIG_IFX_UDP_REDIRECT) += udp_redirect_symb.o
|
||||
+endif
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
|
||||
obj-$(CONFIG_IP_MROUTE) += ipmr.o
|
||||
--- a/net/ipv4/udp.c
|
||||
+++ b/net/ipv4/udp.c
|
||||
@@ -107,6 +107,10 @@
|
||||
#include <net/xfrm.h>
|
||||
#include "udp_impl.h"
|
||||
|
||||
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
||||
+#include <linux/udp_redirect.h>
|
||||
+#endif
|
||||
+
|
||||
struct udp_table udp_table __read_mostly;
|
||||
EXPORT_SYMBOL(udp_table);
|
||||
|
||||
@@ -802,7 +806,7 @@ int udp_sendmsg(struct kiocb *iocb, stru
|
||||
u8 tos;
|
||||
int err, is_udplite = IS_UDPLITE(sk);
|
||||
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
|
||||
- int (*getfrag)(void *, char *, int, int, int, struct sk_buff *);
|
||||
+ int (*getfrag)(void *, char *, int, int, int, struct sk_buff *) = NULL;
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (len > 0xFFFF)
|
||||
@@ -818,7 +822,13 @@ int udp_sendmsg(struct kiocb *iocb, stru
|
||||
ipc.opt = NULL;
|
||||
ipc.tx_flags = 0;
|
||||
|
||||
- getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
||||
+/* UDPREDIRECT */
|
||||
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
||||
+ if(udpredirect_getfrag_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
|
||||
+ getfrag = udpredirect_getfrag_fn;
|
||||
+ else
|
||||
+#endif /* IFX_UDP_REDIRECT */
|
||||
+ getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag;
|
||||
|
||||
if (up->pending) {
|
||||
/*
|
||||
@@ -1608,6 +1618,7 @@ int __udp4_lib_rcv(struct sk_buff *skb,
|
||||
struct rtable *rt = skb_rtable(skb);
|
||||
__be32 saddr, daddr;
|
||||
struct net *net = dev_net(skb->dev);
|
||||
+ int ret = 0;
|
||||
|
||||
/*
|
||||
* Validate the packet.
|
||||
@@ -1640,7 +1651,16 @@ int __udp4_lib_rcv(struct sk_buff *skb,
|
||||
sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
|
||||
|
||||
if (sk != NULL) {
|
||||
- int ret = udp_queue_rcv_skb(sk, skb);
|
||||
+ /* UDPREDIRECT */
|
||||
+#if defined(CONFIG_IFX_UDP_REDIRECT) || defined(CONFIG_IFX_UDP_REDIRECT_MODULE)
|
||||
+ if(udp_do_redirect_fn && sk->sk_user_data == UDP_REDIRECT_MAGIC)
|
||||
+ {
|
||||
+ udp_do_redirect_fn(sk,skb);
|
||||
+ kfree_skb(skb);
|
||||
+ return(0);
|
||||
+ }
|
||||
+#endif
|
||||
+ ret = udp_queue_rcv_skb(sk, skb);
|
||||
sock_put(sk);
|
||||
|
||||
/* a return value > 0 means to resubmit the input, but
|
||||
@@ -1937,7 +1957,7 @@ struct proto udp_prot = {
|
||||
.clear_sk = sk_prot_clear_portaddr_nulls,
|
||||
};
|
||||
EXPORT_SYMBOL(udp_prot);
|
||||
-
|
||||
+EXPORT_SYMBOL(udp_rcv);
|
||||
/* ------------------------------------------------------------------------ */
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -72,6 +72,12 @@ config INET
|
||||
|
||||
Short answer: say Y.
|
||||
|
||||
+config IFX_UDP_REDIRECT
|
||||
+ bool "IFX Kernel Packet Interface for UDP redirection"
|
||||
+ help
|
||||
+ You can say Y here if you want to use hooks from kernel for
|
||||
+ UDP redirection.
|
||||
+
|
||||
if INET
|
||||
source "net/ipv4/Kconfig"
|
||||
source "net/ipv6/Kconfig"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,301 @@
|
|||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -1878,6 +1878,28 @@ config IFX_VPE_EXT
|
||||
help
|
||||
IFX included extensions in APRP
|
||||
|
||||
+config IFX_VPE_CACHE_SPLIT
|
||||
+ bool "IFX Cache Split Ways"
|
||||
+ depends on IFX_VPE_EXT
|
||||
+ help
|
||||
+ IFX extension for reserving (splitting) cache ways among VPEs. You must
|
||||
+ give kernel command line arguments vpe_icache_shared=0 or
|
||||
+ vpe_dcache_shared=0 to enable splitting of icache or dcache
|
||||
+ respectively. Then you can specify which cache ways should be
|
||||
+ assigned to which VPE. There are total 8 cache ways, 4 each
|
||||
+ for dcache and icache: dcache_way0, dcache_way1,dcache_way2,
|
||||
+ dcache_way3 and icache_way0,icache_way1, icache_way2,icache_way3.
|
||||
+
|
||||
+ For example, if you specify vpe_icache_shared=0 and icache_way2=1,
|
||||
+ then the 3rd icache way will be assigned to VPE0 and denied in VPE1.
|
||||
+
|
||||
+ For icache, software is required to make at least one cache way available
|
||||
+ for a VPE at all times i.e., one can't assign all the icache ways to one
|
||||
+ VPE.
|
||||
+
|
||||
+ By default, vpe_dcache_shared and vpe_icache_shared are set to 1
|
||||
+ (i.e., both icache and dcache are shared among VPEs)
|
||||
+
|
||||
config PERFCTRS
|
||||
bool "34K Performance counters"
|
||||
depends on MIPS_MT && PROC_FS
|
||||
--- a/arch/mips/kernel/vpe.c
|
||||
+++ b/arch/mips/kernel/vpe.c
|
||||
@@ -128,6 +128,13 @@ __setup("vpe1_wdog_timeout=", wdog_timeo
|
||||
EXPORT_SYMBOL(vpe1_wdog_timeout);
|
||||
|
||||
#endif
|
||||
+
|
||||
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
|
||||
+extern int vpe_icache_shared,vpe_dcache_shared;
|
||||
+extern int icache_way0,icache_way1,icache_way2,icache_way3;
|
||||
+extern int dcache_way0,dcache_way1,dcache_way2,dcache_way3;
|
||||
+#endif
|
||||
+
|
||||
/* grab the likely amount of memory we will need. */
|
||||
#ifdef CONFIG_MIPS_VPE_LOADER_TOM
|
||||
#define P_SIZE (2 * 1024 * 1024)
|
||||
@@ -866,6 +873,65 @@ static int vpe_run(struct vpe * v)
|
||||
/* enable this VPE */
|
||||
write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
|
||||
|
||||
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
|
||||
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ) {
|
||||
+
|
||||
+ /* PCP bit must be 1 to split the cache */
|
||||
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
|
||||
+
|
||||
+ if ( !vpe_icache_shared ){
|
||||
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_ICS);
|
||||
+
|
||||
+ /*
|
||||
+ * If any cache way is 1, then that way is denied
|
||||
+ * in VPE1. Otherwise assign that way to VPE1.
|
||||
+ */
|
||||
+ if (!icache_way0)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX0 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX0 );
|
||||
+ if (!icache_way1)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX1 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX1 );
|
||||
+ if (!icache_way2)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX2 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX2 );
|
||||
+ if (!icache_way3)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_IWX3 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_IWX3 );
|
||||
+ }
|
||||
+
|
||||
+ if ( !vpe_dcache_shared ) {
|
||||
+ write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0()) & ~VPECONF0_DCS);
|
||||
+
|
||||
+ /*
|
||||
+ * If any cache way is 1, then that way is denied
|
||||
+ * in VPE1. Otherwise assign that way to VPE1.
|
||||
+ */
|
||||
+ if (!dcache_way0)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX0 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX0 );
|
||||
+ if (!dcache_way1)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX1 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX1 );
|
||||
+ if (!dcache_way2)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX2 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX2 );
|
||||
+ if (!dcache_way3)
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() | VPEOPT_DWX3 );
|
||||
+ else
|
||||
+ write_vpe_c0_vpeopt(read_vpe_c0_vpeopt() & ~VPEOPT_DWX3 );
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
|
||||
+
|
||||
/* clear out any left overs from a previous program */
|
||||
write_vpe_c0_status(0);
|
||||
write_vpe_c0_cause(0);
|
||||
--- a/arch/mips/mm/c-r4k.c
|
||||
+++ b/arch/mips/mm/c-r4k.c
|
||||
@@ -1345,6 +1345,106 @@ static int __init setcoherentio(char *st
|
||||
__setup("coherentio", setcoherentio);
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT /* Code for splitting the cache ways among VPEs. */
|
||||
+
|
||||
+#include <asm/mipsmtregs.h>
|
||||
+
|
||||
+/*
|
||||
+ * By default, vpe_icache_shared and vpe_dcache_shared
|
||||
+ * values are 1 i.e., both icache and dcache are shared
|
||||
+ * among the VPEs.
|
||||
+ */
|
||||
+
|
||||
+int vpe_icache_shared = 1;
|
||||
+static int __init vpe_icache_shared_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &vpe_icache_shared);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("vpe_icache_shared=", vpe_icache_shared_val);
|
||||
+EXPORT_SYMBOL(vpe_icache_shared);
|
||||
+
|
||||
+int vpe_dcache_shared = 1;
|
||||
+static int __init vpe_dcache_shared_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &vpe_dcache_shared);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("vpe_dcache_shared=", vpe_dcache_shared_val);
|
||||
+EXPORT_SYMBOL(vpe_dcache_shared);
|
||||
+
|
||||
+/*
|
||||
+ * Software is required to make atleast one icache
|
||||
+ * way available for a VPE at all times i.e., one
|
||||
+ * can't assign all the icache ways to one VPE.
|
||||
+ */
|
||||
+
|
||||
+int icache_way0 = 0;
|
||||
+static int __init icache_way0_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &icache_way0);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("icache_way0=", icache_way0_val);
|
||||
+
|
||||
+int icache_way1 = 0;
|
||||
+static int __init icache_way1_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &icache_way1);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("icache_way1=", icache_way1_val);
|
||||
+
|
||||
+int icache_way2 = 0;
|
||||
+static int __init icache_way2_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &icache_way2);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("icache_way2=", icache_way2_val);
|
||||
+
|
||||
+int icache_way3 = 0;
|
||||
+static int __init icache_way3_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &icache_way3);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("icache_way3=", icache_way3_val);
|
||||
+
|
||||
+int dcache_way0 = 0;
|
||||
+static int __init dcache_way0_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &dcache_way0);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("dcache_way0=", dcache_way0_val);
|
||||
+
|
||||
+int dcache_way1 = 0;
|
||||
+static int __init dcache_way1_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &dcache_way1);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("dcache_way1=", dcache_way1_val);
|
||||
+
|
||||
+int dcache_way2 = 0;
|
||||
+static int __init dcache_way2_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &dcache_way2);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("dcache_way2=", dcache_way2_val);
|
||||
+
|
||||
+int dcache_way3 = 0;
|
||||
+static int __init dcache_way3_val(char *str)
|
||||
+{
|
||||
+ get_option(&str, &dcache_way3);
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("dcache_way3=", dcache_way3_val);
|
||||
+
|
||||
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
|
||||
+
|
||||
void __cpuinit r4k_cache_init(void)
|
||||
{
|
||||
extern void build_clear_page(void);
|
||||
@@ -1364,6 +1464,78 @@ void __cpuinit r4k_cache_init(void)
|
||||
break;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_IFX_VPE_CACHE_SPLIT
|
||||
+ /*
|
||||
+ * We split the cache ways appropriately among the VPEs
|
||||
+ * based on cache ways values we received as command line
|
||||
+ * arguments
|
||||
+ */
|
||||
+ if ( (!vpe_icache_shared) || (!vpe_dcache_shared) ){
|
||||
+
|
||||
+ /* PCP bit must be 1 to split the cache */
|
||||
+ if(read_c0_mvpconf0() & MVPCONF0_PCP) {
|
||||
+
|
||||
+ /* Set CPA bit which enables us to modify VPEOpt register */
|
||||
+ write_c0_mvpcontrol((read_c0_mvpcontrol()) | MVPCONTROL_CPA);
|
||||
+
|
||||
+ if ( !vpe_icache_shared ){
|
||||
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_ICS);
|
||||
+ /*
|
||||
+ * If any cache way is 1, then that way is denied
|
||||
+ * in VPE0. Otherwise assign that way to VPE0.
|
||||
+ */
|
||||
+ printk(KERN_DEBUG "icache is split\n");
|
||||
+ printk(KERN_DEBUG "icache_way0=%d icache_way1=%d icache_way2=%d icache_way3=%d\n",
|
||||
+ icache_way0, icache_way1,icache_way2, icache_way3);
|
||||
+ if (icache_way0)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX0 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX0 );
|
||||
+ if (icache_way1)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX1 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX1 );
|
||||
+ if (icache_way2)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX2 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX2 );
|
||||
+ if (icache_way3)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_IWX3 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_IWX3 );
|
||||
+ }
|
||||
+
|
||||
+ if ( !vpe_dcache_shared ) {
|
||||
+ /*
|
||||
+ * If any cache way is 1, then that way is denied
|
||||
+ * in VPE0. Otherwise assign that way to VPE0.
|
||||
+ */
|
||||
+ printk(KERN_DEBUG "dcache is split\n");
|
||||
+ printk(KERN_DEBUG "dcache_way0=%d dcache_way1=%d dcache_way2=%d dcache_way3=%d\n",
|
||||
+ dcache_way0, dcache_way1, dcache_way2, dcache_way3);
|
||||
+ write_c0_vpeconf0((read_c0_vpeconf0()) & ~VPECONF0_DCS);
|
||||
+ if (dcache_way0)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX0 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX0 );
|
||||
+ if (dcache_way1)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX1 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX1 );
|
||||
+ if (dcache_way2)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX2 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX2 );
|
||||
+ if (dcache_way3)
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() | VPEOPT_DWX3 );
|
||||
+ else
|
||||
+ write_c0_vpeopt(read_c0_vpeopt() & ~VPEOPT_DWX3 );
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+#endif /* endif CONFIG_IFX_VPE_CACHE_SPLIT */
|
||||
+
|
||||
probe_pcache();
|
||||
setup_scache();
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -1,3 +1,5 @@
|
||||
+
|
||||
+
|
||||
/*
|
||||
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
|
||||
*
|
|
@ -0,0 +1,36 @@
|
|||
From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
||||
Date: Thu, 3 Mar 2011 17:15:58 +0000 (+0100)
|
||||
Subject: MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver
|
||||
X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=3d21b04682ae8eb1c1965aba39d1796e8c5ad84b;hp=06b420500fe98e37662837e78d8e51aead8aea81
|
||||
|
||||
MIPS: lantiq: Add platform data for Lantiq SoC SPI controller driver
|
||||
|
||||
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
||||
---
|
||||
|
||||
--- a/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_platform.h
|
||||
@@ -50,4 +50,13 @@ struct ltq_eth_data {
|
||||
int mii_mode;
|
||||
};
|
||||
|
||||
+
|
||||
+struct ltq_spi_platform_data {
|
||||
+ u16 num_chipselect;
|
||||
+};
|
||||
+
|
||||
+struct ltq_spi_controller_data {
|
||||
+ unsigned gpio;
|
||||
+};
|
||||
+
|
||||
#endif
|
||||
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
||||
@@ -75,6 +75,7 @@
|
||||
|
||||
#define PMU_DMA 0x0020
|
||||
#define PMU_USB 0x8041
|
||||
+#define PMU_SPI 0x0100
|
||||
#define PMU_LED 0x0800
|
||||
#define PMU_GPT 0x1000
|
||||
#define PMU_PPE 0x2000
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,89 @@
|
|||
From: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
||||
Date: Thu, 3 Mar 2011 20:42:26 +0000 (+0100)
|
||||
Subject: MIPS: lantiq: Add device register helper for SPI controller and devices
|
||||
X-Git-Url: http://nbd.name/gitweb.cgi?p=lantiq.git;a=commitdiff_plain;h=b35b07062b718ece9b9cb7b23b12d83a087eafb0;hp=653c95b8b9066c9c6ac08bd64d0ceee439e9fd90
|
||||
|
||||
MIPS: lantiq: Add device register helper for SPI controller and devices
|
||||
|
||||
Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@googlemail.com>
|
||||
---
|
||||
|
||||
--- a/arch/mips/lantiq/xway/devices.h
|
||||
+++ b/arch/mips/lantiq/xway/devices.h
|
||||
@@ -11,10 +11,13 @@
|
||||
|
||||
#include "../devices.h"
|
||||
#include <linux/phy.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
|
||||
extern void ltq_register_gpio(void);
|
||||
extern void ltq_register_gpio_stp(void);
|
||||
extern void ltq_register_ase_asc(void);
|
||||
extern void ltq_register_etop(struct ltq_eth_data *eth);
|
||||
+extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
||||
+ struct spi_board_info const *info, unsigned n);
|
||||
|
||||
#endif
|
||||
--- a/arch/mips/lantiq/xway/devices.c
|
||||
+++ b/arch/mips/lantiq/xway/devices.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/leds.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/irq.h>
|
||||
@@ -119,3 +120,41 @@
|
||||
platform_device_register(<q_etop);
|
||||
}
|
||||
}
|
||||
+
|
||||
+static struct resource ltq_spi_resources[] = {
|
||||
+ {
|
||||
+ .start = LTQ_SSC_BASE_ADDR,
|
||||
+ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1,
|
||||
+ .flags = IORESOURCE_MEM,
|
||||
+ },
|
||||
+ IRQ_RES(spi_tx, LTQ_SSC_TIR),
|
||||
+ IRQ_RES(spi_rx, LTQ_SSC_RIR),
|
||||
+ IRQ_RES(spi_err, LTQ_SSC_EIR),
|
||||
+};
|
||||
+
|
||||
+static struct resource ltq_spi_resources_ar9[] = {
|
||||
+ {
|
||||
+ .start = LTQ_SSC_BASE_ADDR,
|
||||
+ .end = LTQ_SSC_BASE_ADDR + LTQ_SSC_SIZE - 1,
|
||||
+ .flags = IORESOURCE_MEM,
|
||||
+ },
|
||||
+ IRQ_RES(spi_tx, LTQ_SSC_TIR_AR9),
|
||||
+ IRQ_RES(spi_rx, LTQ_SSC_RIR_AR9),
|
||||
+ IRQ_RES(spi_err, LTQ_SSC_EIR),
|
||||
+};
|
||||
+
|
||||
+static struct platform_device ltq_spi = {
|
||||
+ .name = "ltq-spi",
|
||||
+ .resource = ltq_spi_resources,
|
||||
+ .num_resources = ARRAY_SIZE(ltq_spi_resources),
|
||||
+};
|
||||
+
|
||||
+void __init ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
||||
+ struct spi_board_info const *info, unsigned n)
|
||||
+{
|
||||
+ if(ltq_is_ar9())
|
||||
+ ltq_spi.resource = ltq_spi_resources_ar9;
|
||||
+ spi_register_board_info(info, n);
|
||||
+ ltq_spi.dev.platform_data = pdata;
|
||||
+ platform_device_register(<q_spi);
|
||||
+}
|
||||
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
|
||||
#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
|
||||
+#define LTQ_SSC_TIR_AR9 (INT_NUM_IM0_IRL0 + 14)
|
||||
+#define LTQ_SSC_RIR_AR9 (INT_NUM_IM0_IRL0 + 15)
|
||||
#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
|
||||
|
||||
#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
|
|
@ -0,0 +1,999 @@
|
|||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/xway/timer.c
|
||||
@@ -0,0 +1,830 @@
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/miscdevice.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <linux/unistd.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/sched.h>
|
||||
+
|
||||
+#include <asm/irq.h>
|
||||
+#include <asm/div64.h>
|
||||
+
|
||||
+#include <lantiq_soc.h>
|
||||
+#include <lantiq_irq.h>
|
||||
+#include <lantiq_timer.h>
|
||||
+
|
||||
+#define MAX_NUM_OF_32BIT_TIMER_BLOCKS 6
|
||||
+
|
||||
+#ifdef TIMER1A
|
||||
+#define FIRST_TIMER TIMER1A
|
||||
+#else
|
||||
+#define FIRST_TIMER 2
|
||||
+#endif
|
||||
+
|
||||
+/*
|
||||
+ * GPTC divider is set or not.
|
||||
+ */
|
||||
+#define GPTU_CLC_RMC_IS_SET 0
|
||||
+
|
||||
+/*
|
||||
+ * Timer Interrupt (IRQ)
|
||||
+ */
|
||||
+/* Must be adjusted when ICU driver is available */
|
||||
+#define TIMER_INTERRUPT (INT_NUM_IM3_IRL0 + 22)
|
||||
+
|
||||
+/*
|
||||
+ * Bits Operation
|
||||
+ */
|
||||
+#define GET_BITS(x, msb, lsb) \
|
||||
+ (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
|
||||
+#define SET_BITS(x, msb, lsb, value) \
|
||||
+ (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | \
|
||||
+ (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
|
||||
+
|
||||
+/*
|
||||
+ * GPTU Register Mapping
|
||||
+ */
|
||||
+#define LQ_GPTU (KSEG1 + 0x1E100A00)
|
||||
+#define LQ_GPTU_CLC ((volatile u32 *)(LQ_GPTU + 0x0000))
|
||||
+#define LQ_GPTU_ID ((volatile u32 *)(LQ_GPTU + 0x0008))
|
||||
+#define LQ_GPTU_CON(n, X) ((volatile u32 *)(LQ_GPTU + 0x0010 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
+#define LQ_GPTU_RUN(n, X) ((volatile u32 *)(LQ_GPTU + 0x0018 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
+#define LQ_GPTU_RELOAD(n, X) ((volatile u32 *)(LQ_GPTU + 0x0020 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
+#define LQ_GPTU_COUNT(n, X) ((volatile u32 *)(LQ_GPTU + 0x0028 + ((X) * 4) + ((n) - 1) * 0x0020)) /* X must be either A or B */
|
||||
+#define LQ_GPTU_IRNEN ((volatile u32 *)(LQ_GPTU + 0x00F4))
|
||||
+#define LQ_GPTU_IRNICR ((volatile u32 *)(LQ_GPTU + 0x00F8))
|
||||
+#define LQ_GPTU_IRNCR ((volatile u32 *)(LQ_GPTU + 0x00FC))
|
||||
+
|
||||
+/*
|
||||
+ * Clock Control Register
|
||||
+ */
|
||||
+#define GPTU_CLC_SMC GET_BITS(*LQ_GPTU_CLC, 23, 16)
|
||||
+#define GPTU_CLC_RMC GET_BITS(*LQ_GPTU_CLC, 15, 8)
|
||||
+#define GPTU_CLC_FSOE (*LQ_GPTU_CLC & (1 << 5))
|
||||
+#define GPTU_CLC_EDIS (*LQ_GPTU_CLC & (1 << 3))
|
||||
+#define GPTU_CLC_SPEN (*LQ_GPTU_CLC & (1 << 2))
|
||||
+#define GPTU_CLC_DISS (*LQ_GPTU_CLC & (1 << 1))
|
||||
+#define GPTU_CLC_DISR (*LQ_GPTU_CLC & (1 << 0))
|
||||
+
|
||||
+#define GPTU_CLC_SMC_SET(value) SET_BITS(0, 23, 16, (value))
|
||||
+#define GPTU_CLC_RMC_SET(value) SET_BITS(0, 15, 8, (value))
|
||||
+#define GPTU_CLC_FSOE_SET(value) ((value) ? (1 << 5) : 0)
|
||||
+#define GPTU_CLC_SBWE_SET(value) ((value) ? (1 << 4) : 0)
|
||||
+#define GPTU_CLC_EDIS_SET(value) ((value) ? (1 << 3) : 0)
|
||||
+#define GPTU_CLC_SPEN_SET(value) ((value) ? (1 << 2) : 0)
|
||||
+#define GPTU_CLC_DISR_SET(value) ((value) ? (1 << 0) : 0)
|
||||
+
|
||||
+/*
|
||||
+ * ID Register
|
||||
+ */
|
||||
+#define GPTU_ID_ID GET_BITS(*LQ_GPTU_ID, 15, 8)
|
||||
+#define GPTU_ID_CFG GET_BITS(*LQ_GPTU_ID, 7, 5)
|
||||
+#define GPTU_ID_REV GET_BITS(*LQ_GPTU_ID, 4, 0)
|
||||
+
|
||||
+/*
|
||||
+ * Control Register of Timer/Counter nX
|
||||
+ * n is the index of block (1 based index)
|
||||
+ * X is either A or B
|
||||
+ */
|
||||
+#define GPTU_CON_SRC_EG(n, X) (*LQ_GPTU_CON(n, X) & (1 << 10))
|
||||
+#define GPTU_CON_SRC_EXT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 9))
|
||||
+#define GPTU_CON_SYNC(n, X) (*LQ_GPTU_CON(n, X) & (1 << 8))
|
||||
+#define GPTU_CON_EDGE(n, X) GET_BITS(*LQ_GPTU_CON(n, X), 7, 6)
|
||||
+#define GPTU_CON_INV(n, X) (*LQ_GPTU_CON(n, X) & (1 << 5))
|
||||
+#define GPTU_CON_EXT(n, X) (*LQ_GPTU_CON(n, A) & (1 << 4)) /* Timer/Counter B does not have this bit */
|
||||
+#define GPTU_CON_STP(n, X) (*LQ_GPTU_CON(n, X) & (1 << 3))
|
||||
+#define GPTU_CON_CNT(n, X) (*LQ_GPTU_CON(n, X) & (1 << 2))
|
||||
+#define GPTU_CON_DIR(n, X) (*LQ_GPTU_CON(n, X) & (1 << 1))
|
||||
+#define GPTU_CON_EN(n, X) (*LQ_GPTU_CON(n, X) & (1 << 0))
|
||||
+
|
||||
+#define GPTU_CON_SRC_EG_SET(value) ((value) ? 0 : (1 << 10))
|
||||
+#define GPTU_CON_SRC_EXT_SET(value) ((value) ? (1 << 9) : 0)
|
||||
+#define GPTU_CON_SYNC_SET(value) ((value) ? (1 << 8) : 0)
|
||||
+#define GPTU_CON_EDGE_SET(value) SET_BITS(0, 7, 6, (value))
|
||||
+#define GPTU_CON_INV_SET(value) ((value) ? (1 << 5) : 0)
|
||||
+#define GPTU_CON_EXT_SET(value) ((value) ? (1 << 4) : 0)
|
||||
+#define GPTU_CON_STP_SET(value) ((value) ? (1 << 3) : 0)
|
||||
+#define GPTU_CON_CNT_SET(value) ((value) ? (1 << 2) : 0)
|
||||
+#define GPTU_CON_DIR_SET(value) ((value) ? (1 << 1) : 0)
|
||||
+
|
||||
+#define GPTU_RUN_RL_SET(value) ((value) ? (1 << 2) : 0)
|
||||
+#define GPTU_RUN_CEN_SET(value) ((value) ? (1 << 1) : 0)
|
||||
+#define GPTU_RUN_SEN_SET(value) ((value) ? (1 << 0) : 0)
|
||||
+
|
||||
+#define GPTU_IRNEN_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
|
||||
+#define GPTU_IRNCR_TC_SET(n, X, value) ((value) ? (1 << (((n) - 1) * 2 + (X))) : 0)
|
||||
+
|
||||
+#define TIMER_FLAG_MASK_SIZE(x) (x & 0x0001)
|
||||
+#define TIMER_FLAG_MASK_TYPE(x) (x & 0x0002)
|
||||
+#define TIMER_FLAG_MASK_STOP(x) (x & 0x0004)
|
||||
+#define TIMER_FLAG_MASK_DIR(x) (x & 0x0008)
|
||||
+#define TIMER_FLAG_NONE_EDGE 0x0000
|
||||
+#define TIMER_FLAG_MASK_EDGE(x) (x & 0x0030)
|
||||
+#define TIMER_FLAG_REAL 0x0000
|
||||
+#define TIMER_FLAG_INVERT 0x0040
|
||||
+#define TIMER_FLAG_MASK_INVERT(x) (x & 0x0040)
|
||||
+#define TIMER_FLAG_MASK_TRIGGER(x) (x & 0x0070)
|
||||
+#define TIMER_FLAG_MASK_SYNC(x) (x & 0x0080)
|
||||
+#define TIMER_FLAG_CALLBACK_IN_HB 0x0200
|
||||
+#define TIMER_FLAG_MASK_HANDLE(x) (x & 0x0300)
|
||||
+#define TIMER_FLAG_MASK_SRC(x) (x & 0x1000)
|
||||
+
|
||||
+struct timer_dev_timer {
|
||||
+ unsigned int f_irq_on;
|
||||
+ unsigned int irq;
|
||||
+ unsigned int flag;
|
||||
+ unsigned long arg1;
|
||||
+ unsigned long arg2;
|
||||
+};
|
||||
+
|
||||
+struct timer_dev {
|
||||
+ struct mutex gptu_mutex;
|
||||
+ unsigned int number_of_timers;
|
||||
+ unsigned int occupation;
|
||||
+ unsigned int f_gptu_on;
|
||||
+ struct timer_dev_timer timer[MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2];
|
||||
+};
|
||||
+
|
||||
+unsigned int ltq_get_fpi_bus_clock(int fpi);
|
||||
+
|
||||
+static long gptu_ioctl(struct file *, unsigned int, unsigned long);
|
||||
+static int gptu_open(struct inode *, struct file *);
|
||||
+static int gptu_release(struct inode *, struct file *);
|
||||
+
|
||||
+static struct file_operations gptu_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .unlocked_ioctl = gptu_ioctl,
|
||||
+ .open = gptu_open,
|
||||
+ .release = gptu_release
|
||||
+};
|
||||
+
|
||||
+static struct miscdevice gptu_miscdev = {
|
||||
+ .minor = MISC_DYNAMIC_MINOR,
|
||||
+ .name = "gptu",
|
||||
+ .fops = &gptu_fops,
|
||||
+};
|
||||
+
|
||||
+static struct timer_dev timer_dev;
|
||||
+
|
||||
+static irqreturn_t timer_irq_handler(int irq, void *p)
|
||||
+{
|
||||
+ unsigned int timer;
|
||||
+ unsigned int flag;
|
||||
+ struct timer_dev_timer *dev_timer = (struct timer_dev_timer *)p;
|
||||
+
|
||||
+ timer = irq - TIMER_INTERRUPT;
|
||||
+ if (timer < timer_dev.number_of_timers
|
||||
+ && dev_timer == &timer_dev.timer[timer]) {
|
||||
+ /* Clear interrupt. */
|
||||
+ ltq_w32(1 << timer, LQ_GPTU_IRNCR);
|
||||
+
|
||||
+ /* Call user hanler or signal. */
|
||||
+ flag = dev_timer->flag;
|
||||
+ if (!(timer & 0x01)
|
||||
+ || TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
|
||||
+ /* 16-bit timer or timer A of 32-bit timer */
|
||||
+ switch (TIMER_FLAG_MASK_HANDLE(flag)) {
|
||||
+ case TIMER_FLAG_CALLBACK_IN_IRQ:
|
||||
+ case TIMER_FLAG_CALLBACK_IN_HB:
|
||||
+ if (dev_timer->arg1)
|
||||
+ (*(timer_callback)dev_timer->arg1)(dev_timer->arg2);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_SIGNAL:
|
||||
+ send_sig((int)dev_timer->arg2, (struct task_struct *)dev_timer->arg1, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static inline void lq_enable_gptu(void)
|
||||
+{
|
||||
+ ltq_pmu_enable(PMU_GPT);
|
||||
+
|
||||
+ /* Set divider as 1, disable write protection for SPEN, enable module. */
|
||||
+ *LQ_GPTU_CLC =
|
||||
+ GPTU_CLC_SMC_SET(0x00) |
|
||||
+ GPTU_CLC_RMC_SET(0x01) |
|
||||
+ GPTU_CLC_FSOE_SET(0) |
|
||||
+ GPTU_CLC_SBWE_SET(1) |
|
||||
+ GPTU_CLC_EDIS_SET(0) |
|
||||
+ GPTU_CLC_SPEN_SET(0) |
|
||||
+ GPTU_CLC_DISR_SET(0);
|
||||
+}
|
||||
+
|
||||
+static inline void lq_disable_gptu(void)
|
||||
+{
|
||||
+ ltq_w32(0x00, LQ_GPTU_IRNEN);
|
||||
+ ltq_w32(0xfff, LQ_GPTU_IRNCR);
|
||||
+
|
||||
+ /* Set divider as 0, enable write protection for SPEN, disable module. */
|
||||
+ *LQ_GPTU_CLC =
|
||||
+ GPTU_CLC_SMC_SET(0x00) |
|
||||
+ GPTU_CLC_RMC_SET(0x00) |
|
||||
+ GPTU_CLC_FSOE_SET(0) |
|
||||
+ GPTU_CLC_SBWE_SET(0) |
|
||||
+ GPTU_CLC_EDIS_SET(0) |
|
||||
+ GPTU_CLC_SPEN_SET(0) |
|
||||
+ GPTU_CLC_DISR_SET(1);
|
||||
+
|
||||
+ ltq_pmu_disable(PMU_GPT);
|
||||
+}
|
||||
+
|
||||
+int lq_request_timer(unsigned int timer, unsigned int flag,
|
||||
+ unsigned long value, unsigned long arg1, unsigned long arg2)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+ unsigned int con_reg, irnen_reg;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ printk(KERN_INFO "request_timer(%d, 0x%08X, %lu)...",
|
||||
+ timer, flag, value);
|
||||
+
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT)
|
||||
+ value &= 0xFFFF;
|
||||
+ else
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ /*
|
||||
+ * Allocate timer.
|
||||
+ */
|
||||
+ if (timer < FIRST_TIMER) {
|
||||
+ unsigned int mask;
|
||||
+ unsigned int shift;
|
||||
+ /* This takes care of TIMER1B which is the only choice for Voice TAPI system */
|
||||
+ unsigned int offset = TIMER2A;
|
||||
+
|
||||
+ /*
|
||||
+ * Pick up a free timer.
|
||||
+ */
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT) {
|
||||
+ mask = 1 << offset;
|
||||
+ shift = 1;
|
||||
+ } else {
|
||||
+ mask = 3 << offset;
|
||||
+ shift = 2;
|
||||
+ }
|
||||
+ for (timer = offset;
|
||||
+ timer < offset + timer_dev.number_of_timers;
|
||||
+ timer += shift, mask <<= shift)
|
||||
+ if (!(timer_dev.occupation & mask)) {
|
||||
+ timer_dev.occupation |= mask;
|
||||
+ break;
|
||||
+ }
|
||||
+ if (timer >= offset + timer_dev.number_of_timers) {
|
||||
+ printk("failed![%d]\n", __LINE__);
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ } else
|
||||
+ ret = timer;
|
||||
+ } else {
|
||||
+ register unsigned int mask;
|
||||
+
|
||||
+ /*
|
||||
+ * Check if the requested timer is free.
|
||||
+ */
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if ((timer_dev.occupation & mask)) {
|
||||
+ printk("failed![%d] mask %#x, timer_dev.occupation %#x\n",
|
||||
+ __LINE__, mask, timer_dev.occupation);
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EBUSY;
|
||||
+ } else {
|
||||
+ timer_dev.occupation |= mask;
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Prepare control register value.
|
||||
+ */
|
||||
+ switch (TIMER_FLAG_MASK_EDGE(flag)) {
|
||||
+ default:
|
||||
+ case TIMER_FLAG_NONE_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x00);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_RISE_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x01);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_FALL_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x02);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_ANY_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x03);
|
||||
+ break;
|
||||
+ }
|
||||
+ if (TIMER_FLAG_MASK_TYPE(flag) == TIMER_FLAG_TIMER)
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_SRC(flag) ==
|
||||
+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) :
|
||||
+ GPTU_CON_SRC_EXT_SET(0);
|
||||
+ else
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_SRC(flag) ==
|
||||
+ TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) :
|
||||
+ GPTU_CON_SRC_EG_SET(0);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_SYNC(flag) ==
|
||||
+ TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) :
|
||||
+ GPTU_CON_SYNC_SET(1);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_INVERT(flag) ==
|
||||
+ TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_SIZE(flag) ==
|
||||
+ TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) :
|
||||
+ GPTU_CON_EXT_SET(1);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_STOP(flag) ==
|
||||
+ TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_TYPE(flag) ==
|
||||
+ TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) :
|
||||
+ GPTU_CON_CNT_SET(1);
|
||||
+ con_reg |=
|
||||
+ TIMER_FLAG_MASK_DIR(flag) ==
|
||||
+ TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
|
||||
+
|
||||
+ /*
|
||||
+ * Fill up running data.
|
||||
+ */
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].flag = flag;
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].arg1 = arg1;
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].arg2 = arg2;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flag;
|
||||
+
|
||||
+ /*
|
||||
+ * Enable GPTU module.
|
||||
+ */
|
||||
+ if (!timer_dev.f_gptu_on) {
|
||||
+ lq_enable_gptu();
|
||||
+ timer_dev.f_gptu_on = 1;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Enable IRQ.
|
||||
+ */
|
||||
+ if (TIMER_FLAG_MASK_HANDLE(flag) != TIMER_FLAG_NO_HANDLE) {
|
||||
+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL)
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].arg1 =
|
||||
+ (unsigned long) find_task_by_vpid((int) arg1);
|
||||
+
|
||||
+ irnen_reg = 1 << (timer - FIRST_TIMER);
|
||||
+
|
||||
+ if (TIMER_FLAG_MASK_HANDLE(flag) == TIMER_FLAG_SIGNAL
|
||||
+ || (TIMER_FLAG_MASK_HANDLE(flag) ==
|
||||
+ TIMER_FLAG_CALLBACK_IN_IRQ
|
||||
+ && timer_dev.timer[timer - FIRST_TIMER].arg1)) {
|
||||
+ enable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 1;
|
||||
+ }
|
||||
+ } else
|
||||
+ irnen_reg = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * Write config register, reload value and enable interrupt.
|
||||
+ */
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+ *LQ_GPTU_CON(n, X) = con_reg;
|
||||
+ *LQ_GPTU_RELOAD(n, X) = value;
|
||||
+ /* printk("reload value = %d\n", (u32)value); */
|
||||
+ *LQ_GPTU_IRNEN |= irnen_reg;
|
||||
+
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ printk("successful!\n");
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_request_timer);
|
||||
+
|
||||
+int lq_free_timer(unsigned int timer)
|
||||
+{
|
||||
+ unsigned int flag;
|
||||
+ unsigned int mask;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (!timer_dev.f_gptu_on)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+
|
||||
+ if (GPTU_CON_EN(n, X))
|
||||
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
|
||||
+
|
||||
+ *LQ_GPTU_IRNEN &= ~GPTU_IRNEN_TC_SET(n, X, 1);
|
||||
+ *LQ_GPTU_IRNCR |= GPTU_IRNCR_TC_SET(n, X, 1);
|
||||
+
|
||||
+ if (timer_dev.timer[timer - FIRST_TIMER].f_irq_on) {
|
||||
+ disable_irq(timer_dev.timer[timer - FIRST_TIMER].irq);
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].f_irq_on = 0;
|
||||
+ }
|
||||
+
|
||||
+ timer_dev.occupation &= ~mask;
|
||||
+ if (!timer_dev.occupation && timer_dev.f_gptu_on) {
|
||||
+ lq_disable_gptu();
|
||||
+ timer_dev.f_gptu_on = 0;
|
||||
+ }
|
||||
+
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_free_timer);
|
||||
+
|
||||
+int lq_start_timer(unsigned int timer, int is_resume)
|
||||
+{
|
||||
+ unsigned int flag;
|
||||
+ unsigned int mask;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (!timer_dev.f_gptu_on)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(flag) ==
|
||||
+ TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+
|
||||
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_RL_SET(!is_resume) | GPTU_RUN_SEN_SET(1);
|
||||
+
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_start_timer);
|
||||
+
|
||||
+int lq_stop_timer(unsigned int timer)
|
||||
+{
|
||||
+ unsigned int flag;
|
||||
+ unsigned int mask;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (!timer_dev.f_gptu_on)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (timer < FIRST_TIMER
|
||||
+ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+
|
||||
+ *LQ_GPTU_RUN(n, X) = GPTU_RUN_CEN_SET(1);
|
||||
+
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_stop_timer);
|
||||
+
|
||||
+int lq_reset_counter_flags(u32 timer, u32 flags)
|
||||
+{
|
||||
+ unsigned int oflag;
|
||||
+ unsigned int mask, con_reg;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (!timer_dev.f_gptu_on)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (timer < FIRST_TIMER || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ oflag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(oflag) != TIMER_FLAG_16BIT)
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(oflag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (TIMER_FLAG_MASK_EDGE(flags)) {
|
||||
+ default:
|
||||
+ case TIMER_FLAG_NONE_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x00);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_RISE_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x01);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_FALL_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x02);
|
||||
+ break;
|
||||
+ case TIMER_FLAG_ANY_EDGE:
|
||||
+ con_reg = GPTU_CON_EDGE_SET(0x03);
|
||||
+ break;
|
||||
+ }
|
||||
+ if (TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER)
|
||||
+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EXT_SET(1) : GPTU_CON_SRC_EXT_SET(0);
|
||||
+ else
|
||||
+ con_reg |= TIMER_FLAG_MASK_SRC(flags) == TIMER_FLAG_EXT_SRC ? GPTU_CON_SRC_EG_SET(1) : GPTU_CON_SRC_EG_SET(0);
|
||||
+ con_reg |= TIMER_FLAG_MASK_SYNC(flags) == TIMER_FLAG_UNSYNC ? GPTU_CON_SYNC_SET(0) : GPTU_CON_SYNC_SET(1);
|
||||
+ con_reg |= TIMER_FLAG_MASK_INVERT(flags) == TIMER_FLAG_REAL ? GPTU_CON_INV_SET(0) : GPTU_CON_INV_SET(1);
|
||||
+ con_reg |= TIMER_FLAG_MASK_SIZE(flags) == TIMER_FLAG_16BIT ? GPTU_CON_EXT_SET(0) : GPTU_CON_EXT_SET(1);
|
||||
+ con_reg |= TIMER_FLAG_MASK_STOP(flags) == TIMER_FLAG_ONCE ? GPTU_CON_STP_SET(1) : GPTU_CON_STP_SET(0);
|
||||
+ con_reg |= TIMER_FLAG_MASK_TYPE(flags) == TIMER_FLAG_TIMER ? GPTU_CON_CNT_SET(0) : GPTU_CON_CNT_SET(1);
|
||||
+ con_reg |= TIMER_FLAG_MASK_DIR(flags) == TIMER_FLAG_UP ? GPTU_CON_DIR_SET(1) : GPTU_CON_DIR_SET(0);
|
||||
+
|
||||
+ timer_dev.timer[timer - FIRST_TIMER].flag = flags;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flags) != TIMER_FLAG_16BIT)
|
||||
+ timer_dev.timer[timer - FIRST_TIMER + 1].flag = flags;
|
||||
+
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+
|
||||
+ *LQ_GPTU_CON(n, X) = con_reg;
|
||||
+ smp_wmb();
|
||||
+ printk(KERN_INFO "[%s]: counter%d oflags %#x, nflags %#x, GPTU_CON %#x\n", __func__, timer, oflag, flags, *LQ_GPTU_CON(n, X));
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_reset_counter_flags);
|
||||
+
|
||||
+int lq_get_count_value(unsigned int timer, unsigned long *value)
|
||||
+{
|
||||
+ unsigned int flag;
|
||||
+ unsigned int mask;
|
||||
+ int n, X;
|
||||
+
|
||||
+ if (!timer_dev.f_gptu_on)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (timer < FIRST_TIMER
|
||||
+ || timer >= FIRST_TIMER + timer_dev.number_of_timers)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ mutex_lock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ flag = timer_dev.timer[timer - FIRST_TIMER].flag;
|
||||
+ if (TIMER_FLAG_MASK_SIZE(flag) != TIMER_FLAG_16BIT)
|
||||
+ timer &= ~0x01;
|
||||
+
|
||||
+ mask = (TIMER_FLAG_MASK_SIZE(flag) == TIMER_FLAG_16BIT ? 1 : 3) << timer;
|
||||
+ if (((timer_dev.occupation & mask) ^ mask)) {
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ n = timer >> 1;
|
||||
+ X = timer & 0x01;
|
||||
+
|
||||
+ *value = *LQ_GPTU_COUNT(n, X);
|
||||
+
|
||||
+ mutex_unlock(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_get_count_value);
|
||||
+
|
||||
+u32 lq_cal_divider(unsigned long freq)
|
||||
+{
|
||||
+ u64 module_freq, fpi = ltq_get_fpi_bus_clock(2);
|
||||
+ u32 clock_divider = 1;
|
||||
+ module_freq = fpi * 1000;
|
||||
+ do_div(module_freq, clock_divider * freq);
|
||||
+ return module_freq;
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_cal_divider);
|
||||
+
|
||||
+int lq_set_timer(unsigned int timer, unsigned int freq, int is_cyclic,
|
||||
+ int is_ext_src, unsigned int handle_flag, unsigned long arg1,
|
||||
+ unsigned long arg2)
|
||||
+{
|
||||
+ unsigned long divider;
|
||||
+ unsigned int flag;
|
||||
+
|
||||
+ divider = lq_cal_divider(freq);
|
||||
+ if (divider == 0)
|
||||
+ return -EINVAL;
|
||||
+ flag = ((divider & ~0xFFFF) ? TIMER_FLAG_32BIT : TIMER_FLAG_16BIT)
|
||||
+ | (is_cyclic ? TIMER_FLAG_CYCLIC : TIMER_FLAG_ONCE)
|
||||
+ | (is_ext_src ? TIMER_FLAG_EXT_SRC : TIMER_FLAG_INT_SRC)
|
||||
+ | TIMER_FLAG_TIMER | TIMER_FLAG_DOWN
|
||||
+ | TIMER_FLAG_MASK_HANDLE(handle_flag);
|
||||
+
|
||||
+ printk(KERN_INFO "lq_set_timer(%d, %d), divider = %lu\n",
|
||||
+ timer, freq, divider);
|
||||
+ return lq_request_timer(timer, flag, divider, arg1, arg2);
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_set_timer);
|
||||
+
|
||||
+int lq_set_counter(unsigned int timer, unsigned int flag, u32 reload,
|
||||
+ unsigned long arg1, unsigned long arg2)
|
||||
+{
|
||||
+ printk(KERN_INFO "lq_set_counter(%d, %#x, %d)\n", timer, flag, reload);
|
||||
+ return lq_request_timer(timer, flag, reload, arg1, arg2);
|
||||
+}
|
||||
+EXPORT_SYMBOL(lq_set_counter);
|
||||
+
|
||||
+static long gptu_ioctl(struct file *file, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct gptu_ioctl_param param;
|
||||
+
|
||||
+ if (!access_ok(VERIFY_READ, arg, sizeof(struct gptu_ioctl_param)))
|
||||
+ return -EFAULT;
|
||||
+ copy_from_user(¶m, (void *) arg, sizeof(param));
|
||||
+
|
||||
+ if ((((cmd == GPTU_REQUEST_TIMER || cmd == GPTU_SET_TIMER
|
||||
+ || GPTU_SET_COUNTER) && param.timer < 2)
|
||||
+ || cmd == GPTU_GET_COUNT_VALUE || cmd == GPTU_CALCULATE_DIVIDER)
|
||||
+ && !access_ok(VERIFY_WRITE, arg,
|
||||
+ sizeof(struct gptu_ioctl_param)))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case GPTU_REQUEST_TIMER:
|
||||
+ ret = lq_request_timer(param.timer, param.flag, param.value,
|
||||
+ (unsigned long) param.pid,
|
||||
+ (unsigned long) param.sig);
|
||||
+ if (ret > 0) {
|
||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
+ timer, &ret, sizeof(&ret));
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ case GPTU_FREE_TIMER:
|
||||
+ ret = lq_free_timer(param.timer);
|
||||
+ break;
|
||||
+ case GPTU_START_TIMER:
|
||||
+ ret = lq_start_timer(param.timer, param.flag);
|
||||
+ break;
|
||||
+ case GPTU_STOP_TIMER:
|
||||
+ ret = lq_stop_timer(param.timer);
|
||||
+ break;
|
||||
+ case GPTU_GET_COUNT_VALUE:
|
||||
+ ret = lq_get_count_value(param.timer, ¶m.value);
|
||||
+ if (!ret)
|
||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
+ value, ¶m.value,
|
||||
+ sizeof(param.value));
|
||||
+ break;
|
||||
+ case GPTU_CALCULATE_DIVIDER:
|
||||
+ param.value = lq_cal_divider(param.value);
|
||||
+ if (param.value == 0)
|
||||
+ ret = -EINVAL;
|
||||
+ else {
|
||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
+ value, ¶m.value,
|
||||
+ sizeof(param.value));
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ case GPTU_SET_TIMER:
|
||||
+ ret = lq_set_timer(param.timer, param.value,
|
||||
+ TIMER_FLAG_MASK_STOP(param.flag) !=
|
||||
+ TIMER_FLAG_ONCE ? 1 : 0,
|
||||
+ TIMER_FLAG_MASK_SRC(param.flag) ==
|
||||
+ TIMER_FLAG_EXT_SRC ? 1 : 0,
|
||||
+ TIMER_FLAG_MASK_HANDLE(param.flag) ==
|
||||
+ TIMER_FLAG_SIGNAL ? TIMER_FLAG_SIGNAL :
|
||||
+ TIMER_FLAG_NO_HANDLE,
|
||||
+ (unsigned long) param.pid,
|
||||
+ (unsigned long) param.sig);
|
||||
+ if (ret > 0) {
|
||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
+ timer, &ret, sizeof(&ret));
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ case GPTU_SET_COUNTER:
|
||||
+ lq_set_counter(param.timer, param.flag, param.value, 0, 0);
|
||||
+ if (ret > 0) {
|
||||
+ copy_to_user(&((struct gptu_ioctl_param *) arg)->
|
||||
+ timer, &ret, sizeof(&ret));
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ ret = -ENOTTY;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int gptu_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gptu_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int __init lq_gptu_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ ltq_w32(0, LQ_GPTU_IRNEN);
|
||||
+ ltq_w32(0xfff, LQ_GPTU_IRNCR);
|
||||
+
|
||||
+ memset(&timer_dev, 0, sizeof(timer_dev));
|
||||
+ mutex_init(&timer_dev.gptu_mutex);
|
||||
+
|
||||
+ lq_enable_gptu();
|
||||
+ timer_dev.number_of_timers = GPTU_ID_CFG * 2;
|
||||
+ lq_disable_gptu();
|
||||
+ if (timer_dev.number_of_timers > MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2)
|
||||
+ timer_dev.number_of_timers = MAX_NUM_OF_32BIT_TIMER_BLOCKS * 2;
|
||||
+ printk(KERN_INFO "gptu: totally %d 16-bit timers/counters\n", timer_dev.number_of_timers);
|
||||
+
|
||||
+ ret = misc_register(&gptu_miscdev);
|
||||
+ if (ret) {
|
||||
+ printk(KERN_ERR "gptu: can't misc_register, get error %d\n", -ret);
|
||||
+ return ret;
|
||||
+ } else {
|
||||
+ printk(KERN_INFO "gptu: misc_register on minor %d\n", gptu_miscdev.minor);
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < timer_dev.number_of_timers; i++) {
|
||||
+ ret = request_irq(TIMER_INTERRUPT + i, timer_irq_handler, IRQF_TIMER, gptu_miscdev.name, &timer_dev.timer[i]);
|
||||
+ if (ret) {
|
||||
+ for (; i >= 0; i--)
|
||||
+ free_irq(TIMER_INTERRUPT + i, &timer_dev.timer[i]);
|
||||
+ misc_deregister(&gptu_miscdev);
|
||||
+ printk(KERN_ERR "gptu: failed in requesting irq (%d), get error %d\n", i, -ret);
|
||||
+ return ret;
|
||||
+ } else {
|
||||
+ timer_dev.timer[i].irq = TIMER_INTERRUPT + i;
|
||||
+ disable_irq(timer_dev.timer[i].irq);
|
||||
+ printk(KERN_INFO "gptu: succeeded to request irq %d\n", timer_dev.timer[i].irq);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void __exit lq_gptu_exit(void)
|
||||
+{
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ for (i = 0; i < timer_dev.number_of_timers; i++) {
|
||||
+ if (timer_dev.timer[i].f_irq_on)
|
||||
+ disable_irq(timer_dev.timer[i].irq);
|
||||
+ free_irq(timer_dev.timer[i].irq, &timer_dev.timer[i]);
|
||||
+ }
|
||||
+ lq_disable_gptu();
|
||||
+ misc_deregister(&gptu_miscdev);
|
||||
+}
|
||||
+
|
||||
+module_init(lq_gptu_init);
|
||||
+module_exit(lq_gptu_exit);
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/lantiq_timer.h
|
||||
@@ -0,0 +1,155 @@
|
||||
+#ifndef __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
|
||||
+#define __DANUBE_GPTU_DEV_H__2005_07_26__10_19__
|
||||
+
|
||||
+
|
||||
+/******************************************************************************
|
||||
+ Copyright (c) 2002, Infineon Technologies. All rights reserved.
|
||||
+
|
||||
+ No Warranty
|
||||
+ Because the program is licensed free of charge, there is no warranty for
|
||||
+ the program, to the extent permitted by applicable law. Except when
|
||||
+ otherwise stated in writing the copyright holders and/or other parties
|
||||
+ provide the program "as is" without warranty of any kind, either
|
||||
+ expressed or implied, including, but not limited to, the implied
|
||||
+ warranties of merchantability and fitness for a particular purpose. The
|
||||
+ entire risk as to the quality and performance of the program is with
|
||||
+ you. should the program prove defective, you assume the cost of all
|
||||
+ necessary servicing, repair or correction.
|
||||
+
|
||||
+ In no event unless required by applicable law or agreed to in writing
|
||||
+ will any copyright holder, or any other party who may modify and/or
|
||||
+ redistribute the program as permitted above, be liable to you for
|
||||
+ damages, including any general, special, incidental or consequential
|
||||
+ damages arising out of the use or inability to use the program
|
||||
+ (including but not limited to loss of data or data being rendered
|
||||
+ inaccurate or losses sustained by you or third parties or a failure of
|
||||
+ the program to operate with any other programs), even if such holder or
|
||||
+ other party has been advised of the possibility of such damages.
|
||||
+******************************************************************************/
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * ####################################
|
||||
+ * Definition
|
||||
+ * ####################################
|
||||
+ */
|
||||
+
|
||||
+/*
|
||||
+ * Available Timer/Counter Index
|
||||
+ */
|
||||
+#define TIMER(n, X) (n * 2 + (X ? 1 : 0))
|
||||
+#define TIMER_ANY 0x00
|
||||
+#define TIMER1A TIMER(1, 0)
|
||||
+#define TIMER1B TIMER(1, 1)
|
||||
+#define TIMER2A TIMER(2, 0)
|
||||
+#define TIMER2B TIMER(2, 1)
|
||||
+#define TIMER3A TIMER(3, 0)
|
||||
+#define TIMER3B TIMER(3, 1)
|
||||
+
|
||||
+/*
|
||||
+ * Flag of Timer/Counter
|
||||
+ * These flags specify the way in which timer is configured.
|
||||
+ */
|
||||
+/* Bit size of timer/counter. */
|
||||
+#define TIMER_FLAG_16BIT 0x0000
|
||||
+#define TIMER_FLAG_32BIT 0x0001
|
||||
+/* Switch between timer and counter. */
|
||||
+#define TIMER_FLAG_TIMER 0x0000
|
||||
+#define TIMER_FLAG_COUNTER 0x0002
|
||||
+/* Stop or continue when overflowing/underflowing. */
|
||||
+#define TIMER_FLAG_ONCE 0x0000
|
||||
+#define TIMER_FLAG_CYCLIC 0x0004
|
||||
+/* Count up or counter down. */
|
||||
+#define TIMER_FLAG_UP 0x0000
|
||||
+#define TIMER_FLAG_DOWN 0x0008
|
||||
+/* Count on specific level or edge. */
|
||||
+#define TIMER_FLAG_HIGH_LEVEL_SENSITIVE 0x0000
|
||||
+#define TIMER_FLAG_LOW_LEVEL_SENSITIVE 0x0040
|
||||
+#define TIMER_FLAG_RISE_EDGE 0x0010
|
||||
+#define TIMER_FLAG_FALL_EDGE 0x0020
|
||||
+#define TIMER_FLAG_ANY_EDGE 0x0030
|
||||
+/* Signal is syncronous to module clock or not. */
|
||||
+#define TIMER_FLAG_UNSYNC 0x0000
|
||||
+#define TIMER_FLAG_SYNC 0x0080
|
||||
+/* Different interrupt handle type. */
|
||||
+#define TIMER_FLAG_NO_HANDLE 0x0000
|
||||
+#if defined(__KERNEL__)
|
||||
+ #define TIMER_FLAG_CALLBACK_IN_IRQ 0x0100
|
||||
+#endif // defined(__KERNEL__)
|
||||
+#define TIMER_FLAG_SIGNAL 0x0300
|
||||
+/* Internal clock source or external clock source */
|
||||
+#define TIMER_FLAG_INT_SRC 0x0000
|
||||
+#define TIMER_FLAG_EXT_SRC 0x1000
|
||||
+
|
||||
+
|
||||
+/*
|
||||
+ * ioctl Command
|
||||
+ */
|
||||
+#define GPTU_REQUEST_TIMER 0x01 /* General method to setup timer/counter. */
|
||||
+#define GPTU_FREE_TIMER 0x02 /* Free timer/counter. */
|
||||
+#define GPTU_START_TIMER 0x03 /* Start or resume timer/counter. */
|
||||
+#define GPTU_STOP_TIMER 0x04 /* Suspend timer/counter. */
|
||||
+#define GPTU_GET_COUNT_VALUE 0x05 /* Get current count value. */
|
||||
+#define GPTU_CALCULATE_DIVIDER 0x06 /* Calculate timer divider from given freq.*/
|
||||
+#define GPTU_SET_TIMER 0x07 /* Simplified method to setup timer. */
|
||||
+#define GPTU_SET_COUNTER 0x08 /* Simplified method to setup counter. */
|
||||
+
|
||||
+/*
|
||||
+ * Data Type Used to Call ioctl
|
||||
+ */
|
||||
+struct gptu_ioctl_param {
|
||||
+ unsigned int timer; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
|
||||
+ * GPTU_SET_COUNTER, this field is ID of expected *
|
||||
+ * timer/counter. If it's zero, a timer/counter would *
|
||||
+ * be dynamically allocated and ID would be stored in *
|
||||
+ * this field. *
|
||||
+ * In command GPTU_GET_COUNT_VALUE, this field is *
|
||||
+ * ignored. *
|
||||
+ * In other command, this field is ID of timer/counter *
|
||||
+ * allocated. */
|
||||
+ unsigned int flag; /* In command GPTU_REQUEST_TIMER, GPTU_SET_TIMER, and *
|
||||
+ * GPTU_SET_COUNTER, this field contains flags to *
|
||||
+ * specify how to configure timer/counter. *
|
||||
+ * In command GPTU_START_TIMER, zero indicate start *
|
||||
+ * and non-zero indicate resume timer/counter. *
|
||||
+ * In other command, this field is ignored. */
|
||||
+ unsigned long value; /* In command GPTU_REQUEST_TIMER, this field contains *
|
||||
+ * init/reload value. *
|
||||
+ * In command GPTU_SET_TIMER, this field contains *
|
||||
+ * frequency (0.001Hz) of timer. *
|
||||
+ * In command GPTU_GET_COUNT_VALUE, current count *
|
||||
+ * value would be stored in this field. *
|
||||
+ * In command GPTU_CALCULATE_DIVIDER, this field *
|
||||
+ * contains frequency wanted, and after calculation, *
|
||||
+ * divider would be stored in this field to overwrite *
|
||||
+ * the frequency. *
|
||||
+ * In other command, this field is ignored. */
|
||||
+ int pid; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
|
||||
+ * if signal is required, this field contains process *
|
||||
+ * ID to which signal would be sent. *
|
||||
+ * In other command, this field is ignored. */
|
||||
+ int sig; /* In command GPTU_REQUEST_TIMER and GPTU_SET_TIMER, *
|
||||
+ * if signal is required, this field contains signal *
|
||||
+ * number which would be sent. *
|
||||
+ * In other command, this field is ignored. */
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * ####################################
|
||||
+ * Data Type
|
||||
+ * ####################################
|
||||
+ */
|
||||
+typedef void (*timer_callback)(unsigned long arg);
|
||||
+
|
||||
+extern int lq_request_timer(unsigned int, unsigned int, unsigned long, unsigned long, unsigned long);
|
||||
+extern int lq_free_timer(unsigned int);
|
||||
+extern int lq_start_timer(unsigned int, int);
|
||||
+extern int lq_stop_timer(unsigned int);
|
||||
+extern int lq_reset_counter_flags(u32 timer, u32 flags);
|
||||
+extern int lq_get_count_value(unsigned int, unsigned long *);
|
||||
+extern u32 lq_cal_divider(unsigned long);
|
||||
+extern int lq_set_timer(unsigned int, unsigned int, int, int, unsigned int, unsigned long, unsigned long);
|
||||
+extern int lq_set_counter(unsigned int timer, unsigned int flag,
|
||||
+ u32 reload, unsigned long arg1, unsigned long arg2);
|
||||
+
|
||||
+#endif /* __DANUBE_GPTU_DEV_H__2005_07_26__10_19__ */
|
||||
--- a/arch/mips/lantiq/xway/Makefile
|
||||
+++ b/arch/mips/lantiq/xway/Makefile
|
||||
@@ -1,4 +1,4 @@
|
||||
-obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o
|
||||
+obj-y := pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o devices.o dma.o timer.o
|
||||
|
||||
obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o setup-xway.o
|
||||
obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o setup-ase.o
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,547 @@
|
|||
--- a/arch/mips/lantiq/xway/Kconfig
|
||||
+++ b/arch/mips/lantiq/xway/Kconfig
|
||||
@@ -6,6 +6,10 @@
|
||||
bool "Easy50712 - Danube"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_ARV45XX
|
||||
+ bool "ARV45XX"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/xway/Makefile
|
||||
+++ b/arch/mips/lantiq/xway/Makefile
|
||||
@@ -5,3 +5,4 @@
|
||||
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/xway/mach-arv45xx.c
|
||||
@@ -0,0 +1,504 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ *
|
||||
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio_buttons.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/mtd/physmap.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/etherdevice.h>
|
||||
+#include <linux/ath5k_platform.h>
|
||||
+#include <linux/pci.h>
|
||||
+
|
||||
+#include <lantiq_soc.h>
|
||||
+#include <lantiq_platform.h>
|
||||
+
|
||||
+#include "../machtypes.h"
|
||||
+#include "devices.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+#include "dev-dwc_otg.h"
|
||||
+
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+static struct mtd_partition arv4510_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x20000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x20000,
|
||||
+ .size = 0x120000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x40000,
|
||||
+ .size = 0xfa0000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "board_config",
|
||||
+ .offset = 0xfe0000,
|
||||
+ .size = 0x20000,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct mtd_partition arv45xx_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x20000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x20000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x30000,
|
||||
+ .size = 0x3c0000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "board_config",
|
||||
+ .offset = 0x3f0000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct mtd_partition arv75xx_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x0,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot_env",
|
||||
+ .offset = 0x10000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x20000,
|
||||
+ .size = 0x7d0000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "board_config",
|
||||
+ .offset = 0x7f0000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
+static struct physmap_flash_data arv4510_flash_data = {
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .nr_parts = ARRAY_SIZE(arv4510_partitions),
|
||||
+ .parts = arv4510_partitions,
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct physmap_flash_data arv45xx_flash_data = {
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .nr_parts = ARRAY_SIZE(arv45xx_partitions),
|
||||
+ .parts = arv45xx_partitions,
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct physmap_flash_data arv75xx_flash_data = {
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .nr_parts = ARRAY_SIZE(arv75xx_partitions),
|
||||
+ .parts = arv75xx_partitions,
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct ltq_pci_data ltq_pci_data = {
|
||||
+ .clock = PCI_CLOCK_EXT,
|
||||
+ .gpio = PCI_GNT1 | PCI_REQ1,
|
||||
+ .irq = {
|
||||
+ [14] = INT_NUM_IM0_IRL0 + 22,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct ltq_eth_data ltq_eth_data = {
|
||||
+ .mii_mode = PHY_INTERFACE_MODE_RMII,
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv4510pw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:green:foo", .gpio = 4, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv4518pw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:green:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:fail", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:voip", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:fxs1", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:fxs2", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_button
|
||||
+arv4518pw_gpio_buttons[] __initdata = {
|
||||
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 28, .active_low = 1, },
|
||||
+ { .desc = "wps", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 29, .active_low = 1, },
|
||||
+ { .desc = "reset", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 30, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv4520pw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, },
|
||||
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, },
|
||||
+ { .name = "soc:blue:internet", .gpio = 5, .active_low = 1, },
|
||||
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, },
|
||||
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, },
|
||||
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, },
|
||||
+ { .name = "soc:blue:voip", .gpio = 72, .active_low = 1, },
|
||||
+ { .name = "soc:blue:fxs1", .gpio = 73, .active_low = 1, },
|
||||
+ { .name = "soc:blue:fxs2", .gpio = 74, .active_low = 1, },
|
||||
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, },
|
||||
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, },
|
||||
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, },
|
||||
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv452cpw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:adsl", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:isdn", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:yellow:wps", .gpio = 7, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:wps", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:fxs1", .gpio = 72, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:fxs2", .gpio = 73, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:wps", .gpio = 74, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:internet", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:internet", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv4525pw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:green:festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:wlan", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv752dpw22_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:power", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:wps", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:fxo", .gpio = 75, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:red:voice", .gpio = 76, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:usb", .gpio = 77, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:wlan", .gpio = 78, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:wlan1", .gpio = 79, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:wlan", .gpio = 80, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:blue:wlan1", .gpio = 81, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:eth1", .gpio = 83, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:eth2", .gpio = 84, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:eth3", .gpio = 85, .active_low = 1, .default_trigger = "default-on" },
|
||||
+ { .name = "soc:green:eth4", .gpio = 86, .active_low = 1, .default_trigger = "default-on", },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_button
|
||||
+arv752dpw22_gpio_buttons[] __initdata = {
|
||||
+ { .desc = "btn0", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 12, .active_low = 1, },
|
||||
+ { .desc = "btn1", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 13, .active_low = 1, },
|
||||
+ { .desc = "btn2", .type = EV_KEY, .code = BTN_2, .threshold = 3, .gpio = 28, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_led
|
||||
+arv7518pw_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:green:power", .gpio = 2, .active_low = 1, },
|
||||
+ { .name = "soc:green:adsl", .gpio = 4, .active_low = 1, },
|
||||
+ { .name = "soc:green:internet", .gpio = 5, .active_low = 1, },
|
||||
+ { .name = "soc:green:wlan", .gpio = 6, .active_low = 1, },
|
||||
+ { .name = "soc:red:internet", .gpio = 8, .active_low = 1, },
|
||||
+ { .name = "soc:green:usb", .gpio = 19, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static struct gpio_button
|
||||
+arv7518pw_gpio_buttons[] __initdata = {
|
||||
+ { .desc = "reset", .type = EV_KEY, .code = BTN_0, .threshold = 3, .gpio = 23, .active_low = 1, },
|
||||
+ { .desc = "wlan", .type = EV_KEY, .code = BTN_1, .threshold = 3, .gpio = 25, .active_low = 1, },
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+arv45xx_register_ethernet(void)
|
||||
+{
|
||||
+#define ARV45XX_BRN_MAC 0x3f0016
|
||||
+ memcpy_fromio(<q_eth_data.mac.sa_data,
|
||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
|
||||
+ ltq_register_etop(<q_eth_data);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+arv75xx_register_ethernet(void)
|
||||
+{
|
||||
+#define ARV75XX_BRN_MAC 0x7f0016
|
||||
+ memcpy_fromio(<q_eth_data.mac.sa_data,
|
||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV75XX_BRN_MAC), 6);
|
||||
+ ltq_register_etop(<q_eth_data);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+bewan_register_ethernet(void)
|
||||
+{
|
||||
+#define BEWAN_BRN_MAC 0x3f0014
|
||||
+ memcpy_fromio(<q_eth_data.mac.sa_data,
|
||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + BEWAN_BRN_MAC), 6);
|
||||
+ ltq_register_etop(<q_eth_data);
|
||||
+}
|
||||
+
|
||||
+static u16 arv45xx_ath5k_eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
|
||||
+static struct ath5k_platform_data arv45xx_ath5k_platform_data;
|
||||
+
|
||||
+/*static int arv45xx_pci_plat_dev_init(struct pci_dev *dev)
|
||||
+{
|
||||
+ dev->dev.platform_data = &arv45xx_ath5k_platform_data;
|
||||
+ return 0;
|
||||
+}
|
||||
+*/
|
||||
+void __init
|
||||
+arv45xx_register_ath5k(void)
|
||||
+{
|
||||
+#define ARV45XX_BRN_ATH 0x3f0478
|
||||
+ int i;
|
||||
+ unsigned char eeprom_mac[6];
|
||||
+ static u16 eeprom_data[ATH5K_PLAT_EEP_MAX_WORDS];
|
||||
+ u32 *p = (u32*)arv45xx_ath5k_eeprom_data;
|
||||
+
|
||||
+ memcpy_fromio(eeprom_mac,
|
||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_MAC), 6);
|
||||
+ eeprom_mac[5]++;
|
||||
+ memcpy_fromio(arv45xx_ath5k_eeprom_data,
|
||||
+ (void *)KSEG1ADDR(LTQ_FLASH_START + ARV45XX_BRN_ATH), ATH5K_PLAT_EEP_MAX_WORDS);
|
||||
+ // swap eeprom bytes
|
||||
+ for (i = 0; i < ATH5K_PLAT_EEP_MAX_WORDS>>1; i++){
|
||||
+ //arv4518_ath5k_eeprom_data[i] = ((eeprom_data[i]&0xff)<<8)|((eeprom_data[i]&0xff00)>>8);
|
||||
+ p[i] = ((eeprom_data[(i<<1)+1]&0xff)<<24)|((eeprom_data[(i<<1)+1]&0xff00)<<8)|((eeprom_data[i<<1]&0xff)<<8)|((eeprom_data[i<<1]&0xff00)>>8);
|
||||
+ if (i == 0xbf>>1){
|
||||
+ // printk ("regdomain: 0x%x --> 0x%x\n", p[i], (p[i] & 0xffff0000)|0x67);
|
||||
+ /* regdomain is invalid?? how did original fw convert
|
||||
+ * value to 0x82d4 ??
|
||||
+ * for now, force to 0x67 */
|
||||
+ p[i] &= 0xffff0000;
|
||||
+ p[i] |= 0x67;
|
||||
+ }
|
||||
+ }
|
||||
+ arv45xx_ath5k_platform_data.eeprom_data = arv45xx_ath5k_eeprom_data;
|
||||
+ arv45xx_ath5k_platform_data.macaddr = eeprom_mac;
|
||||
+ //lqpci_plat_dev_init = arv45xx_pci_plat_dev_init;
|
||||
+}
|
||||
+
|
||||
+static void __init
|
||||
+arv3527p_init(void)
|
||||
+{
|
||||
+ ltq_register_gpio_stp();
|
||||
+ //ltq_add_device_leds_gpio(arv3527p_leds_gpio, ARRAY_SIZE(arv3527p_leds_gpio));
|
||||
+ ltq_register_nor(&arv45xx_flash_data);
|
||||
+ arv45xx_register_ethernet();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV3527P,
|
||||
+ "ARV3527P",
|
||||
+ "ARV3527P - Arcor Easybox 401",
|
||||
+ arv3527p_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv4510pw_init(void)
|
||||
+{
|
||||
+ ltq_register_gpio_stp();
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4510pw_leds_gpio), arv4510pw_leds_gpio);
|
||||
+ ltq_register_nor(&arv4510_flash_data);
|
||||
+ ltq_pci_data.irq[12] = (INT_NUM_IM2_IRL0 + 31);
|
||||
+ ltq_pci_data.irq[15] = (INT_NUM_IM0_IRL0 + 26);
|
||||
+ ltq_pci_data.gpio |= PCI_EXIN2 | PCI_REQ2;
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ bewan_register_ethernet();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV4510PW,
|
||||
+ "ARV4510PW",
|
||||
+ "ARV4510PW - Wippies Homebox",
|
||||
+ arv4510pw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv4518pw_init(void)
|
||||
+{
|
||||
+#define ARV4518PW_EBU 0
|
||||
+#define ARV4518PW_USB 14
|
||||
+#define ARV4518PW_SWITCH_RESET 13
|
||||
+
|
||||
+ ltq_register_gpio_ebu(ARV4518PW_EBU);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4518pw_leds_gpio), arv4518pw_leds_gpio);
|
||||
+ ltq_register_gpio_buttons(arv4518pw_gpio_buttons, ARRAY_SIZE(arv4518pw_gpio_buttons));
|
||||
+ ltq_register_nor(&arv45xx_flash_data);
|
||||
+ ltq_pci_data.gpio = PCI_GNT2 | PCI_REQ2;
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_madwifi_eep();
|
||||
+ xway_register_dwc(ARV4518PW_USB);
|
||||
+ arv45xx_register_ethernet();
|
||||
+ arv45xx_register_ath5k();
|
||||
+
|
||||
+ gpio_request(ARV4518PW_SWITCH_RESET, "switch");
|
||||
+ gpio_direction_output(ARV4518PW_SWITCH_RESET, 1);
|
||||
+ gpio_export(ARV4518PW_SWITCH_RESET, 0);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV4518PW,
|
||||
+ "ARV4518PW",
|
||||
+ "ARV4518PW - SMC7908A-ISP, Airties WAV-221",
|
||||
+ arv4518pw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv4520pw_init(void)
|
||||
+{
|
||||
+#define ARV4520PW_EBU 0x400
|
||||
+#define ARV4520PW_USB 28
|
||||
+#define ARV4520PW_SWITCH_RESET 82
|
||||
+
|
||||
+ ltq_register_gpio_ebu(ARV4520PW_EBU);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4520pw_leds_gpio), arv4520pw_leds_gpio);
|
||||
+ ltq_register_nor(&arv45xx_flash_data);
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_tapi();
|
||||
+ arv45xx_register_ethernet();
|
||||
+ xway_register_dwc(ARV4520PW_USB);
|
||||
+
|
||||
+ gpio_request(ARV4520PW_SWITCH_RESET, "switch");
|
||||
+ gpio_set_value(ARV4520PW_SWITCH_RESET, 1);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV4520PW,
|
||||
+ "ARV4520PW",
|
||||
+ "ARV4520PW - Airties WAV-281, Arcor A800",
|
||||
+ arv4520pw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv452Cpw_init(void)
|
||||
+{
|
||||
+#define ARV452CPW_EBU 0x77f
|
||||
+#define ARV452CPW_USB 28
|
||||
+#define ARV452CPW_RELAY1 31
|
||||
+#define ARV452CPW_RELAY2 79
|
||||
+#define ARV452CPW_SWITCH_RESET 82
|
||||
+
|
||||
+ ltq_register_gpio_ebu(ARV452CPW_EBU);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv452cpw_leds_gpio), arv452cpw_leds_gpio);
|
||||
+ ltq_register_nor(&arv45xx_flash_data);
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_madwifi_eep();
|
||||
+ xway_register_dwc(ARV452CPW_USB);
|
||||
+ arv45xx_register_ethernet();
|
||||
+ arv45xx_register_ath5k();
|
||||
+
|
||||
+ gpio_request(ARV452CPW_SWITCH_RESET, "switch");
|
||||
+ gpio_set_value(ARV452CPW_SWITCH_RESET, 1);
|
||||
+ gpio_export(ARV452CPW_SWITCH_RESET, 0);
|
||||
+
|
||||
+ gpio_request(ARV452CPW_RELAY1, "relay1");
|
||||
+ gpio_direction_output(ARV452CPW_RELAY1, 1);
|
||||
+ gpio_export(ARV452CPW_RELAY1, 0);
|
||||
+
|
||||
+ gpio_request(ARV452CPW_RELAY2, "relay2");
|
||||
+ gpio_set_value(ARV452CPW_RELAY2, 1);
|
||||
+ gpio_export(ARV452CPW_RELAY2, 0);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV452CPW,
|
||||
+ "ARV452CPW",
|
||||
+ "ARV452CPW - Arcor A801",
|
||||
+ arv452Cpw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv4525pw_init(void)
|
||||
+{
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv4525pw_leds_gpio), arv4525pw_leds_gpio);
|
||||
+ ltq_register_nor(&arv45xx_flash_data);
|
||||
+ ltq_pci_data.clock = PCI_CLOCK_INT;
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_madwifi_eep();
|
||||
+ ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
|
||||
+ arv45xx_register_ethernet();
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV4525PW,
|
||||
+ "ARV4525PW",
|
||||
+ "ARV4525PW - Speedport W502V",
|
||||
+ arv4525pw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv7518pw_init(void)
|
||||
+{
|
||||
+#define ARV7518PW_EBU 0x2
|
||||
+#define ARV7518PW_USB 14
|
||||
+
|
||||
+ ltq_register_gpio_ebu(ARV7518PW_EBU);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv7518pw_leds_gpio), arv7518pw_leds_gpio);
|
||||
+ ltq_register_gpio_buttons(arv7518pw_gpio_buttons, ARRAY_SIZE(arv7518pw_gpio_buttons));
|
||||
+ ltq_register_nor(&arv75xx_flash_data);
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_tapi();
|
||||
+ xway_register_dwc(ARV7518PW_USB);
|
||||
+ arv75xx_register_ethernet();
|
||||
+ //arv7518_register_ath9k(mac);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV7518PW,
|
||||
+ "ARV7518PW",
|
||||
+ "ARV7518PW - ASTORIA",
|
||||
+ arv7518pw_init);
|
||||
+
|
||||
+static void __init
|
||||
+arv752dpw22_init(void)
|
||||
+{
|
||||
+#define ARV752DPW22_EBU 0x2
|
||||
+#define ARV752DPW22_USB 72
|
||||
+#define ARV752DPW22_RELAY 73
|
||||
+
|
||||
+ ltq_register_gpio_ebu(ARV752DPW22_EBU);
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(arv752dpw22_leds_gpio), arv752dpw22_leds_gpio);
|
||||
+ ltq_register_gpio_buttons(arv752dpw22_gpio_buttons, ARRAY_SIZE(arv752dpw22_gpio_buttons));
|
||||
+ ltq_register_nor(&arv75xx_flash_data);
|
||||
+ ltq_pci_data.irq[15] = (INT_NUM_IM2_IRL0 + 31);
|
||||
+ ltq_pci_data.gpio |= PCI_EXIN1 | PCI_REQ2;
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ xway_register_dwc(ARV752DPW22_USB);
|
||||
+ arv75xx_register_ethernet();
|
||||
+
|
||||
+ gpio_request(ARV752DPW22_RELAY, "relay");
|
||||
+ gpio_set_value(ARV752DPW22_RELAY, 1);
|
||||
+ gpio_export(ARV752DPW22_RELAY, 0);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_ARV752DPW22,
|
||||
+ "ARV752DPW22",
|
||||
+ "ARV752DPW22 - Arcor A803",
|
||||
+ arv752dpw22_init);
|
||||
--- a/arch/mips/lantiq/machtypes.h
|
||||
+++ b/arch/mips/lantiq/machtypes.h
|
||||
@@ -22,6 +22,17 @@
|
||||
LANTIQ_MACH_EASY98000NAND, /* Falcon Eval Board, NAND Flash */
|
||||
LANTIQ_MACH_EASY98020, /* Falcon Reference Board */
|
||||
LANTIQ_MACH_95C3AM1, /* Board 95C3AM1 */
|
||||
+
|
||||
+ /* Arcadyan */
|
||||
+ LANTIQ_MACH_ARV3527P, /* Arcor easybox a401 */
|
||||
+ LANTIQ_MACH_ARV4510PW, /* Wippies Homebox */
|
||||
+ LANTIQ_MACH_ARV4518PW, /* Airties WAV-221, SMC-7908A-ISP */
|
||||
+ LANTIQ_MACH_ARV4520PW, /* Airties WAV-281, Arcor EasyboxA800 */
|
||||
+ LANTIQ_MACH_ARV452CPW, /* Arcor EasyboxA801 */
|
||||
+ LANTIQ_MACH_ARV4525PW, /* Speedport W502V */
|
||||
+ LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
|
||||
+ LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
|
||||
+ LANTIQ_MACH_ARV7518PW, /* ASTORIA */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
--- a/arch/mips/lantiq/machtypes.h
|
||||
+++ b/arch/mips/lantiq/machtypes.h
|
||||
@@ -33,6 +33,9 @@
|
||||
LANTIQ_MACH_ARV752DPW, /* Arcor easybox a802 */
|
||||
LANTIQ_MACH_ARV752DPW22, /* Arcor easybox a803 */
|
||||
LANTIQ_MACH_ARV7518PW, /* ASTORIA */
|
||||
+
|
||||
+ /* Netgear */
|
||||
+ LANTIQ_MACH_DGN3500B, /* Netgear DGN3500 */
|
||||
};
|
||||
|
||||
#endif
|
||||
--- a/arch/mips/lantiq/xway/Kconfig
|
||||
+++ b/arch/mips/lantiq/xway/Kconfig
|
||||
@@ -10,6 +10,10 @@
|
||||
bool "ARV45XX"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_NETGEAR
|
||||
+ bool "Netgear"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/xway/Makefile
|
||||
+++ b/arch/mips/lantiq/xway/Makefile
|
||||
@@ -6,3 +6,4 @@
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY50712) += mach-easy50712.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/xway/mach-netgear.c
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ *
|
||||
+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/mtd/physmap.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+
|
||||
+#include <lantiq_soc.h>
|
||||
+#include <irq.h>
|
||||
+
|
||||
+#include "../machtypes.h"
|
||||
+#include "devices.h"
|
||||
+
|
||||
+static struct ltq_pci_data ltq_pci_data = {
|
||||
+ .clock = PCI_CLOCK_INT,
|
||||
+ .gpio = PCI_GNT1 | PCI_REQ1,
|
||||
+ .irq = {
|
||||
+ [14] = INT_NUM_IM0_IRL0 + 22,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct ltq_eth_data ltq_eth_data = {
|
||||
+ .mii_mode = PHY_INTERFACE_MODE_MII,
|
||||
+};
|
||||
+
|
||||
+struct spi_board_info spi_info = {
|
||||
+ .bus_num = 0,
|
||||
+ .chip_select = 3,
|
||||
+ .max_speed_hz = 25000000,
|
||||
+ .modalias = "mx25l12805d",
|
||||
+};
|
||||
+
|
||||
+struct ltq_spi_platform_data ltq_spi_data = {
|
||||
+ .num_chipselect = 4,
|
||||
+};
|
||||
+
|
||||
+static void __init dgn3500_init(void)
|
||||
+{
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_etop(<q_eth_data);
|
||||
+ ltq_register_spi(<q_spi_data, &spi_info, 1);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_DGN3500B,
|
||||
+ "DGN3500B",
|
||||
+ "Netgear DGN3500B",
|
||||
+ dgn3500_init);
|
|
@ -0,0 +1,148 @@
|
|||
--- a/arch/mips/lantiq/xway/Kconfig
|
||||
+++ b/arch/mips/lantiq/xway/Kconfig
|
||||
@@ -14,6 +14,10 @@
|
||||
bool "Netgear"
|
||||
default y
|
||||
|
||||
+config LANTIQ_MACH_GIGASX76X
|
||||
+ bool "GIGASX76X"
|
||||
+ default y
|
||||
+
|
||||
endmenu
|
||||
|
||||
endif
|
||||
--- a/arch/mips/lantiq/xway/Makefile
|
||||
+++ b/arch/mips/lantiq/xway/Makefile
|
||||
@@ -7,3 +7,4 @@
|
||||
obj-$(CONFIG_LANTIQ_MACH_EASY50601) += mach-easy50601.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_ARV45XX) += mach-arv45xx.o
|
||||
obj-$(CONFIG_LANTIQ_MACH_NETGEAR) += mach-netgear.o
|
||||
+obj-$(CONFIG_LANTIQ_MACH_GIGASX76X) += mach-gigasx76x.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/xway/mach-gigasx76x.c
|
||||
@@ -0,0 +1,113 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ *
|
||||
+ * Copyright (C) 2011 Andrej Vlašić
|
||||
+ * Copyright (C) 2011 Luka Perkov
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/gpio_buttons.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/mtd/physmap.h>
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/ath5k_platform.h>
|
||||
+#include <linux/pci.h>
|
||||
+#include <linux/phy.h>
|
||||
+
|
||||
+#include <irq.h>
|
||||
+
|
||||
+#include <lantiq_soc.h>
|
||||
+#include <lantiq_platform.h>
|
||||
+
|
||||
+#include "../machtypes.h"
|
||||
+#include "devices.h"
|
||||
+#include "dev-dwc_otg.h"
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+static struct mtd_partition gigasx76x_partitions[] =
|
||||
+{
|
||||
+ {
|
||||
+ .name = "secondary_env",
|
||||
+ .offset = 0xe000,
|
||||
+ .size = 0x2000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "secondary_boot",
|
||||
+ .offset = 0x10000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "uboot",
|
||||
+ .offset = 0x20000,
|
||||
+ .size = 0x30000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "linux",
|
||||
+ .offset = 0x50000,
|
||||
+ .size = 0x7a0000,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "board_config",
|
||||
+ .offset = 0x7f0000,
|
||||
+ .size = 0x10000,
|
||||
+ },
|
||||
+};
|
||||
+#endif
|
||||
+
|
||||
+static struct gpio_led
|
||||
+gigasx76x_leds_gpio[] __initdata = {
|
||||
+ { .name = "soc:green:usb", .gpio = 50, },
|
||||
+ { .name = "soc:green:wlan", .gpio = 51, },
|
||||
+ { .name = "soc:green:phone2", .gpio = 52, },
|
||||
+ { .name = "soc:green:phone1", .gpio = 53, },
|
||||
+ { .name = "soc:green:line", .gpio = 54, },
|
||||
+ { .name = "soc:green:online", .gpio = 55, },
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static struct physmap_flash_data gigasx76x_flash_data = {
|
||||
+#ifdef CONFIG_MTD_PARTITIONS
|
||||
+ .nr_parts = ARRAY_SIZE(gigasx76x_partitions),
|
||||
+ .parts = gigasx76x_partitions,
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct ltq_pci_data ltq_pci_data = {
|
||||
+ .clock = PCI_CLOCK_INT,
|
||||
+ .gpio = PCI_GNT1 | PCI_REQ1,
|
||||
+ .irq = {
|
||||
+ [14] = INT_NUM_IM0_IRL0 + 22,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static struct ltq_eth_data ltq_eth_data = {
|
||||
+ .mii_mode = PHY_INTERFACE_MODE_MII,
|
||||
+};
|
||||
+
|
||||
+static void __init
|
||||
+gigasx76x_init(void)
|
||||
+{
|
||||
+#define GIGASX76X_USB 29
|
||||
+
|
||||
+ ltq_register_gpio_stp();
|
||||
+ ltq_register_nor(&gigasx76x_flash_data);
|
||||
+ ltq_register_pci(<q_pci_data);
|
||||
+ ltq_register_etop(<q_eth_data);
|
||||
+ xway_register_dwc(GIGASX76X_USB);
|
||||
+ ltq_register_tapi();
|
||||
+ ltq_register_madwifi_eep();
|
||||
+ ltq_add_device_leds_gpio(-1, ARRAY_SIZE(gigasx76x_leds_gpio), gigasx76x_leds_gpio);
|
||||
+}
|
||||
+
|
||||
+MIPS_MACHINE(LANTIQ_MACH_GIGASX76X,
|
||||
+ "GIGASX76X",
|
||||
+ "GIGASX76X - Gigaset SX761,SX762,SX763",
|
||||
+ gigasx76x_init);
|
||||
--- a/arch/mips/lantiq/machtypes.h
|
||||
+++ b/arch/mips/lantiq/machtypes.h
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
/* Netgear */
|
||||
LANTIQ_MACH_DGN3500B, /* Netgear DGN3500 */
|
||||
+
|
||||
+ /* Gigaset */
|
||||
+ LANTIQ_MACH_GIGASX76X, /* Gigaset SX76x */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
--- a/arch/mips/lantiq/xway/devices.c
|
||||
+++ b/arch/mips/lantiq/xway/devices.c
|
||||
@@ -121,6 +121,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
+/* madwifi */
|
||||
+int lantiq_emulate_madwifi_eep = 0;
|
||||
+EXPORT_SYMBOL(lantiq_emulate_madwifi_eep);
|
||||
+
|
||||
+void __init
|
||||
+ltq_register_madwifi_eep(void)
|
||||
+{
|
||||
+ lantiq_emulate_madwifi_eep = 1;
|
||||
+}
|
||||
+
|
||||
static struct resource ltq_spi_resources[] = {
|
||||
{
|
||||
.start = LTQ_SSC_BASE_ADDR,
|
||||
--- a/arch/mips/lantiq/xway/devices.h
|
||||
+++ b/arch/mips/lantiq/xway/devices.h
|
||||
@@ -19,5 +19,6 @@
|
||||
extern void ltq_register_etop(struct ltq_eth_data *eth);
|
||||
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
||||
struct spi_board_info const *info, unsigned n);
|
||||
+extern void ltq_register_madwifi_eep(void);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,46 @@
|
|||
--- a/arch/mips/lantiq/xway/devices.c
|
||||
+++ b/arch/mips/lantiq/xway/devices.c
|
||||
@@ -131,6 +131,26 @@
|
||||
lantiq_emulate_madwifi_eep = 1;
|
||||
}
|
||||
|
||||
+/* gpio buttons */
|
||||
+static struct gpio_buttons_platform_data ltq_gpio_buttons_platform_data;
|
||||
+
|
||||
+static struct platform_device ltq_gpio_buttons_platform_device =
|
||||
+{
|
||||
+ .name = "gpio-buttons",
|
||||
+ .id = 0,
|
||||
+ .dev = {
|
||||
+ .platform_data = (void *) <q_gpio_buttons_platform_data,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+void __init
|
||||
+ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt)
|
||||
+{
|
||||
+ ltq_gpio_buttons_platform_data.buttons = buttons;
|
||||
+ ltq_gpio_buttons_platform_data.nbuttons = cnt;
|
||||
+ platform_device_register(<q_gpio_buttons_platform_device);
|
||||
+}
|
||||
+
|
||||
static struct resource ltq_spi_resources[] = {
|
||||
{
|
||||
.start = LTQ_SSC_BASE_ADDR,
|
||||
--- a/arch/mips/lantiq/xway/devices.h
|
||||
+++ b/arch/mips/lantiq/xway/devices.h
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "../devices.h"
|
||||
#include <linux/phy.h>
|
||||
#include <linux/spi/spi.h>
|
||||
+#include <linux/gpio_buttons.h>
|
||||
|
||||
extern void ltq_register_gpio(void);
|
||||
extern void ltq_register_gpio_stp(void);
|
||||
@@ -20,5 +21,6 @@
|
||||
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
||||
struct spi_board_info const *info, unsigned n);
|
||||
extern void ltq_register_madwifi_eep(void);
|
||||
+extern void ltq_register_gpio_buttons(struct gpio_button *buttons, int cnt);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
--- a/arch/mips/lantiq/devices.c
|
||||
+++ b/arch/mips/lantiq/devices.c
|
||||
@@ -120,3 +120,20 @@
|
||||
pr_err("kernel is compiled without PCI support\n");
|
||||
}
|
||||
#endif
|
||||
+
|
||||
+static unsigned int *cp1_base = 0;
|
||||
+unsigned int*
|
||||
+ltq_get_cp1_base(void)
|
||||
+{
|
||||
+ return cp1_base;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ltq_get_cp1_base);
|
||||
+
|
||||
+void __init
|
||||
+ltq_register_tapi(void)
|
||||
+{
|
||||
+#define CP1_SIZE (1 << 20)
|
||||
+ dma_addr_t dma;
|
||||
+ cp1_base =
|
||||
+ (void*)CPHYSADDR(dma_alloc_coherent(NULL, CP1_SIZE, &dma, GFP_ATOMIC));
|
||||
+}
|
||||
--- a/arch/mips/lantiq/devices.h
|
||||
+++ b/arch/mips/lantiq/devices.h
|
||||
@@ -19,5 +19,6 @@
|
||||
extern void ltq_register_wdt(void);
|
||||
extern void ltq_register_asc(int port);
|
||||
extern void ltq_register_pci(struct ltq_pci_data *data);
|
||||
+extern void ltq_register_tapi(void);
|
||||
|
||||
#endif
|
||||
--- a/arch/mips/lantiq/xway/mach-easy50712.c
|
||||
+++ b/arch/mips/lantiq/xway/mach-easy50712.c
|
||||
@@ -61,6 +61,7 @@
|
||||
ltq_register_nor(&easy50712_flash_data);
|
||||
ltq_register_pci(<q_pci_data);
|
||||
ltq_register_etop(<q_eth_data);
|
||||
+ ltq_register_tapi();
|
||||
}
|
||||
|
||||
MIPS_MACHINE(LTQ_MACH_EASY50712,
|
|
@ -0,0 +1,95 @@
|
|||
--- /dev/null
|
||||
+++ b/arch/mips/include/asm/mach-lantiq/dev-leds-gpio.h
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * Lantiq GPIO LED device support
|
||||
+ *
|
||||
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published
|
||||
+ * by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _LANTIQ_DEV_LEDS_GPIO_H
|
||||
+#define _LANTIQ_DEV_LEDS_GPIO_H
|
||||
+
|
||||
+#include <linux/leds.h>
|
||||
+
|
||||
+void ltq_add_device_leds_gpio(int id,
|
||||
+ unsigned num_leds,
|
||||
+ struct gpio_led *leds) __init;
|
||||
+
|
||||
+#endif /* _LANTIQ_DEV_LEDS_GPIO_H */
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lantiq/dev-leds-gpio.c
|
||||
@@ -0,0 +1,57 @@
|
||||
+/*
|
||||
+ * Lantiq GPIO LED device support
|
||||
+ *
|
||||
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
||||
+ *
|
||||
+ * Parts of this file are based on Atheros' 2.6.15 BSP
|
||||
+ *
|
||||
+ * 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/slab.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+#include "dev-leds-gpio.h"
|
||||
+
|
||||
+void __init ltq_add_device_leds_gpio(int id, unsigned num_leds,
|
||||
+ struct gpio_led *leds)
|
||||
+{
|
||||
+ struct platform_device *pdev;
|
||||
+ struct gpio_led_platform_data pdata;
|
||||
+ struct gpio_led *p;
|
||||
+ int err;
|
||||
+
|
||||
+ p = kmalloc(num_leds * sizeof(*p), GFP_KERNEL);
|
||||
+ if (!p)
|
||||
+ return;
|
||||
+
|
||||
+ memcpy(p, leds, num_leds * sizeof(*p));
|
||||
+
|
||||
+ pdev = platform_device_alloc("leds-gpio", id);
|
||||
+ if (!pdev)
|
||||
+ goto err_free_leds;
|
||||
+
|
||||
+ memset(&pdata, 0, sizeof(pdata));
|
||||
+ pdata.num_leds = num_leds;
|
||||
+ pdata.leds = p;
|
||||
+
|
||||
+ err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
|
||||
+ if (err)
|
||||
+ goto err_put_pdev;
|
||||
+
|
||||
+ err = platform_device_add(pdev);
|
||||
+ if (err)
|
||||
+ goto err_put_pdev;
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+err_put_pdev:
|
||||
+ platform_device_put(pdev);
|
||||
+
|
||||
+err_free_leds:
|
||||
+ kfree(p);
|
||||
+}
|
||||
--- a/arch/mips/lantiq/Makefile
|
||||
+++ b/arch/mips/lantiq/Makefile
|
||||
@@ -4,7 +4,7 @@
|
||||
# under the terms of the GNU General Public License version 2 as published
|
||||
# by the Free Software Foundation.
|
||||
|
||||
-obj-y := irq.o setup.o clk.o prom.o devices.o
|
||||
+obj-y := irq.o setup.o clk.o prom.o devices.o dev-leds-gpio.o
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
--- a/arch/mips/lantiq/xway/devices.c
|
||||
+++ b/arch/mips/lantiq/xway/devices.c
|
||||
@@ -151,6 +151,29 @@
|
||||
platform_device_register(<q_gpio_buttons_platform_device);
|
||||
}
|
||||
|
||||
+/* ebu */
|
||||
+static struct resource ltq_ebu_resource =
|
||||
+{
|
||||
+ .name = "gpio_ebu",
|
||||
+ .start = LTQ_EBU_GPIO_START,
|
||||
+ .end = LTQ_EBU_GPIO_START + LTQ_EBU_GPIO_SIZE - 1,
|
||||
+ .flags = IORESOURCE_MEM,
|
||||
+};
|
||||
+
|
||||
+static struct platform_device ltq_ebu =
|
||||
+{
|
||||
+ .name = "ltq_ebu",
|
||||
+ .resource = <q_ebu_resource,
|
||||
+ .num_resources = 1,
|
||||
+};
|
||||
+
|
||||
+void __init
|
||||
+ltq_register_gpio_ebu(unsigned int value)
|
||||
+{
|
||||
+ ltq_ebu.dev.platform_data = (void*) value;
|
||||
+ platform_device_register(<q_ebu);
|
||||
+}
|
||||
+
|
||||
static struct resource ltq_spi_resources[] = {
|
||||
{
|
||||
.start = LTQ_SSC_BASE_ADDR,
|
||||
--- a/arch/mips/lantiq/xway/devices.h
|
||||
+++ b/arch/mips/lantiq/xway/devices.h
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
extern void ltq_register_gpio(void);
|
||||
extern void ltq_register_gpio_stp(void);
|
||||
+extern void ltq_register_gpio_ebu(unsigned int value);
|
||||
extern void ltq_register_ase_asc(void);
|
||||
extern void ltq_register_etop(struct ltq_eth_data *eth);
|
||||
extern void ltq_register_spi(struct ltq_spi_platform_data *pdata,
|
|
@ -0,0 +1,51 @@
|
|||
CONFIG_ADM6996_PHY=y
|
||||
CONFIG_AR8216_PHY=y
|
||||
# CONFIG_ARCH_DMA_ADDR_T_64BIT is not set
|
||||
# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
|
||||
# CONFIG_ATH79 is not set
|
||||
CONFIG_GENERIC_ATOMIC64=y
|
||||
CONFIG_GENERIC_IRQ_SHOW=y
|
||||
CONFIG_HAVE_ARCH_JUMP_LABEL=y
|
||||
CONFIG_HAVE_C_RECORDMCOUNT=y
|
||||
CONFIG_HAVE_DMA_API_DEBUG=y
|
||||
CONFIG_HAVE_DMA_ATTRS=y
|
||||
CONFIG_HAVE_DYNAMIC_FTRACE=y
|
||||
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
|
||||
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACER=y
|
||||
CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
|
||||
CONFIG_HAVE_GENERIC_HARDIRQS=y
|
||||
CONFIG_HAVE_IRQ_WORK=y
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_HW_HAS_PCI=y
|
||||
CONFIG_INPUT=y
|
||||
CONFIG_INPUT_EVDEV=y
|
||||
# CONFIG_INPUT_GPIO_BUTTONS is not set
|
||||
CONFIG_INPUT_POLLDEV=y
|
||||
# CONFIG_ISDN is not set
|
||||
CONFIG_LANTIQ_ETOP=y
|
||||
CONFIG_LANTIQ_MACH_ARV45XX=y
|
||||
CONFIG_LANTIQ_MACH_EASY50712=y
|
||||
CONFIG_LANTIQ_MACH_NETGEAR=y
|
||||
CONFIG_LANTIQ_MACH_GIGASX76X=y
|
||||
CONFIG_MACH_NO_WESTBRIDGE=y
|
||||
# CONFIG_MINIX_FS_NATIVE_ENDIAN is not set
|
||||
CONFIG_NEED_DMA_MAP_STATE=y
|
||||
CONFIG_NEED_PER_CPU_KM=y
|
||||
CONFIG_PCI=y
|
||||
CONFIG_PCI_DOMAINS=y
|
||||
CONFIG_PERF_USE_VMALLOC=y
|
||||
# CONFIG_PREEMPT_RCU is not set
|
||||
# CONFIG_QUOTACTL is not set
|
||||
CONFIG_RTL8306_PHY=y
|
||||
# CONFIG_SOC_AMAZON_SE is not set
|
||||
# CONFIG_SOC_FALCON is not set
|
||||
CONFIG_SOC_TYPE_XWAY=y
|
||||
CONFIG_SOC_XWAY=y
|
||||
CONFIG_SPI=y
|
||||
CONFIG_SPI_BITBANG=y
|
||||
# CONFIG_SPI_GPIO is not set
|
||||
CONFIG_SPI_LANTIQ=y
|
||||
CONFIG_SPI_MASTER=y
|
||||
CONFIG_USB_SUPPORT=y
|
||||
CONFIG_XZ_DEC=y
|
Loading…
Reference in New Issue