diff -ruN linux-2.6.31-vanilla/arch/mips/boot/compressed/Makefile linux-2.6.31/arch/mips/boot/compressed/Makefile --- linux-2.6.31-vanilla/arch/mips/boot/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/compressed/Makefile 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,42 @@ +# +# linux/arch/mips/boot/compressed/Makefile +# +# create a compressed zImage from the original vmlinux +# + +targets := zImage vmlinuz vmlinux.bin.gz head.o misc.o piggy.o dummy.o + +OBJS := $(obj)/head.o $(obj)/misc.o + +LD_ARGS := -T $(obj)/ld.script -Ttext 0x80600000 -Bstatic +OBJCOPY_ARGS := -O elf32-tradlittlemips + +ENTRY := $(obj)/../tools/entry +FILESIZE := $(obj)/../tools/filesize + +drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options +strip-flags = $(addprefix --remove-section=,$(drop-sections)) + + +$(obj)/vmlinux.bin.gz: vmlinux + rm -f $(obj)/vmlinux.bin.gz + $(OBJCOPY) -O binary $(strip-flags) vmlinux $(obj)/vmlinux.bin + gzip -v9f $(obj)/vmlinux.bin + +$(obj)/head.o: $(obj)/head.S $(obj)/vmlinux.bin.gz vmlinux + $(CC) $(KBUILD_AFLAGS) \ + -DIMAGESIZE=$(shell sh $(FILESIZE) $(obj)/vmlinux.bin.gz) \ + -DKERNEL_ENTRY=$(shell sh $(ENTRY) $(NM) vmlinux ) \ + -DLOADADDR=$(loadaddr) \ + -c -o $(obj)/head.o $< + +$(obj)/vmlinuz: $(OBJS) $(obj)/ld.script $(obj)/vmlinux.bin.gz $(obj)/dummy.o + $(OBJCOPY) \ + --add-section=.image=$(obj)/vmlinux.bin.gz \ + --set-section-flags=.image=contents,alloc,load,readonly,data \ + $(obj)/dummy.o $(obj)/piggy.o + $(LD) $(LD_ARGS) -o $@ $(OBJS) $(obj)/piggy.o + $(OBJCOPY) $(OBJCOPY_ARGS) $@ $@ -R .comment -R .stab -R .stabstr -R .initrd -R .sysmap + +zImage: $(obj)/vmlinuz + $(OBJCOPY) -O binary $(obj)/vmlinuz $(obj)/zImage diff -ruN linux-2.6.31-vanilla/arch/mips/boot/compressed/dummy.c linux-2.6.31/arch/mips/boot/compressed/dummy.c --- linux-2.6.31-vanilla/arch/mips/boot/compressed/dummy.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/compressed/dummy.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff -ruN linux-2.6.31-vanilla/arch/mips/boot/compressed/head.S linux-2.6.31/arch/mips/boot/compressed/head.S --- linux-2.6.31-vanilla/arch/mips/boot/compressed/head.S 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/compressed/head.S 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,85 @@ +/* + * linux/arch/mips/boot/compressed/head.S + * + * Copyright (C) 2005-2008 Ingenic Semiconductor Inc. + */ + +#include +#include +#include +#include + +#define IndexInvalidate_I 0x00 +#define IndexWriteBack_D 0x01 + + .set noreorder + LEAF(startup) +startup: + move s0, a0 /* Save the boot loader transfered args */ + move s1, a1 + move s2, a2 + move s3, a3 + + la a0, _edata + la a1, _end +1: sw zero, 0(a0) /* Clear BSS section */ + bne a1, a0, 1b + addu a0, 4 + + la sp, (.stack + 8192) + + la a0, __image_begin + la a1, IMAGESIZE + la a2, LOADADDR + la ra, 1f + la k0, decompress_kernel + jr k0 + nop +1: + + move a0, s0 + move a1, s1 + move a2, s2 + move a3, s3 + li k0, KERNEL_ENTRY + jr k0 + nop +2: + b 32 + END(startup) + + + LEAF(flushcaches) + la t0, 1f + la t1, 0xa0000000 + or t0, t0, t1 + jr t0 + nop +1: + li k0, 0x80000000 # start address + li k1, 0x80004000 # end address (16KB I-Cache) + subu k1, 128 + +2: + .set mips3 + cache IndexWriteBack_D, 0(k0) + cache IndexWriteBack_D, 32(k0) + cache IndexWriteBack_D, 64(k0) + cache IndexWriteBack_D, 96(k0) + cache IndexInvalidate_I, 0(k0) + cache IndexInvalidate_I, 32(k0) + cache IndexInvalidate_I, 64(k0) + cache IndexInvalidate_I, 96(k0) + .set mips0 + + bne k0, k1, 2b + addu k0, k0, 128 + la t0, 3f + jr t0 + nop +3: + jr ra + nop + END(flushcaches) + + .comm .stack,4096*2,4 diff -ruN linux-2.6.31-vanilla/arch/mips/boot/compressed/ld.script linux-2.6.31/arch/mips/boot/compressed/ld.script --- linux-2.6.31-vanilla/arch/mips/boot/compressed/ld.script 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/compressed/ld.script 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,151 @@ +OUTPUT_ARCH(mips) +ENTRY(startup) +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + + .init : { *(.init) } =0 + .text : + { + _ftext = . ; + *(.text) + *(.rodata) + *(.rodata1) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0 + .kstrtab : { *(.kstrtab) } + + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + __start___dbe_table = .; /* Exception table for data bus errors */ + __dbe_table : { *(__dbe_table) } + __stop___dbe_table = .; + + __start___ksymtab = .; /* Kernel symbol table */ + __ksymtab : { *(__ksymtab) } + __stop___ksymtab = .; + + _etext = .; + + . = ALIGN(8192); + .data.init_task : { *(.data.init_task) } + + /* Startup code */ + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(16); + __setup_start = .; + .setup.init : { *(.setup.init) } + __setup_end = .; + __initcall_start = .; + .initcall.init : { *(.initcall.init) } + __initcall_end = .; + . = ALIGN(4096); /* Align double page for init_task_union */ + __init_end = .; + + . = ALIGN(4096); + .data.page_aligned : { *(.data.idt) } + + . = ALIGN(32); + .data.cacheline_aligned : { *(.data.cacheline_aligned) } + + .fini : { *(.fini) } =0 + .reginfo : { *(.reginfo) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. It would + be more correct to do this: + . = .; + The current expression does not correctly handle the case of a + text segment ending precisely at the end of a page; it causes the + data segment to skip a page. The above expression does not have + this problem, but it will currently (2/95) cause BFD to allocate + a single segment, combining both text and data, for this case. + This will prevent the text segment from being shared among + multiple executions of the program; I think that is more + important than losing a page of the virtual address space (note + that no actual memory is lost; the page which is skipped can not + be referenced). */ + . = .; + .data : + { + _fdata = . ; + *(.data) + + /* Put the compressed image here, so bss is on the end. */ + __image_begin = .; + *(.image) + __image_end = .; + /* Align the initial ramdisk image (INITRD) on page boundaries. */ + . = ALIGN(4096); + __ramdisk_begin = .; + *(.initrd) + __ramdisk_end = .; + . = ALIGN(4096); + + CONSTRUCTORS + } + .data1 : { *(.data1) } + _gp = . + 0x8000; + .lit8 : { *(.lit8) } + .lit4 : { *(.lit4) } + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + .got : { *(.got.plt) *(.got) } + .dynamic : { *(.dynamic) } + /* We want the small data sections together, so single-instruction offsets + can access them all, and initialized data all before uninitialized, so + we can shorten the on-disk segment size. */ + .sdata : { *(.sdata) } + . = ALIGN(4); + _edata = .; + PROVIDE (edata = .); + + __bss_start = .; + _fbss = .; + .sbss : { *(.sbss) *(.scommon) } + .bss : + { + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + _end = . ; + PROVIDE (end = .); + } + + /* Sections to be discarded */ + /DISCARD/ : + { + *(.text.exit) + *(.data.exit) + *(.exitcall.exit) + } + + /* This is the MIPS specific mdebug section. */ + .mdebug : { *(.mdebug) } + /* These are needed for ELF backends which have not yet been + converted to the new style linker. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + /* DWARF debug sections. + Symbols in the .debug DWARF section are relative to the beginning of the + section so we begin .debug at 0. It's not clear yet what needs to happen + for the others. */ + .debug 0 : { *(.debug) } + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + .debug_sfnames 0 : { *(.debug_sfnames) } + .line 0 : { *(.line) } + /* These must appear regardless of . */ + .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } + .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } + .comment : { *(.comment) } + .note : { *(.note) } +} diff -ruN linux-2.6.31-vanilla/arch/mips/boot/compressed/misc.c linux-2.6.31/arch/mips/boot/compressed/misc.c --- linux-2.6.31-vanilla/arch/mips/boot/compressed/misc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/compressed/misc.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,242 @@ +/* + * linux/arch/mips/boot/compressed/misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Adapted for JZSOC by Peter Wei, 2008 + * + */ + +#define size_t int +#define NULL 0 + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +void* memset(void* s, int c, size_t n); +void* memcpy(void* __dest, __const void* __src, size_t __n); + +extern void flushcaches(void); /* defined in head.S */ + +char *input_data; +int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *str) +{ +} + +extern unsigned char _end[]; +static unsigned long free_mem_ptr; +static unsigned long free_mem_end_ptr; + +#define HEAP_SIZE 0x10000 + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr == 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 3; i > 0; i--) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 2) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 1) { + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1) + *d++ = *s++; + + return __dest; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +static int fill_inbuf(void) +{ + if (insize != 0) { + error("ran out of input data\n"); + } + + inbuf = input_data; + insize = input_len; + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +static void flush_window(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +void decompress_kernel(unsigned int imageaddr, unsigned int imagesize, unsigned int loadaddr) +{ + input_data = (char *)imageaddr; + input_len = imagesize; + output_ptr = 0; + output_data = (uch *)loadaddr; + free_mem_ptr = (unsigned long)_end; + free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; + + makecrc(); + puts("Uncompressing Linux..."); + gunzip(); + flushcaches(); + puts("Ok, booting the kernel."); +} diff -ruN linux-2.6.31-vanilla/arch/mips/boot/tools/entry linux-2.6.31/arch/mips/boot/tools/entry --- linux-2.6.31-vanilla/arch/mips/boot/tools/entry 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/tools/entry 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,12 @@ +#!/bin/sh + +# grab the kernel_entry address from the vmlinux elf image +entry=`$1 $2 | grep kernel_entry` + +fs=`echo $entry | grep ffffffff` # check toolchain output + +if [ -n "$fs" ]; then + echo "0x"`$1 $2 | grep kernel_entry | cut -c9- | awk '{print $1}'` +else + echo "0x"`$1 $2 | grep kernel_entry | cut -c1- | awk '{print $1}'` +fi diff -ruN linux-2.6.31-vanilla/arch/mips/boot/tools/filesize linux-2.6.31/arch/mips/boot/tools/filesize --- linux-2.6.31-vanilla/arch/mips/boot/tools/filesize 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/boot/tools/filesize 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,7 @@ +#!/bin/sh +HOSTNAME=`uname` +if [ "$HOSTNAME" = "Linux" ]; then +echo `ls -l $1 | awk '{print $5}'` +else +echo `ls -l $1 | awk '{print $6}'` +fi diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/jzsoc.h linux-2.6.31/arch/mips/include/asm/jzsoc.h --- linux-2.6.31-vanilla/arch/mips/include/asm/jzsoc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/jzsoc.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,26 @@ +/* + * linux/include/asm-mips/jzsoc.h + * + * Ingenic's JZXXXX SoC common include. + * + * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZSOC_H__ +#define __ASM_JZSOC_H__ + +/* + * SoC include + */ + +#ifdef CONFIG_SOC_JZ4740 +#include +#endif + +#endif /* __ASM_JZSOC_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-dipper.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-dipper.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-dipper.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-dipper.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,69 @@ +/* + * linux/include/asm-mips/mach-jz4740/board-dipper.h + * + * JZ4725-based (16bit) Dipper board ver 1.x definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4725_DIPPER_H__ +#define __ASM_JZ4725_DIPPER_H__ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ + +/*====================================================================== + * GPIO JZ4725 + */ +#define GPIO_SD_VCC_EN_N 85 /* GPC21 */ +#define GPIO_SD_CD_N 91 /* GPC27 */ +#define GPIO_SD_WP 112 /* GPD16 */ +#define GPIO_USB_DETE 124 /* GPD28 */ +#define GPIO_DC_DETE_N 103 /* GPD7 */ +#define GPIO_CHARG_STAT_N 86 /* GPC22 */ +#define GPIO_DISP_OFF_N 118 /* GPD22 */ + +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE + +/*====================================================================== + * MMC/SD + */ + +#define MSC_WP_PIN GPIO_SD_WP +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + if (__gpio_get_pin(GPIO_SD_CD_N)) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4740_DIPPER_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-leo.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-leo.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-leo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-leo.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,56 @@ +#ifndef __ASM_JZ4740_LEO_H__ +#define __ASM_JZ4740_LEO_H__ + +/* + * Define your board specific codes here !!! + */ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ + + +/*====================================================================== + * GPIO + */ +#define GPIO_DISP_OFF_N 100 +#define GPIO_SD_VCC_EN_N 119 +#define GPIO_SD_CD_N 120 +#define GPIO_SD_WP 111 + +/*====================================================================== + * MMC/SD + */ + +#define MSC_WP_PIN GPIO_SD_WP +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + __gpio_as_input(GPIO_SD_CD_N); \ + if (__gpio_get_pin(GPIO_SD_CD_N)) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4740_BOARD_LEO_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-lyra.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-lyra.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-lyra.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-lyra.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,70 @@ +/* + * linux/include/asm-mips/mach-jz4740/board-lyra.h + * + * JZ4740-based LYRA board ver 2.x definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_LYRA_H__ +#define __ASM_JZ4740_LYRA_H__ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ + + +/*====================================================================== + * GPIO + */ +#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ +#define GPIO_SD_CD_N 110 /* GPD14 */ +#define GPIO_SD_WP 112 /* GPD16 */ +#define GPIO_USB_DETE 102 /* GPD6 */ +#define GPIO_DC_DETE_N 103 /* GPD7 */ +#define GPIO_CHARG_STAT_N 111 /* GPD15 */ +#define GPIO_DISP_OFF_N 118 /* GPD22 */ +#define GPIO_LED_EN 124 /* GPD28 */ + +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE +/*====================================================================== + * MMC/SD + */ + +#define MSC_WP_PIN GPIO_SD_WP +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + if (!(__gpio_get_pin(GPIO_SD_CD_N))) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4740_LYRA_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-pavo.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-pavo.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-pavo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-pavo.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,70 @@ +/* + * linux/include/asm-mips/mach-jz4740/board-pavo.h + * + * JZ4730-based PAVO board ver 2.x definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_PAVO_H__ +#define __ASM_JZ4740_PAVO_H__ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ + + +/*====================================================================== + * GPIO + */ +#define GPIO_SD_VCC_EN_N 113 /* GPD17 */ +#define GPIO_SD_CD_N 110 /* GPD14 */ +#define GPIO_SD_WP 112 /* GPD16 */ +#define GPIO_USB_DETE 102 /* GPD6 */ +#define GPIO_DC_DETE_N 103 /* GPD7 */ +#define GPIO_CHARG_STAT_N 111 /* GPD15 */ +#define GPIO_DISP_OFF_N 118 /* GPD22 */ +#define GPIO_LED_EN 124 /* GPD28 */ + +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE +/*====================================================================== + * MMC/SD + */ + +#define MSC_WP_PIN GPIO_SD_WP +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + if (__gpio_get_pin(GPIO_SD_CD_N)) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4740_PAVO_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-qi_lb60.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2009 Qi Hardware Inc., + * Author: Xiangfu Liu + * + * 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 3 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, see . + */ + +#ifndef __ASM_JZ4740_QI_LB60_H__ +#define __ASM_JZ4740_QI_LB60_H__ + +#include +/* + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL_RTC 32768 /* RTC extal freq: 32.768 KHz */ + +/* + * GPIO + */ +#define GPIO_DC_DETE_N JZ_GPIO_PORTC(26) +#define GPIO_CHARG_STAT_N JZ_GPIO_PORTC(27) +#define GPIO_LED_EN JZ_GPIO_PORTC(28) +#define GPIO_LCD_CS JZ_GPIO_PORTC(21) +#define GPIO_DISP_OFF_N JZ_GPIO_PORTD(21) +#define GPIO_PWM JZ_GPIO_PORTD(27) +#define GPIO_WAKEUP_N JZ_GPIO_PORTD(29) + +#define GPIO_AMP_EN JZ_GPIO_PORTD(4) + +#define GPIO_SD_CD_N JZ_GPIO_PORTD(0) +#define GPIO_SD_VCC_EN_N JZ_GPIO_PORTD(2) +#define GPIO_SD_WP JZ_GPIO_PORTD(16) + +#define GPIO_USB_DETE JZ_GPIO_PORTD(28) +#define GPIO_BUZZ_PWM JZ_GPIO_PORTD(27) +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE + +#define GPIO_AUDIO_POP JZ_GPIO_PORTB(29) +#define GPIO_COB_TEST JZ_GPIO_PORTB(30) + +#define GPIO_KEYOUT_BASE JZ_GPIO_PORTC(10) +#define GPIO_KEYIN_BASE JZ_GPIO_PORTD(18) +#define GPIO_KEYIN_8 JZ_GPIO_PORTD(26) + +/* + * MMC/SD + */ +#define MSC_WP_PIN GPIO_SD_WP +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + if (!__gpio_get_pin(GPIO_SD_CD_N)) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4740_QI_LB60_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-virgo.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-virgo.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/board-virgo.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/board-virgo.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,67 @@ +/* + * linux/include/asm-mips/mach-jz4740/board-virgo.h + * + * JZ4720-based VIRGO board ver 1.x definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4720_VIRGO_H__ +#define __ASM_JZ4720_VIRGO_H__ + +/*====================================================================== + * Frequencies of on-board oscillators + */ +#define JZ_EXTAL 12000000 /* Main extal freq: 12 MHz */ +#define JZ_EXTAL2 32768 /* RTC extal freq: 32.768 KHz */ + +/*====================================================================== + * GPIO VIRGO(JZ4720) + */ +#define GPIO_SD_VCC_EN_N 115 /* GPD19 */ +#define GPIO_SD_CD_N 116 /* GPD20 */ +#define GPIO_USB_DETE 114 /* GPD18 */ +#define GPIO_DC_DETE_N 120 /* GPD24 */ +#define GPIO_DISP_OFF_N 118 /* GPD22 */ +#define GPIO_LED_EN 117 /* GPD21 */ + +#define GPIO_UDC_HOTPLUG GPIO_USB_DETE + +/*====================================================================== + * MMC/SD + */ + +#define MSC_HOTPLUG_PIN GPIO_SD_CD_N +#define MSC_HOTPLUG_IRQ (IRQ_GPIO_0 + GPIO_SD_CD_N) + +#define __msc_init_io() \ +do { \ + __gpio_as_output(GPIO_SD_VCC_EN_N); \ + __gpio_as_input(GPIO_SD_CD_N); \ +} while (0) + +#define __msc_enable_power() \ +do { \ + __gpio_clear_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_disable_power() \ +do { \ + __gpio_set_pin(GPIO_SD_VCC_EN_N); \ +} while (0) + +#define __msc_card_detected(s) \ +({ \ + int detected = 1; \ + if (__gpio_get_pin(GPIO_SD_CD_N)) \ + detected = 0; \ + detected; \ +}) + +#endif /* __ASM_JZ4720_VIRGO_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/clock.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/clock.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/clock.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/clock.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,175 @@ +/* + * linux/include/asm-mips/mach-jz4740/clock.h + * + * JZ4740 clocks definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_CLOCK_H__ +#define __ASM_JZ4740_CLOCK_H__ + +#ifndef JZ_EXTAL +//#define JZ_EXTAL 3686400 /* 3.6864 MHz */ +#define JZ_EXTAL 12000000 /* 3.6864 MHz */ +#endif +#ifndef JZ_EXTAL2 +#define JZ_EXTAL2 32768 /* 32.768 KHz */ +#endif + +/* + * JZ4740 clocks structure + */ +typedef struct { + unsigned int cclk; /* CPU clock */ + unsigned int hclk; /* System bus clock */ + unsigned int pclk; /* Peripheral bus clock */ + unsigned int mclk; /* Flash/SRAM/SDRAM clock */ + unsigned int lcdclk; /* LCDC module clock */ + unsigned int pixclk; /* LCD pixel clock */ + unsigned int i2sclk; /* AIC module clock */ + unsigned int usbclk; /* USB module clock */ + unsigned int mscclk; /* MSC module clock */ + unsigned int extalclk; /* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ + unsigned int rtcclk; /* RTC clock for CPM,INTC,RTC,TCU,WDT */ +} jz_clocks_t; + +extern jz_clocks_t jz_clocks; + + +/* PLL output frequency */ +static __inline__ unsigned int __cpm_get_pllout(void) +{ + unsigned long m, n, no, pllout; + unsigned long cppcr = REG_CPM_CPPCR; + unsigned long od[4] = {1, 2, 2, 4}; + if ((cppcr & CPM_CPPCR_PLLEN) && !(cppcr & CPM_CPPCR_PLLBP)) { + m = __cpm_get_pllm() + 2; + n = __cpm_get_plln() + 2; + no = od[__cpm_get_pllod()]; + pllout = ((JZ_EXTAL) / (n * no)) * m; + } else + pllout = JZ_EXTAL; + return pllout; +} + +/* PLL output frequency for MSC/I2S/LCD/USB */ +static __inline__ unsigned int __cpm_get_pllout2(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_PCS) + return __cpm_get_pllout(); + else + return __cpm_get_pllout()/2; +} + +/* CPU core clock */ +static __inline__ unsigned int __cpm_get_cclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_cdiv()]; +} + +/* AHB system bus clock */ +static __inline__ unsigned int __cpm_get_hclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_hdiv()]; +} + +/* Memory bus clock */ +static __inline__ unsigned int __cpm_get_mclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_mdiv()]; +} + +/* APB peripheral bus clock */ +static __inline__ unsigned int __cpm_get_pclk(void) +{ + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + + return __cpm_get_pllout() / div[__cpm_get_pdiv()]; +} + +/* LCDC module clock */ +static __inline__ unsigned int __cpm_get_lcdclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_ldiv() + 1); +} + +/* LCD pixel clock */ +static __inline__ unsigned int __cpm_get_pixclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_pixdiv() + 1); +} + +/* I2S clock */ +static __inline__ unsigned int __cpm_get_i2sclk(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_I2CS) { + return __cpm_get_pllout2() / (__cpm_get_i2sdiv() + 1); + } + else { + return JZ_EXTAL; + } +} + +/* USB clock */ +static __inline__ unsigned int __cpm_get_usbclk(void) +{ + if (REG_CPM_CPCCR & CPM_CPCCR_UCS) { + return __cpm_get_pllout2() / (__cpm_get_udiv() + 1); + } + else { + return JZ_EXTAL; + } +} + +/* MSC clock */ +static __inline__ unsigned int __cpm_get_mscclk(void) +{ + return __cpm_get_pllout2() / (__cpm_get_mscdiv() + 1); +} + +/* EXTAL clock for UART,I2C,SSI,TCU,USB-PHY */ +static __inline__ unsigned int __cpm_get_extalclk(void) +{ + return JZ_EXTAL; +} + +/* RTC clock for CPM,INTC,RTC,TCU,WDT */ +static __inline__ unsigned int __cpm_get_rtcclk(void) +{ + return JZ_EXTAL2; +} + +/* + * Output 24MHz for SD and 16MHz for MMC. + */ +static inline void __cpm_select_msc_clk(int sd) +{ + unsigned int pllout2 = __cpm_get_pllout2(); + unsigned int div = 0; + + if (sd) { + div = pllout2 / 24000000; + } + else { + div = pllout2 / 16000000; + } + + REG_CPM_MSCCDR = div - 1; +} + +int jz_init_clocks(unsigned long ext_rate); + +#endif /* __ASM_JZ4740_CLOCK_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/dma.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/dma.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/dma.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/dma.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,265 @@ +/* + * linux/include/asm-mips/mach-jz4740/dma.h + * + * JZ4740 DMA definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_DMA_H__ +#define __ASM_JZ4740_DMA_H__ + +#include +#include /* need byte IO */ +#include /* And spinlocks */ +#include +#include + +/* + * Descriptor structure for JZ4740 DMA engine + * Note: this structure must always be aligned to a 16-bytes boundary. + */ + +typedef struct { + volatile u32 dcmd; /* DCMD value for the current transfer */ + volatile u32 dsadr; /* DSAR value for the current transfer */ + volatile u32 dtadr; /* DTAR value for the current transfer */ + volatile u32 ddadr; /* Points to the next descriptor + transfer count */ +} jz_dma_desc; + + +/* DMA Device ID's follow */ +enum { + DMA_ID_UART0_TX = 0, + DMA_ID_UART0_RX, + DMA_ID_SSI_TX, + DMA_ID_SSI_RX, + DMA_ID_AIC_TX, + DMA_ID_AIC_RX, + DMA_ID_MSC_TX, + DMA_ID_MSC_RX, + DMA_ID_TCU_OVERFLOW, + DMA_ID_AUTO, + DMA_ID_RAW_SET, + DMA_ID_MAX +}; + +/* DMA modes, simulated by sw */ +#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_AUTOINIT 0x2 +#define DMA_MODE_MASK 0x3 + +struct jz_dma_chan { + int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */ + unsigned int io; /* DMA channel number */ + const char *dev_str; /* string describes the DMA channel */ + int irq; /* DMA irq number */ + void *irq_dev; /* DMA private device structure */ + unsigned int fifo_addr; /* physical fifo address of the requested device */ + unsigned int cntl; /* DMA controll */ + unsigned int mode; /* DMA configuration */ + unsigned int source; /* DMA request source */ +}; + +extern struct jz_dma_chan jz_dma_table[]; + + +#define DMA_8BIT_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_8BIT_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ + DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_16BIT_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_16BIT_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \ + DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_32BIT_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_32BIT_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_16BYTE_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_16BYTE_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_32BYTE_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_32BYTE_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \ + DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_32_16BYTE_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_32_16BYTE_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_16BIT_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ + DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_16BIT_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ + DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_16BYTE_RX_CMD \ + DMAC_DCMD_DAI | \ + DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +#define DMA_AIC_16BYTE_TX_CMD \ + DMAC_DCMD_SAI | \ + DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \ + DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN + +extern int jz_request_dma(int dev_id, + const char *dev_str, + irqreturn_t (*irqhandler)(int, void *), + unsigned long irqflags, + void *irq_dev_id); +extern void jz_free_dma(unsigned int dmanr); + +extern int jz_dma_read_proc(char *buf, char **start, off_t fpos, + int length, int *eof, void *data); +extern void dump_jz_dma_channel(unsigned int dmanr); + +extern void enable_dma(unsigned int dmanr); +extern void disable_dma(unsigned int dmanr); +extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr); +extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt); +extern void set_dma_mode(unsigned int dmanr, unsigned int mode); +extern void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); +extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt); +extern unsigned int get_dma_residue(unsigned int dmanr); + +extern spinlock_t dma_spin_lock; + +static __inline__ unsigned long claim_dma_lock(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_spin_lock, flags); + return flags; +} + +static __inline__ void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + */ +#define clear_dma_ff(channel) + +static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr) +{ + if (dmanr > MAX_DMA_NUM + || jz_dma_table[dmanr].dev_id < 0) + return NULL; + return &jz_dma_table[dmanr]; +} + +static __inline__ int dma_halted(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return 1; + return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0; +} + +static __inline__ unsigned int get_dma_mode(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return 0; + return chan->mode; +} + +static __inline__ void clear_dma_done(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return; + REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); +} + +static __inline__ void clear_dma_halt(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return; + REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT); + REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT); +} + +static __inline__ void clear_dma_flag(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return; + REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); + REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR); +} + +static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) +{ +} + +static __inline__ unsigned int get_dma_done_status(unsigned int dmanr) +{ + unsigned long dccsr; + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return 0; + dccsr = REG_DMAC_DCCSR(chan->io); + return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); +} + +static __inline__ int get_dma_done_irq(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return -1; + return chan->irq; +} + +#endif /* __ASM_JZ4740_DMA_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/gpio.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/gpio.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/gpio.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/gpio.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ7420/JZ4740 GPIO pin definitions + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _JZ_GPIO_H +#define _JZ_GPIO_H + +#include + +enum jz_gpio_function { + JZ_GPIO_FUNC_NONE, + JZ_GPIO_FUNC1, + JZ_GPIO_FUNC2, + JZ_GPIO_FUNC3, +}; + + +/* + Usually a driver for a SoC component has to request several gpio pins and + configure them as funcion pins. + jz_gpio_bulk_request can be used to ease this process. + Usually one would do something like: + + const static struct jz_gpio_bulk_request i2c_pins[] = { + JZ_GPIO_BULK_PIN(I2C_SDA), + JZ_GPIO_BULK_PIN(I2C_SCK), + }; + + inside the probe function: + + ret = jz_gpio_bulk_request(i2c_pins, ARRAY_SIZE(i2c_pins)); + if (ret) { + ... + + inside the remove function: + + jz_gpio_bulk_free(i2c_pins, ARRAY_SIZE(i2c_pins)); + + +*/ +struct jz_gpio_bulk_request { + int gpio; + const char *name; + enum jz_gpio_function function; +}; + +#define JZ_GPIO_BULK_PIN(pin) { \ + .gpio = JZ_GPIO_ ## pin, \ + .name = #pin, \ + .function = JZ_GPIO_FUNC_ ## pin \ +} + +int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num); +void jz_gpio_enable_pullup(unsigned gpio); +void jz_gpio_disable_pullup(unsigned gpio); +int jz_gpio_set_function(int gpio, enum jz_gpio_function function); + +#include + +#define JZ_GPIO_PORTA(x) (x + 32 * 0) +#define JZ_GPIO_PORTB(x) (x + 32 * 1) +#define JZ_GPIO_PORTC(x) (x + 32 * 2) +#define JZ_GPIO_PORTD(x) (x + 32 * 3) + +/* Port A function pins */ +#define JZ_GPIO_MEM_DATA0 JZ_GPIO_PORTA(0) +#define JZ_GPIO_MEM_DATA1 JZ_GPIO_PORTA(1) +#define JZ_GPIO_MEM_DATA2 JZ_GPIO_PORTA(2) +#define JZ_GPIO_MEM_DATA3 JZ_GPIO_PORTA(3) +#define JZ_GPIO_MEM_DATA4 JZ_GPIO_PORTA(4) +#define JZ_GPIO_MEM_DATA5 JZ_GPIO_PORTA(5) +#define JZ_GPIO_MEM_DATA6 JZ_GPIO_PORTA(6) +#define JZ_GPIO_MEM_DATA7 JZ_GPIO_PORTA(7) +#define JZ_GPIO_MEM_DATA8 JZ_GPIO_PORTA(8) +#define JZ_GPIO_MEM_DATA9 JZ_GPIO_PORTA(9) +#define JZ_GPIO_MEM_DATA10 JZ_GPIO_PORTA(10) +#define JZ_GPIO_MEM_DATA11 JZ_GPIO_PORTA(11) +#define JZ_GPIO_MEM_DATA12 JZ_GPIO_PORTA(12) +#define JZ_GPIO_MEM_DATA13 JZ_GPIO_PORTA(13) +#define JZ_GPIO_MEM_DATA14 JZ_GPIO_PORTA(14) +#define JZ_GPIO_MEM_DATA15 JZ_GPIO_PORTA(15) +#define JZ_GPIO_MEM_DATA16 JZ_GPIO_PORTA(16) +#define JZ_GPIO_MEM_DATA17 JZ_GPIO_PORTA(17) +#define JZ_GPIO_MEM_DATA18 JZ_GPIO_PORTA(18) +#define JZ_GPIO_MEM_DATA19 JZ_GPIO_PORTA(19) +#define JZ_GPIO_MEM_DATA20 JZ_GPIO_PORTA(20) +#define JZ_GPIO_MEM_DATA21 JZ_GPIO_PORTA(21) +#define JZ_GPIO_MEM_DATA22 JZ_GPIO_PORTA(22) +#define JZ_GPIO_MEM_DATA23 JZ_GPIO_PORTA(23) +#define JZ_GPIO_MEM_DATA24 JZ_GPIO_PORTA(24) +#define JZ_GPIO_MEM_DATA25 JZ_GPIO_PORTA(25) +#define JZ_GPIO_MEM_DATA26 JZ_GPIO_PORTA(26) +#define JZ_GPIO_MEM_DATA27 JZ_GPIO_PORTA(27) +#define JZ_GPIO_MEM_DATA28 JZ_GPIO_PORTA(28) +#define JZ_GPIO_MEM_DATA29 JZ_GPIO_PORTA(29) +#define JZ_GPIO_MEM_DATA30 JZ_GPIO_PORTA(30) +#define JZ_GPIO_MEM_DATA31 JZ_GPIO_PORTA(31) + +#define JZ_GPIO_FUNC_MEM_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA17 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA18 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA19 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA20 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA21 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA22 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA23 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA24 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA25 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA26 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA27 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA28 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA29 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA30 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DATA31 JZ_GPIO_FUNC1 + +/* Port B function pins */ +#define JZ_GPIO_MEM_ADDR0 JZ_GPIO_PORTB(0) +#define JZ_GPIO_MEM_ADDR1 JZ_GPIO_PORTB(1) +#define JZ_GPIO_MEM_ADDR2 JZ_GPIO_PORTB(2) +#define JZ_GPIO_MEM_ADDR3 JZ_GPIO_PORTB(3) +#define JZ_GPIO_MEM_ADDR4 JZ_GPIO_PORTB(4) +#define JZ_GPIO_MEM_ADDR5 JZ_GPIO_PORTB(5) +#define JZ_GPIO_MEM_ADDR6 JZ_GPIO_PORTB(6) +#define JZ_GPIO_MEM_ADDR7 JZ_GPIO_PORTB(7) +#define JZ_GPIO_MEM_ADDR8 JZ_GPIO_PORTB(8) +#define JZ_GPIO_MEM_ADDR9 JZ_GPIO_PORTB(9) +#define JZ_GPIO_MEM_ADDR10 JZ_GPIO_PORTB(10) +#define JZ_GPIO_MEM_ADDR11 JZ_GPIO_PORTB(11) +#define JZ_GPIO_MEM_ADDR12 JZ_GPIO_PORTB(12) +#define JZ_GPIO_MEM_ADDR13 JZ_GPIO_PORTB(13) +#define JZ_GPIO_MEM_ADDR14 JZ_GPIO_PORTB(14) +#define JZ_GPIO_MEM_ADDR15 JZ_GPIO_PORTB(15) +#define JZ_GPIO_MEM_ADDR16 JZ_GPIO_PORTB(16) +#define JZ_GPIO_MEM_CLS JZ_GPIO_PORTB(17) +#define JZ_GPIO_MEM_SPL JZ_GPIO_PORTB(18) +#define JZ_GPIO_MEM_DCS JZ_GPIO_PORTB(19) +#define JZ_GPIO_MEM_RAS JZ_GPIO_PORTB(20) +#define JZ_GPIO_MEM_CAS JZ_GPIO_PORTB(21) +#define JZ_GPIO_MEM_SDWE JZ_GPIO_PORTB(22) +#define JZ_GPIO_MEM_CKE JZ_GPIO_PORTB(23) +#define JZ_GPIO_MEM_CKO JZ_GPIO_PORTB(24) +#define JZ_GPIO_MEM_CS0 JZ_GPIO_PORTB(25) +#define JZ_GPIO_MEM_CS1 JZ_GPIO_PORTB(26) +#define JZ_GPIO_MEM_CS2 JZ_GPIO_PORTB(27) +#define JZ_GPIO_MEM_CS3 JZ_GPIO_PORTB(28) +#define JZ_GPIO_MEM_RD JZ_GPIO_PORTB(29) +#define JZ_GPIO_MEM_WR JZ_GPIO_PORTB(30) +#define JZ_GPIO_MEM_WE0 JZ_GPIO_PORTB(31) + +#define JZ_GPIO_FUNC_MEM_ADDR0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_ADDR16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CLS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_SPL JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_DCS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_RAS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CAS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_SDWE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CKE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CKO JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_CS3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_RD JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WR JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE0 JZ_GPIO_FUNC1 + + +#define JZ_GPIO_MEM_ADDR21 JZ_GPIO_PORTB(17) +#define JZ_GPIO_MEM_ADDR22 JZ_GPIO_PORTB(18) + +#define JZ_GPIO_FUNC_MEM_ADDR21 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR22 JZ_GPIO_FUNC2 + +/* Port C function pins */ +#define JZ_GPIO_LCD_DATA0 JZ_GPIO_PORTC(0) +#define JZ_GPIO_LCD_DATA1 JZ_GPIO_PORTC(1) +#define JZ_GPIO_LCD_DATA2 JZ_GPIO_PORTC(2) +#define JZ_GPIO_LCD_DATA3 JZ_GPIO_PORTC(3) +#define JZ_GPIO_LCD_DATA4 JZ_GPIO_PORTC(4) +#define JZ_GPIO_LCD_DATA5 JZ_GPIO_PORTC(5) +#define JZ_GPIO_LCD_DATA6 JZ_GPIO_PORTC(6) +#define JZ_GPIO_LCD_DATA7 JZ_GPIO_PORTC(7) +#define JZ_GPIO_LCD_DATA8 JZ_GPIO_PORTC(8) +#define JZ_GPIO_LCD_DATA9 JZ_GPIO_PORTC(9) +#define JZ_GPIO_LCD_DATA10 JZ_GPIO_PORTC(10) +#define JZ_GPIO_LCD_DATA11 JZ_GPIO_PORTC(11) +#define JZ_GPIO_LCD_DATA12 JZ_GPIO_PORTC(12) +#define JZ_GPIO_LCD_DATA13 JZ_GPIO_PORTC(13) +#define JZ_GPIO_LCD_DATA14 JZ_GPIO_PORTC(14) +#define JZ_GPIO_LCD_DATA15 JZ_GPIO_PORTC(15) +#define JZ_GPIO_LCD_DATA16 JZ_GPIO_PORTC(16) +#define JZ_GPIO_LCD_DATA17 JZ_GPIO_PORTC(17) +#define JZ_GPIO_LCD_PCLK JZ_GPIO_PORTC(18) +#define JZ_GPIO_LCD_HSYNC JZ_GPIO_PORTC(19) +#define JZ_GPIO_LCD_VSYNC JZ_GPIO_PORTC(20) +#define JZ_GPIO_LCD_DE JZ_GPIO_PORTC(21) +#define JZ_GPIO_LCD_PS JZ_GPIO_PORTC(22) +#define JZ_GPIO_LCD_REV JZ_GPIO_PORTC(23) +#define JZ_GPIO_MEM_WE1 JZ_GPIO_PORTC(24) +#define JZ_GPIO_MEM_WE2 JZ_GPIO_PORTC(25) +#define JZ_GPIO_MEM_WE3 JZ_GPIO_PORTC(26) +#define JZ_GPIO_MEM_WAIT JZ_GPIO_PORTC(27) +#define JZ_GPIO_MEM_FRE JZ_GPIO_PORTC(28) +#define JZ_GPIO_MEM_FWE JZ_GPIO_PORTC(29) + +#define JZ_GPIO_FUNC_LCD_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA8 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA9 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA10 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA11 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA12 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA13 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA14 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA15 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA16 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DATA17 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_PCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_VSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_HSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_DE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_PS JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_LCD_REV JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WE3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_WAIT JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_FRE JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MEM_FWE JZ_GPIO_FUNC1 + + +#define JZ_GPIO_MEM_ADDR19 JZ_GPIO_PORTB(22) +#define JZ_GPIO_MEM_ADDR20 JZ_GPIO_PORTB(23) + +#define JZ_GPIO_FUNC_MEM_ADDR19 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR20 JZ_GPIO_FUNC2 + +/* Port D function pins */ +#define JZ_GPIO_CIM_DATA0 JZ_GPIO_PORTD(0) +#define JZ_GPIO_CIM_DATA1 JZ_GPIO_PORTD(1) +#define JZ_GPIO_CIM_DATA2 JZ_GPIO_PORTD(2) +#define JZ_GPIO_CIM_DATA3 JZ_GPIO_PORTD(3) +#define JZ_GPIO_CIM_DATA4 JZ_GPIO_PORTD(4) +#define JZ_GPIO_CIM_DATA5 JZ_GPIO_PORTD(5) +#define JZ_GPIO_CIM_DATA6 JZ_GPIO_PORTD(6) +#define JZ_GPIO_CIM_DATA7 JZ_GPIO_PORTD(7) +#define JZ_GPIO_MSC_CMD JZ_GPIO_PORTD(8) +#define JZ_GPIO_MSC_CLK JZ_GPIO_PORTD(9) +#define JZ_GPIO_MSC_DATA0 JZ_GPIO_PORTD(10) +#define JZ_GPIO_MSC_DATA1 JZ_GPIO_PORTD(11) +#define JZ_GPIO_MSC_DATA2 JZ_GPIO_PORTD(12) +#define JZ_GPIO_MSC_DATA3 JZ_GPIO_PORTD(13) +#define JZ_GPIO_CIM_MCLK JZ_GPIO_PORTD(14) +#define JZ_GPIO_CIM_PCLK JZ_GPIO_PORTD(15) +#define JZ_GPIO_CIM_VSYNC JZ_GPIO_PORTD(16) +#define JZ_GPIO_CIM_HSYNC JZ_GPIO_PORTD(17) +#define JZ_GPIO_SPI_CLK JZ_GPIO_PORTD(18) +#define JZ_GPIO_SPI_CE0 JZ_GPIO_PORTD(19) +#define JZ_GPIO_SPI_DT JZ_GPIO_PORTD(20) +#define JZ_GPIO_SPI_DR JZ_GPIO_PORTD(21) +#define JZ_GPIO_SPI_CE1 JZ_GPIO_PORTD(22) +#define JZ_GPIO_PWM0 JZ_GPIO_PORTD(23) +#define JZ_GPIO_PWM1 JZ_GPIO_PORTD(24) +#define JZ_GPIO_PWM2 JZ_GPIO_PORTD(25) +#define JZ_GPIO_PWM3 JZ_GPIO_PORTD(26) +#define JZ_GPIO_PWM4 JZ_GPIO_PORTD(27) +#define JZ_GPIO_PWM5 JZ_GPIO_PORTD(28) +#define JZ_GPIO_PWM6 JZ_GPIO_PORTD(30) +#define JZ_GPIO_PWM7 JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_CIM_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA6 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_DATA7 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_CMD JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_CLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_MSC_DATA3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_MCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_PCLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_VSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_CIM_HSYNC JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CLK JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CE0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_DT JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_DR JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_SPI_CE1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM0 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM1 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM2 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM3 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM4 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM5 JZ_GPIO_FUNC1 +#define JZ_GPIO_FUNC_PWM6 JZ_GPIO_FUNC1 + +#define JZ_GPIO_MEM_SCLK_RSTN JZ_GPIO_PORTD(18) +#define JZ_GPIO_MEM_BCLK JZ_GPIO_PORTD(19) +#define JZ_GPIO_MEM_SDATO JZ_GPIO_PORTD(20) +#define JZ_GPIO_MEM_SDATI JZ_GPIO_PORTD(21) +#define JZ_GPIO_MEM_SYNC JZ_GPIO_PORTD(22) +#define JZ_GPIO_I2C_SDA JZ_GPIO_PORTD(23) +#define JZ_GPIO_I2C_SCK JZ_GPIO_PORTD(24) +#define JZ_GPIO_UART0_TXD JZ_GPIO_PORTD(25) +#define JZ_GPIO_UART0_RXD JZ_GPIO_PORTD(26) +#define JZ_GPIO_MEM_ADDR17 JZ_GPIO_PORTD(27) +#define JZ_GPIO_MEM_ADDR18 JZ_GPIO_PORTD(28) +#define JZ_GPIO_UART0_CTS JZ_GPIO_PORTD(30) +#define JZ_GPIO_UART0_RTS JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_MEM_SCLK_RSTN JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_BCLK JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SDATO JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SDATI JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_SYNC JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_I2C_SDA JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_I2C_SCK JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_TXD JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_RXD JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR17 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_MEM_ADDR18 JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_CTS JZ_GPIO_FUNC2 +#define JZ_GPIO_FUNC_UART0_RTS JZ_GPIO_FUNC2 + +#define JZ_GPIO_UART1_RXD JZ_GPIO_PORTD(30) +#define JZ_GPIO_UART1_TXD JZ_GPIO_PORTD(31) + +#define JZ_GPIO_FUNC_UART1_RXD JZ_GPIO_FUNC3 +#define JZ_GPIO_FUNC_UART1_TXD JZ_GPIO_FUNC3 + +#endif diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/jz4740.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/jz4740.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/jz4740.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/jz4740.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,60 @@ +/* + * linux/include/asm-mips/mach-jz4740/jz4740.h + * + * JZ4740 common definition. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_H__ +#define __ASM_JZ4740_H__ + +#include +#include +#include +#include + +/*------------------------------------------------------------------ + * Platform definitions + */ +#ifdef CONFIG_JZ4740_PAVO +#include +#endif + +#ifdef CONFIG_JZ4740_LEO +#include +#endif + +#ifdef CONFIG_JZ4740_LYRA +#include +#endif + +#ifdef CONFIG_JZ4725_DIPPER +#include +#endif + +#ifdef CONFIG_JZ4720_VIRGO +#include +#endif + +#ifdef CONFIG_JZ4740_QI_LB60 +#include +#endif + +/* Add other platform definition here ... */ + + +/*------------------------------------------------------------------ + * Follows are related to platform definitions + */ + +#include +#include + +#endif /* __ASM_JZ4740_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/misc.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/misc.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/misc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/misc.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,43 @@ +/* + * linux/include/asm-mips/mach-jz4740/misc.h + * + * Ingenic's JZ4740 common include. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_JZ4740_MISC_H__ +#define __ASM_JZ4740_MISC_H__ + +/*========================================================== + * I2C + *===========================================================*/ + +#define I2C_EEPROM_DEV 0xA /* b'1010 */ +#define I2C_RTC_DEV 0xD /* b'1101 */ +#define DIMM0_SPD_ADDR 0 +#define DIMM1_SPD_ADDR 1 +#define DIMM2_SPD_ADDR 2 +#define DIMM3_SPD_ADDR 3 +#define JZ_HCI_ADDR 7 + +#define DIMM_SPD_LEN 128 +#define JZ_HCI_LEN 512 /* 4K bits E2PROM */ +#define I2C_RTC_LEN 16 +#define HCI_MAC_OFFSET 64 + +extern void i2c_open(void); +extern void i2c_close(void); +extern void i2c_setclk(unsigned int i2cclk); +extern int i2c_read(unsigned char device, unsigned char *buf, + unsigned char address, int count); +extern int i2c_write(unsigned char device, unsigned char *buf, + unsigned char address, int count); + +#endif /* __ASM_JZ4740_MISC_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/ops.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/ops.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/ops.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/ops.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,2224 @@ +/* + * linux/include/asm-mips/mach-jz4740/ops.h + * + * Ingenic's JZ4740 common include. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __JZ4740_OPS_H__ +#define __JZ4740_OPS_H__ + +/* + * Definition of Module Operations + */ + +/*************************************************************************** + * GPIO + ***************************************************************************/ + +//------------------------------------------------------ +// GPIO Pins Description +// +// PORT 0: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 D0 - +// 1 D1 - +// 2 D2 - +// 3 D3 - +// 4 D4 - +// 5 D5 - +// 6 D6 - +// 7 D7 - +// 8 D8 - +// 9 D9 - +// 10 D10 - +// 11 D11 - +// 12 D12 - +// 13 D13 - +// 14 D14 - +// 15 D15 - +// 16 D16 - +// 17 D17 - +// 18 D18 - +// 19 D19 - +// 20 D20 - +// 21 D21 - +// 22 D22 - +// 23 D23 - +// 24 D24 - +// 25 D25 - +// 26 D26 - +// 27 D27 - +// 28 D28 - +// 29 D29 - +// 30 D30 - +// 31 D31 - +// +//------------------------------------------------------ +// PORT 1: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 A0 - +// 1 A1 - +// 2 A2 - +// 3 A3 - +// 4 A4 - +// 5 A5 - +// 6 A6 - +// 7 A7 - +// 8 A8 - +// 9 A9 - +// 10 A10 - +// 11 A11 - +// 12 A12 - +// 13 A13 - +// 14 A14 - +// 15 A15/CL - +// 16 A16/AL - +// 17 LCD_CLS A21 +// 18 LCD_SPL A22 +// 19 DCS# - +// 20 RAS# - +// 21 CAS# - +// 22 RDWE#/BUFD# - +// 23 CKE - +// 24 CKO - +// 25 CS1# - +// 26 CS2# - +// 27 CS3# - +// 28 CS4# - +// 29 RD# - +// 30 WR# - +// 31 WE0# - +// +// Note: PIN15&16 are CL&AL when connecting to NAND flash. +//------------------------------------------------------ +// PORT 2: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 LCD_D0 - +// 1 LCD_D1 - +// 2 LCD_D2 - +// 3 LCD_D3 - +// 4 LCD_D4 - +// 5 LCD_D5 - +// 6 LCD_D6 - +// 7 LCD_D7 - +// 8 LCD_D8 - +// 9 LCD_D9 - +// 10 LCD_D10 - +// 11 LCD_D11 - +// 12 LCD_D12 - +// 13 LCD_D13 - +// 14 LCD_D14 - +// 15 LCD_D15 - +// 16 LCD_D16 - +// 17 LCD_D17 - +// 18 LCD_PCLK - +// 19 LCD_HSYNC - +// 20 LCD_VSYNC - +// 21 LCD_DE - +// 22 LCD_PS A19 +// 23 LCD_REV A20 +// 24 WE1# - +// 25 WE2# - +// 26 WE3# - +// 27 WAIT# - +// 28 FRE# - +// 29 FWE# - +// 30(NOTE:FRB#) - - +// 31 - - +// +// NOTE(1): PIN30 is used for FRB# when connecting to NAND flash. +//------------------------------------------------------ +// PORT 3: +// +// PIN/BIT N FUNC0 FUNC1 +// 0 CIM_D0 - +// 1 CIM_D1 - +// 2 CIM_D2 - +// 3 CIM_D3 - +// 4 CIM_D4 - +// 5 CIM_D5 - +// 6 CIM_D6 - +// 7 CIM_D7 - +// 8 MSC_CMD - +// 9 MSC_CLK - +// 10 MSC_D0 - +// 11 MSC_D1 - +// 12 MSC_D2 - +// 13 MSC_D3 - +// 14 CIM_MCLK - +// 15 CIM_PCLK - +// 16 CIM_VSYNC - +// 17 CIM_HSYNC - +// 18 SSI_CLK SCLK_RSTN +// 19 SSI_CE0# BIT_CLK(AIC) +// 20 SSI_DT SDATA_OUT(AIC) +// 21 SSI_DR SDATA_IN(AIC) +// 22 SSI_CE1#&GPC SYNC(AIC) +// 23 PWM0 I2C_SDA +// 24 PWM1 I2C_SCK +// 25 PWM2 UART0_TxD +// 26 PWM3 UART0_RxD +// 27 PWM4 A17 +// 28 PWM5 A18 +// 29 - - +// 30 PWM6 UART0_CTS/UART1_RxD +// 31 PWM7 UART0_RTS/UART1_TxD +// +////////////////////////////////////////////////////////// + +/* + * p is the port number (0,1,2,3) + * o is the pin offset (0-31) inside the port + * n is the absolute number of a pin (0-127), regardless of the port + */ + +//------------------------------------------- +// Function Pins Mode + +#define __gpio_as_func0(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFUNS(p) = (1 << o); \ + REG_GPIO_PXSELC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_func1(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFUNS(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ +} while (0) + +/* + * D0 ~ D31, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1#, WE2#, WE3# + */ +#define __gpio_as_sdram_32bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0xffffffff; \ + REG_GPIO_PXSELC(0) = 0xffffffff; \ + REG_GPIO_PXPES(0) = 0xffffffff; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x07000000; \ + REG_GPIO_PXSELC(2) = 0x07000000; \ + REG_GPIO_PXPES(2) = 0x07000000; \ +} while (0) + +/* + * D0 ~ D15, A0 ~ A16, DCS#, RAS#, CAS#, CKE#, + * RDWE#, CKO#, WE0#, WE1# + */ +#define __gpio_as_sdram_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x5442bfaa; \ + REG_GPIO_PXSELC(0) = 0x5442bfaa; \ + REG_GPIO_PXPES(0) = 0x5442bfaa; \ + REG_GPIO_PXFUNS(1) = 0x81f9ffff; \ + REG_GPIO_PXSELC(1) = 0x81f9ffff; \ + REG_GPIO_PXPES(1) = 0x81f9ffff; \ + REG_GPIO_PXFUNS(2) = 0x01000000; \ + REG_GPIO_PXSELC(2) = 0x01000000; \ + REG_GPIO_PXPES(2) = 0x01000000; \ +} while (0) + +/* + * CS1#, CLE, ALE, FRE#, FWE#, FRB#, RDWE#/BUFD# + */ +#define __gpio_as_nand() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x02018000; \ + REG_GPIO_PXSELC(1) = 0x02018000; \ + REG_GPIO_PXPES(1) = 0x02018000; \ + REG_GPIO_PXFUNS(2) = 0x30000000; \ + REG_GPIO_PXSELC(2) = 0x30000000; \ + REG_GPIO_PXPES(2) = 0x30000000; \ + REG_GPIO_PXFUNC(2) = 0x40000000; \ + REG_GPIO_PXSELC(2) = 0x40000000; \ + REG_GPIO_PXDIRC(2) = 0x40000000; \ + REG_GPIO_PXPES(2) = 0x40000000; \ + REG_GPIO_PXFUNS(1) = 0x00400000; \ + REG_GPIO_PXSELC(1) = 0x00400000; \ +} while (0) + +/* + * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D7 + */ +#define __gpio_as_nor_8bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x000000ff; \ + REG_GPIO_PXSELC(0) = 0x000000ff; \ + REG_GPIO_PXPES(0) = 0x000000ff; \ + REG_GPIO_PXFUNS(1) = 0x7041ffff; \ + REG_GPIO_PXSELC(1) = 0x7041ffff; \ + REG_GPIO_PXPES(1) = 0x7041ffff; \ + REG_GPIO_PXFUNS(1) = 0x00060000; \ + REG_GPIO_PXSELS(1) = 0x00060000; \ + REG_GPIO_PXPES(1) = 0x00060000; \ + REG_GPIO_PXFUNS(2) = 0x08000000; \ + REG_GPIO_PXSELC(2) = 0x08000000; \ + REG_GPIO_PXPES(2) = 0x08000000; \ + REG_GPIO_PXFUNS(2) = 0x00c00000; \ + REG_GPIO_PXSELS(2) = 0x00c00000; \ + REG_GPIO_PXPES(2) = 0x00c00000; \ + REG_GPIO_PXFUNS(3) = 0x18000000; \ + REG_GPIO_PXSELS(3) = 0x18000000; \ + REG_GPIO_PXPES(3) = 0x18000000; \ +} while (0) + +/* + * CS4#, RD#, WR#, WAIT#, A0 ~ A22, D0 ~ D15 + */ +#define __gpio_as_nor_16bit() \ +do { \ + REG_GPIO_PXFUNS(0) = 0x0000ffff; \ + REG_GPIO_PXSELC(0) = 0x0000ffff; \ + REG_GPIO_PXPES(0) = 0x0000ffff; \ + REG_GPIO_PXFUNS(1) = 0x7041ffff; \ + REG_GPIO_PXSELC(1) = 0x7041ffff; \ + REG_GPIO_PXPES(1) = 0x7041ffff; \ + REG_GPIO_PXFUNS(1) = 0x00060000; \ + REG_GPIO_PXSELS(1) = 0x00060000; \ + REG_GPIO_PXPES(1) = 0x00060000; \ + REG_GPIO_PXFUNS(2) = 0x08000000; \ + REG_GPIO_PXSELC(2) = 0x08000000; \ + REG_GPIO_PXPES(2) = 0x08000000; \ + REG_GPIO_PXFUNS(2) = 0x00c00000; \ + REG_GPIO_PXSELS(2) = 0x00c00000; \ + REG_GPIO_PXPES(2) = 0x00c00000; \ + REG_GPIO_PXFUNS(3) = 0x18000000; \ + REG_GPIO_PXSELS(3) = 0x18000000; \ + REG_GPIO_PXPES(3) = 0x18000000; \ +} while (0) + +/* + * UART0_TxD, UART_RxD0 + */ +#define __gpio_as_uart0() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x06000000; \ + REG_GPIO_PXSELS(3) = 0x06000000; \ + REG_GPIO_PXPES(3) = 0x06000000; \ +} while (0) + +/* + * UART0_CTS, UART0_RTS + */ +#define __gpio_as_ctsrts() \ +do { \ + REG_GPIO_PXFUNS(3) = 0xc0000000; \ + REG_GPIO_PXSELS(3) = 0xc0000000; \ + REG_GPIO_PXTRGC(3) = 0xc0000000; \ + REG_GPIO_PXPES(3) = 0xc0000000; \ +} while (0) + +/* + * UART1_TxD, UART1_RxD1 + */ +#define __gpio_as_uart1() \ +do { \ + REG_GPIO_PXFUNS(3) = 0xc0000000; \ + REG_GPIO_PXSELC(3) = 0xc0000000; \ + REG_GPIO_PXTRGS(3) = 0xc0000000; \ + REG_GPIO_PXPES(3) = 0xc0000000; \ +} while (0) + +/* + * LCD_D0~LCD_D15, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_16bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x003cffff; \ + REG_GPIO_PXSELC(2) = 0x003cffff; \ + REG_GPIO_PXPES(2) = 0x003cffff; \ +} while (0) + +/* + * LCD_D0~LCD_D17, LCD_PCLK, LCD_HSYNC, LCD_VSYNC, LCD_DE + */ +#define __gpio_as_lcd_18bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x003fffff; \ + REG_GPIO_PXSELC(2) = 0x003fffff; \ + REG_GPIO_PXPES(2) = 0x003fffff; \ +} while (0) + +/* + * LCD_PS, LCD_REV, LCD_CLS, LCD_SPL + */ +#define __gpio_as_lcd_special() \ +do { \ + REG_GPIO_PXFUNS(1) = 0x00060000; \ + REG_GPIO_PXSELC(1) = 0x00060000; \ + REG_GPIO_PXPES(1) = 0x00060000; \ + REG_GPIO_PXFUNS(2) = 0x00c00000; \ + REG_GPIO_PXSELC(2) = 0x00c00000; \ + REG_GPIO_PXPES(2) = 0x00c00000; \ +} while (0) + +/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_8bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001800ff; \ + REG_GPIO_PXSELC(2) = 0x001800ff; \ +} while (0) + +/* LCD_D0~LCD_D7, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_9bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001801ff; \ + REG_GPIO_PXSELC(2) = 0x001801ff; \ +} while (0) + +/* LCD_D0~LCD_D15, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_16bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x0018ffff; \ + REG_GPIO_PXSELC(2) = 0x0018ffff; \ +} while (0) + +/* LCD_D0~LCD_D17, SLCD_RS, SLCD_CS */ +#define __gpio_as_slcd_18bit() \ +do { \ + REG_GPIO_PXFUNS(2) = 0x001bffff; \ + REG_GPIO_PXSELC(2) = 0x001bffff; \ +} while (0) + +/* + * CIM_D0~CIM_D7, CIM_MCLK, CIM_PCLK, CIM_VSYNC, CIM_HSYNC + */ +#define __gpio_as_cim() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x0003c0ff; \ + REG_GPIO_PXSELC(3) = 0x0003c0ff; \ + REG_GPIO_PXPES(3) = 0x0003c0ff; \ +} while (0) + +/* + * SDATA_OUT, SDATA_IN, BIT_CLK, SYNC, SCLK_RESET + */ +#define __gpio_as_aic() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x007c0000; \ + REG_GPIO_PXSELS(3) = 0x007c0000; \ + REG_GPIO_PXPES(3) = 0x007c0000; \ +} while (0) + +/* + * MSC_CMD, MSC_CLK, MSC_D0 ~ MSC_D3 + */ +#define __gpio_as_msc() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x00003f00; \ + REG_GPIO_PXSELC(3) = 0x00003f00; \ + REG_GPIO_PXPES(3) = 0x00003f00; \ +} while (0) + +/* + * SSI_CS0, SSI_CLK, SSI_DT, SSI_DR + */ +#define __gpio_as_ssi() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x003c0000; \ + REG_GPIO_PXSELC(3) = 0x003c0000; \ + REG_GPIO_PXPES(3) = 0x003c0000; \ +} while (0) + +/* + * I2C_SCK, I2C_SDA + */ +#define __gpio_as_i2c() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x01800000; \ + REG_GPIO_PXSELS(3) = 0x01800000; \ + REG_GPIO_PXPES(3) = 0x01800000; \ +} while (0) + +/* + * PWM0 + */ +#define __gpio_as_pwm0() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x00800000; \ + REG_GPIO_PXSELC(3) = 0x00800000; \ + REG_GPIO_PXPES(3) = 0x00800000; \ +} while (0) + +/* + * PWM1 + */ +#define __gpio_as_pwm1() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x01000000; \ + REG_GPIO_PXSELC(3) = 0x01000000; \ + REG_GPIO_PXPES(3) = 0x01000000; \ +} while (0) + +/* + * PWM2 + */ +#define __gpio_as_pwm2() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x02000000; \ + REG_GPIO_PXSELC(3) = 0x02000000; \ + REG_GPIO_PXPES(3) = 0x02000000; \ +} while (0) + +/* + * PWM3 + */ +#define __gpio_as_pwm3() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x04000000; \ + REG_GPIO_PXSELC(3) = 0x04000000; \ + REG_GPIO_PXPES(3) = 0x04000000; \ +} while (0) + +/* + * PWM4 + */ +#define __gpio_as_pwm4() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x08000000; \ + REG_GPIO_PXSELC(3) = 0x08000000; \ + REG_GPIO_PXPES(3) = 0x08000000; \ +} while (0) + +/* + * PWM5 + */ +#define __gpio_as_pwm5() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x10000000; \ + REG_GPIO_PXSELC(3) = 0x10000000; \ + REG_GPIO_PXPES(3) = 0x10000000; \ +} while (0) + +/* + * PWM6 + */ +#define __gpio_as_pwm6() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x40000000; \ + REG_GPIO_PXSELC(3) = 0x40000000; \ + REG_GPIO_PXPES(3) = 0x40000000; \ +} while (0) + +/* + * PWM7 + */ +#define __gpio_as_pwm7() \ +do { \ + REG_GPIO_PXFUNS(3) = 0x80000000; \ + REG_GPIO_PXSELC(3) = 0x80000000; \ + REG_GPIO_PXPES(3) = 0x80000000; \ +} while (0) + +/* + * n = 0 ~ 7 + */ +#define __gpio_as_pwm(n) __gpio_as_pwm##n() + +//------------------------------------------- +// GPIO or Interrupt Mode + +#define __gpio_get_port(p) (REG_GPIO_PXPIN(p)) + +#define __gpio_port_as_output(p, o) \ +do { \ + REG_GPIO_PXFUNC(p) = (1 << (o)); \ + REG_GPIO_PXSELC(p) = (1 << (o)); \ + REG_GPIO_PXDIRS(p) = (1 << (o)); \ +} while (0) + +#define __gpio_port_as_input(p, o) \ +do { \ + REG_GPIO_PXFUNC(p) = (1 << (o)); \ + REG_GPIO_PXSELC(p) = (1 << (o)); \ + REG_GPIO_PXDIRC(p) = (1 << (o)); \ +} while (0) + +#define __gpio_as_output(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + __gpio_port_as_output(p, o); \ +} while (0) + +#define __gpio_as_input(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + __gpio_port_as_input(p, o); \ +} while (0) + +#define __gpio_set_pin(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXDATS(p) = (1 << o); \ +} while (0) + +#define __gpio_clear_pin(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXDATC(p) = (1 << o); \ +} while (0) + +#define __gpio_get_pin(n) \ +({ \ + unsigned int p, o, v; \ + p = (n) / 32; \ + o = (n) % 32; \ + if (__gpio_get_port(p) & (1 << o)) \ + v = 1; \ + else \ + v = 0; \ + v; \ +}) + +#define __gpio_as_irq_high_level(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGC(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRS(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_low_level(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGC(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRC(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_rise_edge(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGS(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRS(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_as_irq_fall_edge(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ + REG_GPIO_PXTRGS(p) = (1 << o); \ + REG_GPIO_PXFUNC(p) = (1 << o); \ + REG_GPIO_PXSELS(p) = (1 << o); \ + REG_GPIO_PXDIRC(p) = (1 << o); \ + REG_GPIO_PXFLGC(p) = (1 << o); \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_mask_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMS(p) = (1 << o); \ +} while (0) + +#define __gpio_unmask_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXIMC(p) = (1 << o); \ +} while (0) + +#define __gpio_ack_irq(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXFLGC(p) = (1 << o); \ +} while (0) + +#define __gpio_get_irq() \ +({ \ + unsigned int p, i, tmp, v = 0; \ + for (p = 3; p >= 0; p--) { \ + tmp = REG_GPIO_PXFLG(p); \ + for (i = 0; i < 32; i++) \ + if (tmp & (1 << i)) \ + v = (32*p + i); \ + } \ + v; \ +}) + +#define __gpio_group_irq(n) \ +({ \ + register int tmp, i; \ + tmp = REG_GPIO_PXFLG((n)); \ + for (i=31;i>=0;i--) \ + if (tmp & (1 << i)) \ + break; \ + i; \ +}) + +#define __gpio_enable_pull(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXPEC(p) = (1 << o); \ +} while (0) + +#define __gpio_disable_pull(n) \ +do { \ + unsigned int p, o; \ + p = (n) / 32; \ + o = (n) % 32; \ + REG_GPIO_PXPES(p) = (1 << o); \ +} while (0) + + +/*************************************************************************** + * CPM + ***************************************************************************/ +#define __cpm_get_pllm() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLM_MASK) >> CPM_CPPCR_PLLM_BIT) +#define __cpm_get_plln() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLN_MASK) >> CPM_CPPCR_PLLN_BIT) +#define __cpm_get_pllod() \ + ((REG_CPM_CPPCR & CPM_CPPCR_PLLOD_MASK) >> CPM_CPPCR_PLLOD_BIT) + +#define __cpm_get_cdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_CDIV_MASK) >> CPM_CPCCR_CDIV_BIT) +#define __cpm_get_hdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_HDIV_MASK) >> CPM_CPCCR_HDIV_BIT) +#define __cpm_get_pdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_PDIV_MASK) >> CPM_CPCCR_PDIV_BIT) +#define __cpm_get_mdiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT) +#define __cpm_get_ldiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_LDIV_MASK) >> CPM_CPCCR_LDIV_BIT) +#define __cpm_get_udiv() \ + ((REG_CPM_CPCCR & CPM_CPCCR_UDIV_MASK) >> CPM_CPCCR_UDIV_BIT) +#define __cpm_get_i2sdiv() \ + ((REG_CPM_I2SCDR & CPM_I2SCDR_I2SDIV_MASK) >> CPM_I2SCDR_I2SDIV_BIT) +#define __cpm_get_pixdiv() \ + ((REG_CPM_LPCDR & CPM_LPCDR_PIXDIV_MASK) >> CPM_LPCDR_PIXDIV_BIT) +#define __cpm_get_mscdiv() \ + ((REG_CPM_MSCCDR & CPM_MSCCDR_MSCDIV_MASK) >> CPM_MSCCDR_MSCDIV_BIT) +#define __cpm_get_uhcdiv() \ + ((REG_CPM_UHCCDR & CPM_UHCCDR_UHCDIV_MASK) >> CPM_UHCCDR_UHCDIV_BIT) +#define __cpm_get_ssidiv() \ + ((REG_CPM_SSICCDR & CPM_SSICDR_SSICDIV_MASK) >> CPM_SSICDR_SSIDIV_BIT) + +#define __cpm_set_cdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_CDIV_MASK) | ((v) << (CPM_CPCCR_CDIV_BIT))) +#define __cpm_set_hdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_HDIV_MASK) | ((v) << (CPM_CPCCR_HDIV_BIT))) +#define __cpm_set_pdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_PDIV_MASK) | ((v) << (CPM_CPCCR_PDIV_BIT))) +#define __cpm_set_mdiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_MDIV_MASK) | ((v) << (CPM_CPCCR_MDIV_BIT))) +#define __cpm_set_ldiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT))) +#define __cpm_set_udiv(v) \ + (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_UDIV_MASK) | ((v) << (CPM_CPCCR_UDIV_BIT))) +#define __cpm_set_i2sdiv(v) \ + (REG_CPM_I2SCDR = (REG_CPM_I2SCDR & ~CPM_I2SCDR_I2SDIV_MASK) | ((v) << (CPM_I2SCDR_I2SDIV_BIT))) +#define __cpm_set_pixdiv(v) \ + (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT))) +#define __cpm_set_mscdiv(v) \ + (REG_CPM_MSCCDR = (REG_CPM_MSCCDR & ~CPM_MSCCDR_MSCDIV_MASK) | ((v) << (CPM_MSCCDR_MSCDIV_BIT))) +#define __cpm_set_uhcdiv(v) \ + (REG_CPM_UHCCDR = (REG_CPM_UHCCDR & ~CPM_UHCCDR_UHCDIV_MASK) | ((v) << (CPM_UHCCDR_UHCDIV_BIT))) +#define __cpm_ssiclk_select_exclk() \ + (REG_CPM_SSICDR &= ~CPM_SSICDR_SCS) +#define __cpm_ssiclk_select_pllout() \ + (REG_CPM_SSICDR |= CPM_SSICDR_SCS) +#define __cpm_set_ssidiv(v) \ + (REG_CPM_SSICDR = (REG_CPM_SSICDR & ~CPM_SSICDR_SSIDIV_MASK) | ((v) << (CPM_SSICDR_SSIDIV_BIT))) + +#define __cpm_select_i2sclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_I2CS) +#define __cpm_select_i2sclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_I2CS) +#define __cpm_enable_cko() (REG_CPM_CPCCR |= CPM_CPCCR_CLKOEN) +#define __cpm_select_usbclk_exclk() (REG_CPM_CPCCR &= ~CPM_CPCCR_UCS) +#define __cpm_select_usbclk_pll() (REG_CPM_CPCCR |= CPM_CPCCR_UCS) +#define __cpm_enable_pll_change() (REG_CPM_CPCCR |= CPM_CPCCR_CE) +#define __cpm_pllout_direct() (REG_CPM_CPCCR |= CPM_CPCCR_PCS) +#define __cpm_pllout_div2() (REG_CPM_CPCCR &= ~CPM_CPCCR_PCS) + +#define __cpm_pll_is_on() (REG_CPM_CPPCR & CPM_CPPCR_PLLS) +#define __cpm_pll_bypass() (REG_CPM_CPPCR |= CPM_CPPCR_PLLBP) +#define __cpm_pll_enable() (REG_CPM_CPPCR |= CPM_CPPCR_PLLEN) + +#define __cpm_get_cclk_doze_duty() \ + ((REG_CPM_LCR & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT) +#define __cpm_set_cclk_doze_duty(v) \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_DOZE_DUTY_MASK) | ((v) << (CPM_LCR_DOZE_DUTY_BIT))) + +#define __cpm_doze_mode() (REG_CPM_LCR |= CPM_LCR_DOZE_ON) +#define __cpm_idle_mode() \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_IDLE) +#define __cpm_sleep_mode() \ + (REG_CPM_LCR = (REG_CPM_LCR & ~CPM_LCR_LPM_MASK) | CPM_LCR_LPM_SLEEP) + +#define __cpm_stop_all() (REG_CPM_CLKGR = 0x7fff) +#define __cpm_stop_uart1() (REG_CPM_CLKGR |= CPM_CLKGR_UART1) +#define __cpm_stop_uhc() (REG_CPM_CLKGR |= CPM_CLKGR_UHC) +#define __cpm_stop_ipu() (REG_CPM_CLKGR |= CPM_CLKGR_IPU) +#define __cpm_stop_dmac() (REG_CPM_CLKGR |= CPM_CLKGR_DMAC) +#define __cpm_stop_udc() (REG_CPM_CLKGR |= CPM_CLKGR_UDC) +#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD) +#define __cpm_stop_cim() (REG_CPM_CLKGR |= CPM_CLKGR_CIM) +#define __cpm_stop_sadc() (REG_CPM_CLKGR |= CPM_CLKGR_SADC) +#define __cpm_stop_msc() (REG_CPM_CLKGR |= CPM_CLKGR_MSC) +#define __cpm_stop_aic1() (REG_CPM_CLKGR |= CPM_CLKGR_AIC1) +#define __cpm_stop_aic2() (REG_CPM_CLKGR |= CPM_CLKGR_AIC2) +#define __cpm_stop_ssi() (REG_CPM_CLKGR |= CPM_CLKGR_SSI) +#define __cpm_stop_i2c() (REG_CPM_CLKGR |= CPM_CLKGR_I2C) +#define __cpm_stop_rtc() (REG_CPM_CLKGR |= CPM_CLKGR_RTC) +#define __cpm_stop_tcu() (REG_CPM_CLKGR |= CPM_CLKGR_TCU) +#define __cpm_stop_uart0() (REG_CPM_CLKGR |= CPM_CLKGR_UART0) + +#define __cpm_start_all() (REG_CPM_CLKGR = 0x0) +#define __cpm_start_uart1() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART1) +#define __cpm_start_uhc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UHC) +#define __cpm_start_ipu() (REG_CPM_CLKGR &= ~CPM_CLKGR_IPU) +#define __cpm_start_dmac() (REG_CPM_CLKGR &= ~CPM_CLKGR_DMAC) +#define __cpm_start_udc() (REG_CPM_CLKGR &= ~CPM_CLKGR_UDC) +#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD) +#define __cpm_start_cim() (REG_CPM_CLKGR &= ~CPM_CLKGR_CIM) +#define __cpm_start_sadc() (REG_CPM_CLKGR &= ~CPM_CLKGR_SADC) +#define __cpm_start_msc() (REG_CPM_CLKGR &= ~CPM_CLKGR_MSC) +#define __cpm_start_aic1() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC1) +#define __cpm_start_aic2() (REG_CPM_CLKGR &= ~CPM_CLKGR_AIC2) +#define __cpm_start_ssi() (REG_CPM_CLKGR &= ~CPM_CLKGR_SSI) +#define __cpm_start_i2c() (REG_CPM_CLKGR &= ~CPM_CLKGR_I2C) +#define __cpm_start_rtc() (REG_CPM_CLKGR &= ~CPM_CLKGR_RTC) +#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU) +#define __cpm_start_uart0() (REG_CPM_CLKGR &= ~CPM_CLKGR_UART0) + +#define __cpm_get_o1st() \ + ((REG_CPM_SCR & CPM_SCR_O1ST_MASK) >> CPM_SCR_O1ST_BIT) +#define __cpm_set_o1st(v) \ + (REG_CPM_SCR = (REG_CPM_SCR & ~CPM_SCR_O1ST_MASK) | ((v) << (CPM_SCR_O1ST_BIT))) +#define __cpm_suspend_usbphy() (REG_CPM_SCR |= CPM_SCR_USBPHY_SUSPEND) +#define __cpm_enable_osc_in_sleep() (REG_CPM_SCR |= CPM_SCR_OSC_ENABLE) + + +/*************************************************************************** + * TCU + ***************************************************************************/ +// where 'n' is the TCU channel +#define __tcu_select_extalclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_EXT_EN) +#define __tcu_select_rtcclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_RTC_EN) +#define __tcu_select_pclk(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~(TCU_TCSR_EXT_EN | TCU_TCSR_RTC_EN | TCU_TCSR_PCK_EN)) | TCU_TCSR_PCK_EN) + +#define __tcu_select_clk_div1(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1) +#define __tcu_select_clk_div4(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE4) +#define __tcu_select_clk_div16(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE16) +#define __tcu_select_clk_div64(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE64) +#define __tcu_select_clk_div256(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE256) +#define __tcu_select_clk_div1024(n) \ + (REG_TCU_TCSR((n)) = (REG_TCU_TCSR((n)) & ~TCU_TCSR_PRESCALE_MASK) | TCU_TCSR_PRESCALE1024) + +#define __tcu_enable_pwm_output(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_EN ) +#define __tcu_disable_pwm_output(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_EN ) + +#define __tcu_init_pwm_output_high(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_INITL_HIGH ) +#define __tcu_init_pwm_output_low(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_INITL_HIGH ) + +#define __tcu_set_pwm_output_shutdown_graceful(n) ( REG_TCU_TCSR((n)) &= ~TCU_TCSR_PWM_SD ) +#define __tcu_set_pwm_output_shutdown_abrupt(n) ( REG_TCU_TCSR((n)) |= TCU_TCSR_PWM_SD ) + +#define __tcu_start_counter(n) ( REG_TCU_TESR |= (1 << (n)) ) +#define __tcu_stop_counter(n) ( REG_TCU_TECR |= (1 << (n)) ) + +#define __tcu_half_match_flag(n) ( REG_TCU_TFR & (1 << ((n) + 16)) ) +#define __tcu_full_match_flag(n) ( REG_TCU_TFR & (1 << (n)) ) +#define __tcu_set_half_match_flag(n) ( REG_TCU_TFSR = (1 << ((n) + 16)) ) +#define __tcu_set_full_match_flag(n) ( REG_TCU_TFSR = (1 << (n)) ) +#define __tcu_clear_half_match_flag(n) ( REG_TCU_TFCR = (1 << ((n) + 16)) ) +#define __tcu_clear_full_match_flag(n) ( REG_TCU_TFCR = (1 << (n)) ) +#define __tcu_mask_half_match_irq(n) ( REG_TCU_TMSR = (1 << ((n) + 16)) ) +#define __tcu_mask_full_match_irq(n) ( REG_TCU_TMSR = (1 << (n)) ) +#define __tcu_unmask_half_match_irq(n) ( REG_TCU_TMCR = (1 << ((n) + 16)) ) +#define __tcu_unmask_full_match_irq(n) ( REG_TCU_TMCR = (1 << (n)) ) + +#define __tcu_wdt_clock_stopped() ( REG_TCU_TSR & TCU_TSSR_WDTSC ) +#define __tcu_timer_clock_stopped(n) ( REG_TCU_TSR & (1 << (n)) ) + +#define __tcu_start_wdt_clock() ( REG_TCU_TSCR = TCU_TSSR_WDTSC ) +#define __tcu_start_timer_clock(n) ( REG_TCU_TSCR = (1 << (n)) ) + +#define __tcu_stop_wdt_clock() ( REG_TCU_TSSR = TCU_TSSR_WDTSC ) +#define __tcu_stop_timer_clock(n) ( REG_TCU_TSSR = (1 << (n)) ) + +#define __tcu_get_count(n) ( REG_TCU_TCNT((n)) ) +#define __tcu_set_count(n,v) ( REG_TCU_TCNT((n)) = (v) ) +#define __tcu_set_full_data(n,v) ( REG_TCU_TDFR((n)) = (v) ) +#define __tcu_set_half_data(n,v) ( REG_TCU_TDHR((n)) = (v) ) + + +/*************************************************************************** + * WDT + ***************************************************************************/ +#define __wdt_start() ( REG_WDT_TCER |= WDT_TCER_TCEN ) +#define __wdt_stop() ( REG_WDT_TCER &= ~WDT_TCER_TCEN ) +#define __wdt_set_count(v) ( REG_WDT_TCNT = (v) ) +#define __wdt_set_data(v) ( REG_WDT_TDR = (v) ) + +#define __wdt_select_extalclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_EXT_EN) +#define __wdt_select_rtcclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_RTC_EN) +#define __wdt_select_pclk() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN)) | WDT_TCSR_PCK_EN) + +#define __wdt_select_clk_div1() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1) +#define __wdt_select_clk_div4() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE4) +#define __wdt_select_clk_div16() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE16) +#define __wdt_select_clk_div64() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE64) +#define __wdt_select_clk_div256() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE256) +#define __wdt_select_clk_div1024() \ + (REG_WDT_TCSR = (REG_WDT_TCSR & ~WDT_TCSR_PRESCALE_MASK) | WDT_TCSR_PRESCALE1024) + + +/*************************************************************************** + * UART + ***************************************************************************/ + +#define __uart_enable(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) |= UARTFCR_UUE | UARTFCR_FE ) +#define __uart_disable(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_FCR) = ~UARTFCR_UUE ) + +#define __uart_enable_transmit_irq(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_TIE ) +#define __uart_disable_transmit_irq(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~UARTIER_TIE ) + +#define __uart_enable_receive_irq(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) |= UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE ) +#define __uart_disable_receive_irq(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_IER) &= ~(UARTIER_RIE | UARTIER_RLIE | UARTIER_RTIE) ) + +#define __uart_enable_loopback(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) |= UARTMCR_LOOP ) +#define __uart_disable_loopback(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_MCR) &= ~UARTMCR_LOOP ) + +#define __uart_set_8n1(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) = UARTLCR_WLEN_8 ) + +#define __uart_set_baud(n, devclk, baud) \ + do { \ + REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) |= UARTLCR_DLAB; \ + REG8(UART_BASE + UART_OFF*(n) + OFF_DLLR) = (devclk / 16 / baud) & 0xff; \ + REG8(UART_BASE + UART_OFF*(n) + OFF_DLHR) = ((devclk / 16 / baud) >> 8) & 0xff; \ + REG8(UART_BASE + UART_OFF*(n) + OFF_LCR) &= ~UARTLCR_DLAB; \ + } while (0) + +#define __uart_parity_error(n) \ + ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_PER) != 0 ) + +#define __uart_clear_errors(n) \ + ( REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) &= ~(UARTLSR_ORER | UARTLSR_BRK | UARTLSR_FER | UARTLSR_PER | UARTLSR_RFER) ) + +#define __uart_transmit_fifo_empty(n) \ + ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TDRQ) != 0 ) + +#define __uart_transmit_end(n) \ + ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_TEMT) != 0 ) + +#define __uart_transmit_char(n, ch) \ + REG8(UART_BASE + UART_OFF*(n) + OFF_TDR) = (ch) + +#define __uart_receive_fifo_full(n) \ + ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) + +#define __uart_receive_ready(n) \ + ( (REG8(UART_BASE + UART_OFF*(n) + OFF_LSR) & UARTLSR_DR) != 0 ) + +#define __uart_receive_char(n) \ + REG8(UART_BASE + UART_OFF*(n) + OFF_RDR) + +#define __uart_disable_irda() \ + ( REG8(IRDA_BASE + OFF_SIRCR) &= ~(SIRCR_TSIRE | SIRCR_RSIRE) ) +#define __uart_enable_irda() \ + /* Tx high pulse as 0, Rx low pulse as 0 */ \ + ( REG8(IRDA_BASE + OFF_SIRCR) = SIRCR_TSIRE | SIRCR_RSIRE | SIRCR_RXPL | SIRCR_TPWS ) + + +/*************************************************************************** + * DMAC + ***************************************************************************/ + +/* n is the DMA channel (0 - 5) */ + +#define __dmac_enable_module() \ + ( REG_DMAC_DMACR |= DMAC_DMACR_DMAE | DMAC_DMACR_PR_RR ) +#define __dmac_disable_module() \ + ( REG_DMAC_DMACR &= ~DMAC_DMACR_DMAE ) + +/* p=0,1,2,3 */ +#define __dmac_set_priority(p) \ +do { \ + REG_DMAC_DMACR &= ~DMAC_DMACR_PR_MASK; \ + REG_DMAC_DMACR |= ((p) << DMAC_DMACR_PR_BIT); \ +} while (0) + +#define __dmac_test_halt_error() ( REG_DMAC_DMACR & DMAC_DMACR_HLT ) +#define __dmac_test_addr_error() ( REG_DMAC_DMACR & DMAC_DMACR_AR ) + +#define __dmac_enable_descriptor(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_NDES ) +#define __dmac_disable_descriptor(n) \ + ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_NDES ) + +#define __dmac_enable_channel(n) \ + ( REG_DMAC_DCCSR((n)) |= DMAC_DCCSR_EN ) +#define __dmac_disable_channel(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_EN ) +#define __dmac_channel_enabled(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_EN ) + +#define __dmac_channel_enable_irq(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TIE ) +#define __dmac_channel_disable_irq(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TIE ) + +#define __dmac_channel_transmit_halt_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_HLT ) +#define __dmac_channel_transmit_end_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_TT ) +#define __dmac_channel_address_error_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_AR ) +#define __dmac_channel_count_terminated_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_CT ) +#define __dmac_channel_descriptor_invalid_detected(n) \ + ( REG_DMAC_DCCSR((n)) & DMAC_DCCSR_INV ) + +#define __dmac_channel_clear_transmit_halt(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_HLT ) +#define __dmac_channel_clear_transmit_end(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_TT ) +#define __dmac_channel_clear_address_error(n) \ + ( REG_DMAC_DCCSR(n) &= ~DMAC_DCCSR_AR ) +#define __dmac_channel_clear_count_terminated(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_CT ) +#define __dmac_channel_clear_descriptor_invalid(n) \ + ( REG_DMAC_DCCSR((n)) &= ~DMAC_DCCSR_INV ) + +#define __dmac_channel_set_single_mode(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_TM ) +#define __dmac_channel_set_block_mode(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_TM ) + +#define __dmac_channel_set_transfer_unit_32bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_16bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_8bit(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_8BIT; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_16byte(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_16BYTE; \ +} while (0) + +#define __dmac_channel_set_transfer_unit_32byte(n) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DS_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DS_32BYTE; \ +} while (0) + +/* w=8,16,32 */ +#define __dmac_channel_set_dest_port_width(n,w) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DWDH_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_DWDH_##w; \ +} while (0) + +/* w=8,16,32 */ +#define __dmac_channel_set_src_port_width(n,w) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SWDH_MASK; \ + REG_DMAC_DCMD((n)) |= DMAC_DCMD_SWDH_##w; \ +} while (0) + +/* v=0-15 */ +#define __dmac_channel_set_rdil(n,v) \ +do { \ + REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_RDIL_MASK; \ + REG_DMAC_DCMD((n) |= ((v) << DMAC_DCMD_RDIL_BIT); \ +} while (0) + +#define __dmac_channel_dest_addr_fixed(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_DAI ) +#define __dmac_channel_dest_addr_increment(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_DAI ) + +#define __dmac_channel_src_addr_fixed(n) \ + ( REG_DMAC_DCMD((n)) &= ~DMAC_DCMD_SAI ) +#define __dmac_channel_src_addr_increment(n) \ + ( REG_DMAC_DCMD((n)) |= DMAC_DCMD_SAI ) + +#define __dmac_channel_set_doorbell(n) \ + ( REG_DMAC_DMADBSR = (1 << (n)) ) + +#define __dmac_channel_irq_detected(n) ( REG_DMAC_DMAIPR & (1 << (n)) ) +#define __dmac_channel_ack_irq(n) ( REG_DMAC_DMAIPR &= ~(1 << (n)) ) + +static __inline__ int __dmac_get_irq(void) +{ + int i; + for (i = 0; i < MAX_DMA_NUM; i++) + if (__dmac_channel_irq_detected(i)) + return i; + return -1; +} + + +/*************************************************************************** + * AIC (AC'97 & I2S Controller) + ***************************************************************************/ + +#define __aic_enable() ( REG_AIC_FR |= AIC_FR_ENB ) +#define __aic_disable() ( REG_AIC_FR &= ~AIC_FR_ENB ) + +#define __aic_select_ac97() ( REG_AIC_FR &= ~AIC_FR_AUSEL ) +#define __aic_select_i2s() ( REG_AIC_FR |= AIC_FR_AUSEL ) + +#define __aic_play_zero() ( REG_AIC_FR &= ~AIC_FR_LSMP ) +#define __aic_play_lastsample() ( REG_AIC_FR |= AIC_FR_LSMP ) + +#define __i2s_as_master() ( REG_AIC_FR |= AIC_FR_BCKD | AIC_FR_SYNCD ) +#define __i2s_as_slave() ( REG_AIC_FR &= ~(AIC_FR_BCKD | AIC_FR_SYNCD) ) +#define __aic_reset_status() ( REG_AIC_FR & AIC_FR_RST ) + +#define __aic_reset() \ +do { \ + REG_AIC_FR |= AIC_FR_RST; \ +} while(0) + + +#define __aic_set_transmit_trigger(n) \ +do { \ + REG_AIC_FR &= ~AIC_FR_TFTH_MASK; \ + REG_AIC_FR |= ((n) << AIC_FR_TFTH_BIT); \ +} while(0) + +#define __aic_set_receive_trigger(n) \ +do { \ + REG_AIC_FR &= ~AIC_FR_RFTH_MASK; \ + REG_AIC_FR |= ((n) << AIC_FR_RFTH_BIT); \ +} while(0) + +#define __aic_enable_record() ( REG_AIC_CR |= AIC_CR_EREC ) +#define __aic_disable_record() ( REG_AIC_CR &= ~AIC_CR_EREC ) +#define __aic_enable_replay() ( REG_AIC_CR |= AIC_CR_ERPL ) +#define __aic_disable_replay() ( REG_AIC_CR &= ~AIC_CR_ERPL ) +#define __aic_enable_loopback() ( REG_AIC_CR |= AIC_CR_ENLBF ) +#define __aic_disable_loopback() ( REG_AIC_CR &= ~AIC_CR_ENLBF ) + +#define __aic_flush_fifo() ( REG_AIC_CR |= AIC_CR_FLUSH ) +#define __aic_unflush_fifo() ( REG_AIC_CR &= ~AIC_CR_FLUSH ) + +#define __aic_enable_transmit_intr() \ + ( REG_AIC_CR |= (AIC_CR_ETFS | AIC_CR_ETUR) ) +#define __aic_disable_transmit_intr() \ + ( REG_AIC_CR &= ~(AIC_CR_ETFS | AIC_CR_ETUR) ) +#define __aic_enable_receive_intr() \ + ( REG_AIC_CR |= (AIC_CR_ERFS | AIC_CR_EROR) ) +#define __aic_disable_receive_intr() \ + ( REG_AIC_CR &= ~(AIC_CR_ERFS | AIC_CR_EROR) ) + +#define __aic_enable_transmit_dma() ( REG_AIC_CR |= AIC_CR_TDMS ) +#define __aic_disable_transmit_dma() ( REG_AIC_CR &= ~AIC_CR_TDMS ) +#define __aic_enable_receive_dma() ( REG_AIC_CR |= AIC_CR_RDMS ) +#define __aic_disable_receive_dma() ( REG_AIC_CR &= ~AIC_CR_RDMS ) + +#define __aic_enable_mono2stereo() ( REG_AIC_CR |= AIC_CR_M2S ) +#define __aic_disable_mono2stereo() ( REG_AIC_CR &= ~AIC_CR_M2S ) +#define __aic_enable_byteswap() ( REG_AIC_CR |= AIC_CR_ENDSW ) +#define __aic_disable_byteswap() ( REG_AIC_CR &= ~AIC_CR_ENDSW ) +#define __aic_enable_unsignadj() ( REG_AIC_CR |= AIC_CR_AVSTSU ) +#define __aic_disable_unsignadj() ( REG_AIC_CR &= ~AIC_CR_AVSTSU ) + +#define AC97_PCM_XS_L_FRONT AIC_ACCR1_XS_SLOT3 +#define AC97_PCM_XS_R_FRONT AIC_ACCR1_XS_SLOT4 +#define AC97_PCM_XS_CENTER AIC_ACCR1_XS_SLOT6 +#define AC97_PCM_XS_L_SURR AIC_ACCR1_XS_SLOT7 +#define AC97_PCM_XS_R_SURR AIC_ACCR1_XS_SLOT8 +#define AC97_PCM_XS_LFE AIC_ACCR1_XS_SLOT9 + +#define AC97_PCM_RS_L_FRONT AIC_ACCR1_RS_SLOT3 +#define AC97_PCM_RS_R_FRONT AIC_ACCR1_RS_SLOT4 +#define AC97_PCM_RS_CENTER AIC_ACCR1_RS_SLOT6 +#define AC97_PCM_RS_L_SURR AIC_ACCR1_RS_SLOT7 +#define AC97_PCM_RS_R_SURR AIC_ACCR1_RS_SLOT8 +#define AC97_PCM_RS_LFE AIC_ACCR1_RS_SLOT9 + +#define __ac97_set_xs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK ) +#define __ac97_set_xs_mono() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_XS_R_FRONT; \ +} while(0) +#define __ac97_set_xs_stereo() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_XS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_XS_L_FRONT | AC97_PCM_XS_R_FRONT; \ +} while(0) + +/* In fact, only stereo is support now. */ +#define __ac97_set_rs_none() ( REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK ) +#define __ac97_set_rs_mono() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_RS_R_FRONT; \ +} while(0) +#define __ac97_set_rs_stereo() \ +do { \ + REG_AIC_ACCR1 &= ~AIC_ACCR1_RS_MASK; \ + REG_AIC_ACCR1 |= AC97_PCM_RS_L_FRONT | AC97_PCM_RS_R_FRONT; \ +} while(0) + +#define __ac97_warm_reset_codec() \ + do { \ + REG_AIC_ACCR2 |= AIC_ACCR2_SA; \ + REG_AIC_ACCR2 |= AIC_ACCR2_SS; \ + udelay(2); \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SS; \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SA; \ + } while (0) + +#define __ac97_cold_reset_codec() \ + do { \ + REG_AIC_ACCR2 |= AIC_ACCR2_SR; \ + udelay(2); \ + REG_AIC_ACCR2 &= ~AIC_ACCR2_SR; \ + } while (0) + +/* n=8,16,18,20 */ +#define __ac97_set_iass(n) \ + ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_IASS_MASK) | AIC_ACCR2_IASS_##n##BIT ) +#define __ac97_set_oass(n) \ + ( REG_AIC_ACCR2 = (REG_AIC_ACCR2 & ~AIC_ACCR2_OASS_MASK) | AIC_ACCR2_OASS_##n##BIT ) + +#define __i2s_select_i2s() ( REG_AIC_I2SCR &= ~AIC_I2SCR_AMSL ) +#define __i2s_select_msbjustified() ( REG_AIC_I2SCR |= AIC_I2SCR_AMSL ) + +/* n=8,16,18,20,24 */ +/*#define __i2s_set_sample_size(n) \ + ( REG_AIC_I2SCR |= (REG_AIC_I2SCR & ~AIC_I2SCR_WL_MASK) | AIC_I2SCR_WL_##n##BIT )*/ + +#define __i2s_set_oss_sample_size(n) \ + ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_OSS_MASK) | AIC_CR_OSS_##n##BIT ) +#define __i2s_set_iss_sample_size(n) \ + ( REG_AIC_CR = (REG_AIC_CR & ~AIC_CR_ISS_MASK) | AIC_CR_ISS_##n##BIT ) + +#define __i2s_stop_bitclk() ( REG_AIC_I2SCR |= AIC_I2SCR_STPBK ) +#define __i2s_start_bitclk() ( REG_AIC_I2SCR &= ~AIC_I2SCR_STPBK ) + +#define __aic_transmit_request() ( REG_AIC_SR & AIC_SR_TFS ) +#define __aic_receive_request() ( REG_AIC_SR & AIC_SR_RFS ) +#define __aic_transmit_underrun() ( REG_AIC_SR & AIC_SR_TUR ) +#define __aic_receive_overrun() ( REG_AIC_SR & AIC_SR_ROR ) + +#define __aic_clear_errors() ( REG_AIC_SR &= ~(AIC_SR_TUR | AIC_SR_ROR) ) + +#define __aic_get_transmit_resident() \ + ( (REG_AIC_SR & AIC_SR_TFL_MASK) >> AIC_SR_TFL_BIT ) +#define __aic_get_receive_count() \ + ( (REG_AIC_SR & AIC_SR_RFL_MASK) >> AIC_SR_RFL_BIT ) + +#define __ac97_command_transmitted() ( REG_AIC_ACSR & AIC_ACSR_CADT ) +#define __ac97_status_received() ( REG_AIC_ACSR & AIC_ACSR_SADR ) +#define __ac97_status_receive_timeout() ( REG_AIC_ACSR & AIC_ACSR_RSTO ) +#define __ac97_codec_is_low_power_mode() ( REG_AIC_ACSR & AIC_ACSR_CLPM ) +#define __ac97_codec_is_ready() ( REG_AIC_ACSR & AIC_ACSR_CRDY ) +#define __ac97_slot_error_detected() ( REG_AIC_ACSR & AIC_ACSR_SLTERR ) +#define __ac97_clear_slot_error() ( REG_AIC_ACSR &= ~AIC_ACSR_SLTERR ) + +#define __i2s_is_busy() ( REG_AIC_I2SSR & AIC_I2SSR_BSY ) + +#define CODEC_READ_CMD (1 << 19) +#define CODEC_WRITE_CMD (0 << 19) +#define CODEC_REG_INDEX_BIT 12 +#define CODEC_REG_INDEX_MASK (0x7f << CODEC_REG_INDEX_BIT) /* 18:12 */ +#define CODEC_REG_DATA_BIT 4 +#define CODEC_REG_DATA_MASK (0x0ffff << 4) /* 19:4 */ + +#define __ac97_out_rcmd_addr(reg) \ +do { \ + REG_AIC_ACCAR = CODEC_READ_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ +} while (0) + +#define __ac97_out_wcmd_addr(reg) \ +do { \ + REG_AIC_ACCAR = CODEC_WRITE_CMD | ((reg) << CODEC_REG_INDEX_BIT); \ +} while (0) + +#define __ac97_out_data(value) \ +do { \ + REG_AIC_ACCDR = ((value) << CODEC_REG_DATA_BIT); \ +} while (0) + +#define __ac97_in_data() \ + ( (REG_AIC_ACSDR & CODEC_REG_DATA_MASK) >> CODEC_REG_DATA_BIT ) + +#define __ac97_in_status_addr() \ + ( (REG_AIC_ACSAR & CODEC_REG_INDEX_MASK) >> CODEC_REG_INDEX_BIT ) + +#define __i2s_set_sample_rate(i2sclk, sync) \ + ( REG_AIC_I2SDIV = ((i2sclk) / (4*64)) / (sync) ) + +#define __aic_write_tfifo(v) ( REG_AIC_DR = (v) ) +#define __aic_read_rfifo() ( REG_AIC_DR ) + +#define __aic_internal_codec() ( REG_AIC_FR |= AIC_FR_ICDC ) +#define __aic_external_codec() ( REG_AIC_FR &= ~AIC_FR_ICDC ) + +// +// Define next ops for AC97 compatible +// + +#define AC97_ACSR AIC_ACSR + +#define __ac97_enable() __aic_enable(); __aic_select_ac97() +#define __ac97_disable() __aic_disable() +#define __ac97_reset() __aic_reset() + +#define __ac97_set_transmit_trigger(n) __aic_set_transmit_trigger(n) +#define __ac97_set_receive_trigger(n) __aic_set_receive_trigger(n) + +#define __ac97_enable_record() __aic_enable_record() +#define __ac97_disable_record() __aic_disable_record() +#define __ac97_enable_replay() __aic_enable_replay() +#define __ac97_disable_replay() __aic_disable_replay() +#define __ac97_enable_loopback() __aic_enable_loopback() +#define __ac97_disable_loopback() __aic_disable_loopback() + +#define __ac97_enable_transmit_dma() __aic_enable_transmit_dma() +#define __ac97_disable_transmit_dma() __aic_disable_transmit_dma() +#define __ac97_enable_receive_dma() __aic_enable_receive_dma() +#define __ac97_disable_receive_dma() __aic_disable_receive_dma() + +#define __ac97_transmit_request() __aic_transmit_request() +#define __ac97_receive_request() __aic_receive_request() +#define __ac97_transmit_underrun() __aic_transmit_underrun() +#define __ac97_receive_overrun() __aic_receive_overrun() + +#define __ac97_clear_errors() __aic_clear_errors() + +#define __ac97_get_transmit_resident() __aic_get_transmit_resident() +#define __ac97_get_receive_count() __aic_get_receive_count() + +#define __ac97_enable_transmit_intr() __aic_enable_transmit_intr() +#define __ac97_disable_transmit_intr() __aic_disable_transmit_intr() +#define __ac97_enable_receive_intr() __aic_enable_receive_intr() +#define __ac97_disable_receive_intr() __aic_disable_receive_intr() + +#define __ac97_write_tfifo(v) __aic_write_tfifo(v) +#define __ac97_read_rfifo() __aic_read_rfifo() + +// +// Define next ops for I2S compatible +// + +#define I2S_ACSR AIC_I2SSR + +#define __i2s_enable() __aic_enable(); __aic_select_i2s() +#define __i2s_disable() __aic_disable() +#define __i2s_reset() __aic_reset() + +#define __i2s_set_transmit_trigger(n) __aic_set_transmit_trigger(n) +#define __i2s_set_receive_trigger(n) __aic_set_receive_trigger(n) + +#define __i2s_enable_record() __aic_enable_record() +#define __i2s_disable_record() __aic_disable_record() +#define __i2s_enable_replay() __aic_enable_replay() +#define __i2s_disable_replay() __aic_disable_replay() +#define __i2s_enable_loopback() __aic_enable_loopback() +#define __i2s_disable_loopback() __aic_disable_loopback() + +#define __i2s_enable_transmit_dma() __aic_enable_transmit_dma() +#define __i2s_disable_transmit_dma() __aic_disable_transmit_dma() +#define __i2s_enable_receive_dma() __aic_enable_receive_dma() +#define __i2s_disable_receive_dma() __aic_disable_receive_dma() + +#define __i2s_transmit_request() __aic_transmit_request() +#define __i2s_receive_request() __aic_receive_request() +#define __i2s_transmit_underrun() __aic_transmit_underrun() +#define __i2s_receive_overrun() __aic_receive_overrun() + +#define __i2s_clear_errors() __aic_clear_errors() + +#define __i2s_get_transmit_resident() __aic_get_transmit_resident() +#define __i2s_get_receive_count() __aic_get_receive_count() + +#define __i2s_enable_transmit_intr() __aic_enable_transmit_intr() +#define __i2s_disable_transmit_intr() __aic_disable_transmit_intr() +#define __i2s_enable_receive_intr() __aic_enable_receive_intr() +#define __i2s_disable_receive_intr() __aic_disable_receive_intr() + +#define __i2s_write_tfifo(v) __aic_write_tfifo(v) +#define __i2s_read_rfifo() __aic_read_rfifo() + +#define __i2s_reset_codec() \ + do { \ + } while (0) + + +/*************************************************************************** + * ICDC + ***************************************************************************/ +#define __i2s_internal_codec() __aic_internal_codec() +#define __i2s_external_codec() __aic_external_codec() + +/*************************************************************************** + * INTC + ***************************************************************************/ +#define __intc_unmask_irq(n) ( REG_INTC_IMCR = (1 << (n)) ) +#define __intc_mask_irq(n) ( REG_INTC_IMSR = (1 << (n)) ) +#define __intc_ack_irq(n) ( REG_INTC_IPR = (1 << (n)) ) + + +/*************************************************************************** + * I2C + ***************************************************************************/ + +#define __i2c_enable() ( REG_I2C_CR |= I2C_CR_I2CE ) +#define __i2c_disable() ( REG_I2C_CR &= ~I2C_CR_I2CE ) + +#define __i2c_send_start() ( REG_I2C_CR |= I2C_CR_STA ) +#define __i2c_send_stop() ( REG_I2C_CR |= I2C_CR_STO ) +#define __i2c_send_ack() ( REG_I2C_CR &= ~I2C_CR_AC ) +#define __i2c_send_nack() ( REG_I2C_CR |= I2C_CR_AC ) + +#define __i2c_set_drf() ( REG_I2C_SR |= I2C_SR_DRF ) +#define __i2c_clear_drf() ( REG_I2C_SR &= ~I2C_SR_DRF ) +#define __i2c_check_drf() ( REG_I2C_SR & I2C_SR_DRF ) + +#define __i2c_received_ack() ( !(REG_I2C_SR & I2C_SR_ACKF) ) +#define __i2c_is_busy() ( REG_I2C_SR & I2C_SR_BUSY ) +#define __i2c_transmit_ended() ( REG_I2C_SR & I2C_SR_TEND ) + +#define __i2c_set_clk(dev_clk, i2c_clk) \ + ( REG_I2C_GR = (dev_clk) / (16*(i2c_clk)) - 1 ) + +#define __i2c_read() ( REG_I2C_DR ) +#define __i2c_write(val) ( REG_I2C_DR = (val) ) + + +/*************************************************************************** + * MSC + ***************************************************************************/ + +#define __msc_start_op() \ + ( REG_MSC_STRPCL = MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START ) + +#define __msc_set_resto(to) ( REG_MSC_RESTO = to ) +#define __msc_set_rdto(to) ( REG_MSC_RDTO = to ) +#define __msc_set_cmd(cmd) ( REG_MSC_CMD = cmd ) +#define __msc_set_arg(arg) ( REG_MSC_ARG = arg ) +#define __msc_set_nob(nob) ( REG_MSC_NOB = nob ) +#define __msc_get_nob() ( REG_MSC_NOB ) +#define __msc_set_blklen(len) ( REG_MSC_BLKLEN = len ) +#define __msc_set_cmdat(cmdat) ( REG_MSC_CMDAT = cmdat ) +#define __msc_set_cmdat_ioabort() ( REG_MSC_CMDAT |= MSC_CMDAT_IO_ABORT ) +#define __msc_clear_cmdat_ioabort() ( REG_MSC_CMDAT &= ~MSC_CMDAT_IO_ABORT ) + +#define __msc_set_cmdat_bus_width1() \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ + REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_1BIT; \ +} while(0) + +#define __msc_set_cmdat_bus_width4() \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_BUS_WIDTH_MASK; \ + REG_MSC_CMDAT |= MSC_CMDAT_BUS_WIDTH_4BIT; \ +} while(0) + +#define __msc_set_cmdat_dma_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DMA_EN ) +#define __msc_set_cmdat_init() ( REG_MSC_CMDAT |= MSC_CMDAT_INIT ) +#define __msc_set_cmdat_busy() ( REG_MSC_CMDAT |= MSC_CMDAT_BUSY ) +#define __msc_set_cmdat_stream() ( REG_MSC_CMDAT |= MSC_CMDAT_STREAM_BLOCK ) +#define __msc_set_cmdat_block() ( REG_MSC_CMDAT &= ~MSC_CMDAT_STREAM_BLOCK ) +#define __msc_set_cmdat_read() ( REG_MSC_CMDAT &= ~MSC_CMDAT_WRITE_READ ) +#define __msc_set_cmdat_write() ( REG_MSC_CMDAT |= MSC_CMDAT_WRITE_READ ) +#define __msc_set_cmdat_data_en() ( REG_MSC_CMDAT |= MSC_CMDAT_DATA_EN ) + +/* r is MSC_CMDAT_RESPONSE_FORMAT_Rx or MSC_CMDAT_RESPONSE_FORMAT_NONE */ +#define __msc_set_cmdat_res_format(r) \ +do { \ + REG_MSC_CMDAT &= ~MSC_CMDAT_RESPONSE_FORMAT_MASK; \ + REG_MSC_CMDAT |= (r); \ +} while(0) + +#define __msc_clear_cmdat() \ + REG_MSC_CMDAT &= ~( MSC_CMDAT_IO_ABORT | MSC_CMDAT_DMA_EN | MSC_CMDAT_INIT| \ + MSC_CMDAT_BUSY | MSC_CMDAT_STREAM_BLOCK | MSC_CMDAT_WRITE_READ | \ + MSC_CMDAT_DATA_EN | MSC_CMDAT_RESPONSE_FORMAT_MASK ) + +#define __msc_get_imask() ( REG_MSC_IMASK ) +#define __msc_mask_all_intrs() ( REG_MSC_IMASK = 0xff ) +#define __msc_unmask_all_intrs() ( REG_MSC_IMASK = 0x00 ) +#define __msc_mask_rd() ( REG_MSC_IMASK |= MSC_IMASK_RXFIFO_RD_REQ ) +#define __msc_unmask_rd() ( REG_MSC_IMASK &= ~MSC_IMASK_RXFIFO_RD_REQ ) +#define __msc_mask_wr() ( REG_MSC_IMASK |= MSC_IMASK_TXFIFO_WR_REQ ) +#define __msc_unmask_wr() ( REG_MSC_IMASK &= ~MSC_IMASK_TXFIFO_WR_REQ ) +#define __msc_mask_endcmdres() ( REG_MSC_IMASK |= MSC_IMASK_END_CMD_RES ) +#define __msc_unmask_endcmdres() ( REG_MSC_IMASK &= ~MSC_IMASK_END_CMD_RES ) +#define __msc_mask_datatrandone() ( REG_MSC_IMASK |= MSC_IMASK_DATA_TRAN_DONE ) +#define __msc_unmask_datatrandone() ( REG_MSC_IMASK &= ~MSC_IMASK_DATA_TRAN_DONE ) +#define __msc_mask_prgdone() ( REG_MSC_IMASK |= MSC_IMASK_PRG_DONE ) +#define __msc_unmask_prgdone() ( REG_MSC_IMASK &= ~MSC_IMASK_PRG_DONE ) + +/* n=0,1,2,3,4,5,6,7 */ +#define __msc_set_clkrt(n) \ +do { \ + REG_MSC_CLKRT = n; \ +} while(0) + +#define __msc_get_ireg() ( REG_MSC_IREG ) +#define __msc_ireg_rd() ( REG_MSC_IREG & MSC_IREG_RXFIFO_RD_REQ ) +#define __msc_ireg_wr() ( REG_MSC_IREG & MSC_IREG_TXFIFO_WR_REQ ) +#define __msc_ireg_end_cmd_res() ( REG_MSC_IREG & MSC_IREG_END_CMD_RES ) +#define __msc_ireg_data_tran_done() ( REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE ) +#define __msc_ireg_prg_done() ( REG_MSC_IREG & MSC_IREG_PRG_DONE ) +#define __msc_ireg_clear_end_cmd_res() ( REG_MSC_IREG = MSC_IREG_END_CMD_RES ) +#define __msc_ireg_clear_data_tran_done() ( REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE ) +#define __msc_ireg_clear_prg_done() ( REG_MSC_IREG = MSC_IREG_PRG_DONE ) + +#define __msc_get_stat() ( REG_MSC_STAT ) +#define __msc_stat_not_end_cmd_res() ( (REG_MSC_STAT & MSC_STAT_END_CMD_RES) == 0) +#define __msc_stat_crc_err() \ + ( REG_MSC_STAT & (MSC_STAT_CRC_RES_ERR | MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR_YES) ) +#define __msc_stat_res_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_RES_ERR ) +#define __msc_stat_rd_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_READ_ERROR ) +#define __msc_stat_wr_crc_err() ( REG_MSC_STAT & MSC_STAT_CRC_WRITE_ERROR_YES ) +#define __msc_stat_resto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_RES ) +#define __msc_stat_rdto_err() ( REG_MSC_STAT & MSC_STAT_TIME_OUT_READ ) + +#define __msc_rd_resfifo() ( REG_MSC_RES ) +#define __msc_rd_rxfifo() ( REG_MSC_RXFIFO ) +#define __msc_wr_txfifo(v) ( REG_MSC_TXFIFO = v ) + +#define __msc_reset() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_RESET; \ + while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \ +} while (0) + +#define __msc_start_clk() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START; \ +} while (0) + +#define __msc_stop_clk() \ +do { \ + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; \ +} while (0) + +#define MMC_CLK 19169200 +#define SD_CLK 24576000 + +/* msc_clk should little than pclk and little than clk retrieve from card */ +#define __msc_calc_clk_divisor(type,dev_clk,msc_clk,lv) \ +do { \ + unsigned int rate, pclk, i; \ + pclk = dev_clk; \ + rate = type?SD_CLK:MMC_CLK; \ + if (msc_clk && msc_clk < pclk) \ + pclk = msc_clk; \ + i = 0; \ + while (pclk < rate) \ + { \ + i ++; \ + rate >>= 1; \ + } \ + lv = i; \ +} while(0) + +/* divide rate to little than or equal to 400kHz */ +#define __msc_calc_slow_clk_divisor(type, lv) \ +do { \ + unsigned int rate, i; \ + rate = (type?SD_CLK:MMC_CLK)/1000/400; \ + i = 0; \ + while (rate > 0) \ + { \ + rate >>= 1; \ + i ++; \ + } \ + lv = i; \ +} while(0) + + +/*************************************************************************** + * SSI + ***************************************************************************/ + +#define __ssi_enable() ( REG_SSI_CR0 |= SSI_CR0_SSIE ) +#define __ssi_disable() ( REG_SSI_CR0 &= ~SSI_CR0_SSIE ) +#define __ssi_select_ce() ( REG_SSI_CR0 &= ~SSI_CR0_FSEL ) + +#define __ssi_normal_mode() ( REG_SSI_ITR &= ~SSI_ITR_IVLTM_MASK ) + +#define __ssi_select_ce2() \ +do { \ + REG_SSI_CR0 |= SSI_CR0_FSEL; \ + REG_SSI_CR1 &= ~SSI_CR1_MULTS; \ +} while (0) + +#define __ssi_select_gpc() \ +do { \ + REG_SSI_CR0 &= ~SSI_CR0_FSEL; \ + REG_SSI_CR1 |= SSI_CR1_MULTS; \ +} while (0) + +#define __ssi_enable_tx_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_TIE | SSI_CR0_TEIE ) + +#define __ssi_disable_tx_intr() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_TIE | SSI_CR0_TEIE) ) + +#define __ssi_enable_rx_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_RIE | SSI_CR0_REIE ) + +#define __ssi_disable_rx_intr() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_RIE | SSI_CR0_REIE) ) + +#define __ssi_enable_txfifo_half_empty_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_TIE ) +#define __ssi_disable_txfifo_half_empty_intr() \ + ( REG_SSI_CR0 &= ~SSI_CR0_TIE ) +#define __ssi_enable_tx_error_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_TEIE ) +#define __ssi_disable_tx_error_intr() \ + ( REG_SSI_CR0 &= ~SSI_CR0_TEIE ) + +#define __ssi_enable_rxfifo_half_full_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_RIE ) +#define __ssi_disable_rxfifo_half_full_intr() \ + ( REG_SSI_CR0 &= ~SSI_CR0_RIE ) +#define __ssi_enable_rx_error_intr() \ + ( REG_SSI_CR0 |= SSI_CR0_REIE ) +#define __ssi_disable_rx_error_intr() \ + ( REG_SSI_CR0 &= ~SSI_CR0_REIE ) + +#define __ssi_enable_loopback() ( REG_SSI_CR0 |= SSI_CR0_LOOP ) +#define __ssi_disable_loopback() ( REG_SSI_CR0 &= ~SSI_CR0_LOOP ) + +#define __ssi_enable_receive() ( REG_SSI_CR0 &= ~SSI_CR0_DISREV ) +#define __ssi_disable_receive() ( REG_SSI_CR0 |= SSI_CR0_DISREV ) + +#define __ssi_finish_receive() \ + ( REG_SSI_CR0 |= (SSI_CR0_RFINE | SSI_CR0_RFINC) ) + +#define __ssi_disable_recvfinish() \ + ( REG_SSI_CR0 &= ~(SSI_CR0_RFINE | SSI_CR0_RFINC) ) + +#define __ssi_flush_txfifo() ( REG_SSI_CR0 |= SSI_CR0_TFLUSH ) +#define __ssi_flush_rxfifo() ( REG_SSI_CR0 |= SSI_CR0_RFLUSH ) + +#define __ssi_flush_fifo() \ + ( REG_SSI_CR0 |= SSI_CR0_TFLUSH | SSI_CR0_RFLUSH ) + +#define __ssi_finish_transmit() ( REG_SSI_CR1 &= ~SSI_CR1_UNFIN ) +#define __ssi_wait_transmit() ( REG_SSI_CR1 |= SSI_CR1_UNFIN ) + +#define __ssi_spi_format() \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ + REG_SSI_CR1 |= SSI_CR1_FMAT_SPI; \ + REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ + REG_SSI_CR1 |= (SSI_CR1_TFVCK_1 | SSI_CR1_TCKFI_1); \ +} while (0) + +/* TI's SSP format, must clear SSI_CR1.UNFIN */ +#define __ssi_ssp_format() \ +do { \ + REG_SSI_CR1 &= ~(SSI_CR1_FMAT_MASK | SSI_CR1_UNFIN); \ + REG_SSI_CR1 |= SSI_CR1_FMAT_SSP; \ +} while (0) + +/* National's Microwire format, must clear SSI_CR0.RFINE, and set max delay */ +#define __ssi_microwire_format() \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_FMAT_MASK; \ + REG_SSI_CR1 |= SSI_CR1_FMAT_MW1; \ + REG_SSI_CR1 &= ~(SSI_CR1_TFVCK_MASK|SSI_CR1_TCKFI_MASK);\ + REG_SSI_CR1 |= (SSI_CR1_TFVCK_3 | SSI_CR1_TCKFI_3); \ + REG_SSI_CR0 &= ~SSI_CR0_RFINE; \ +} while (0) + +/* CE# level (FRMHL), CE# in interval time (ITFRM), + clock phase and polarity (PHA POL), + interval time (SSIITR), interval characters/frame (SSIICR) */ + + /* frmhl,endian,mcom,flen,pha,pol MASK */ +#define SSICR1_MISC_MASK \ + ( SSI_CR1_FRMHL_MASK | SSI_CR1_LFST | SSI_CR1_MCOM_MASK \ + | SSI_CR1_FLEN_MASK | SSI_CR1_PHA | SSI_CR1_POL ) \ + +#define __ssi_spi_set_misc(frmhl,endian,flen,mcom,pha,pol) \ +do { \ + REG_SSI_CR1 &= ~SSICR1_MISC_MASK; \ + REG_SSI_CR1 |= ((frmhl) << 30) | ((endian) << 25) | \ + (((mcom) - 1) << 12) | (((flen) - 2) << 4) | \ + ((pha) << 1) | (pol); \ +} while(0) + +/* Transfer with MSB or LSB first */ +#define __ssi_set_msb() ( REG_SSI_CR1 &= ~SSI_CR1_LFST ) +#define __ssi_set_lsb() ( REG_SSI_CR1 |= SSI_CR1_LFST ) + +#define __ssi_set_frame_length(n) \ + REG_SSI_CR1 = (REG_SSI_CR1 & ~SSI_CR1_FLEN_MASK) | (((n) - 2) << 4) + +/* n = 1 - 16 */ +#define __ssi_set_microwire_command_length(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_MCOM_MASK) | SSI_CR1_MCOM_##n##BIT) ) + +/* Set the clock phase for SPI */ +#define __ssi_set_spi_clock_phase(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_PHA) | ((n&0x1)<< 1))) + +/* Set the clock polarity for SPI */ +#define __ssi_set_spi_clock_polarity(n) \ + ( REG_SSI_CR1 = ((REG_SSI_CR1 & ~SSI_CR1_POL) | (n&0x1)) ) + +/* n = ix8 */ +#define __ssi_set_tx_trigger(n) \ +do { \ + REG_SSI_CR1 &= ~SSI_CR1_TTRG_MASK; \ + REG_SSI_CR1 |= (n/8)<> SSI_SR_TFIFONUM_BIT ) + +#define __ssi_get_rxfifo_count() \ + ( (REG_SSI_SR & SSI_SR_RFIFONUM_MASK) >> SSI_SR_RFIFONUM_BIT ) + +#define __ssi_transfer_end() ( REG_SSI_SR & SSI_SR_END ) +#define __ssi_is_busy() ( REG_SSI_SR & SSI_SR_BUSY ) + +#define __ssi_txfifo_full() ( REG_SSI_SR & SSI_SR_TFF ) +#define __ssi_rxfifo_empty() ( REG_SSI_SR & SSI_SR_RFE ) +#define __ssi_rxfifo_half_full() ( REG_SSI_SR & SSI_SR_RFHF ) +#define __ssi_txfifo_half_empty() ( REG_SSI_SR & SSI_SR_TFHE ) +#define __ssi_underrun() ( REG_SSI_SR & SSI_SR_UNDR ) +#define __ssi_overrun() ( REG_SSI_SR & SSI_SR_OVER ) +#define __ssi_clear_underrun() ( REG_SSI_SR = ~SSI_SR_UNDR ) +#define __ssi_clear_overrun() ( REG_SSI_SR = ~SSI_SR_OVER ) +#define __ssi_clear_errors() \ + ( REG_SSI_SR &= ~(SSI_SR_UNDR | SSI_SR_OVER) ) + + +#define __ssi_set_clk(dev_clk, ssi_clk) \ + ( REG_SSI_GR = (dev_clk) / (2*(ssi_clk)) - 1 ) + +#define __ssi_receive_data() REG_SSI_DR +#define __ssi_transmit_data(v) ( REG_SSI_DR = (v) ) + + +/*************************************************************************** + * CIM + ***************************************************************************/ + +#define __cim_enable() ( REG_CIM_CTRL |= CIM_CTRL_ENA ) +#define __cim_disable() ( REG_CIM_CTRL &= ~CIM_CTRL_ENA ) + +#define __cim_input_data_inverse() ( REG_CIM_CFG |= CIM_CFG_INV_DAT ) +#define __cim_input_data_normal() ( REG_CIM_CFG &= ~CIM_CFG_INV_DAT ) + +#define __cim_vsync_active_low() ( REG_CIM_CFG |= CIM_CFG_VSP ) +#define __cim_vsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_VSP ) + +#define __cim_hsync_active_low() ( REG_CIM_CFG |= CIM_CFG_HSP ) +#define __cim_hsync_active_high() ( REG_CIM_CFG &= ~CIM_CFG_HSP ) + +#define __cim_sample_data_at_pclk_falling_edge() \ + ( REG_CIM_CFG |= CIM_CFG_PCP ) +#define __cim_sample_data_at_pclk_rising_edge() \ + ( REG_CIM_CFG &= ~CIM_CFG_PCP ) + +#define __cim_enable_dummy_zero() ( REG_CIM_CFG |= CIM_CFG_DUMMY_ZERO ) +#define __cim_disable_dummy_zero() ( REG_CIM_CFG &= ~CIM_CFG_DUMMY_ZERO ) + +#define __cim_select_external_vsync() ( REG_CIM_CFG |= CIM_CFG_EXT_VSYNC ) +#define __cim_select_internal_vsync() ( REG_CIM_CFG &= ~CIM_CFG_EXT_VSYNC ) + +/* n=0-7 */ +#define __cim_set_data_packing_mode(n) \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_PACK_MASK; \ + REG_CIM_CFG |= (CIM_CFG_PACK_##n); \ +} while (0) + +#define __cim_enable_ccir656_progressive_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_CPM; \ +} while (0) + +#define __cim_enable_ccir656_interlace_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_CIM; \ +} while (0) + +#define __cim_enable_gated_clock_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_GCM; \ +} while (0) + +#define __cim_enable_nongated_clock_mode() \ +do { \ + REG_CIM_CFG &= ~CIM_CFG_DSM_MASK; \ + REG_CIM_CFG |= CIM_CFG_DSM_NGCM; \ +} while (0) + +/* sclk:system bus clock + * mclk: CIM master clock + */ +#define __cim_set_master_clk(sclk, mclk) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_MCLKDIV_MASK; \ + REG_CIM_CTRL |= (((sclk)/(mclk) - 1) << CIM_CTRL_MCLKDIV_BIT); \ +} while (0) + +#define __cim_enable_sof_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_SOFM ) +#define __cim_disable_sof_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_SOFM ) + +#define __cim_enable_eof_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_EOFM ) +#define __cim_disable_eof_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EOFM ) + +#define __cim_enable_stop_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_DMA_STOPM ) +#define __cim_disable_stop_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_STOPM ) + +#define __cim_enable_trig_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_RXF_TRIGM ) +#define __cim_disable_trig_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIGM ) + +#define __cim_enable_rxfifo_overflow_intr() \ + ( REG_CIM_CTRL |= CIM_CTRL_RXF_OFM ) +#define __cim_disable_rxfifo_overflow_intr() \ + ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_OFM ) + +/* n=1-16 */ +#define __cim_set_frame_rate(n) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_FRC_MASK; \ + REG_CIM_CTRL |= CIM_CTRL_FRC_##n; \ +} while (0) + +#define __cim_enable_dma() ( REG_CIM_CTRL |= CIM_CTRL_DMA_EN ) +#define __cim_disable_dma() ( REG_CIM_CTRL &= ~CIM_CTRL_DMA_EN ) + +#define __cim_reset_rxfifo() ( REG_CIM_CTRL |= CIM_CTRL_RXF_RST ) +#define __cim_unreset_rxfifo() ( REG_CIM_CTRL &= ~CIM_CTRL_RXF_RST ) + +/* n=4,8,12,16,20,24,28,32 */ +#define __cim_set_rxfifo_trigger(n) \ +do { \ + REG_CIM_CTRL &= ~CIM_CTRL_RXF_TRIG_MASK; \ + REG_CIM_CTRL |= CIM_CTRL_RXF_TRIG_##n; \ +} while (0) + +#define __cim_clear_state() ( REG_CIM_STATE = 0 ) + +#define __cim_disable_done() ( REG_CIM_STATE & CIM_STATE_VDD ) +#define __cim_rxfifo_empty() ( REG_CIM_STATE & CIM_STATE_RXF_EMPTY ) +#define __cim_rxfifo_reach_trigger() ( REG_CIM_STATE & CIM_STATE_RXF_TRIG ) +#define __cim_rxfifo_overflow() ( REG_CIM_STATE & CIM_STATE_RXF_OF ) +#define __cim_clear_rxfifo_overflow() ( REG_CIM_STATE &= ~CIM_STATE_RXF_OF ) +#define __cim_dma_stop() ( REG_CIM_STATE & CIM_STATE_DMA_STOP ) +#define __cim_dma_eof() ( REG_CIM_STATE & CIM_STATE_DMA_EOF ) +#define __cim_dma_sof() ( REG_CIM_STATE & CIM_STATE_DMA_SOF ) + +#define __cim_get_iid() ( REG_CIM_IID ) +#define __cim_get_image_data() ( REG_CIM_RXFIFO ) +#define __cim_get_dam_cmd() ( REG_CIM_CMD ) + +#define __cim_set_da(a) ( REG_CIM_DA = (a) ) + +/*************************************************************************** + * LCD + ***************************************************************************/ +#define __lcd_as_smart_lcd() ( REG_LCD_CFG |= (1<> LCD_VSYNC_VPS_BIT ) + +#define __lcd_vsync_get_vpe() \ + ( (REG_LCD_VSYNC & LCD_VSYNC_VPE_MASK) >> LCD_VSYNC_VPE_BIT ) +#define __lcd_vsync_set_vpe(n) \ +do { \ + REG_LCD_VSYNC &= ~LCD_VSYNC_VPE_MASK; \ + REG_LCD_VSYNC |= (n) << LCD_VSYNC_VPE_BIT; \ +} while (0) + +#define __lcd_hsync_get_hps() \ + ( (REG_LCD_HSYNC & LCD_HSYNC_HPS_MASK) >> LCD_HSYNC_HPS_BIT ) +#define __lcd_hsync_set_hps(n) \ +do { \ + REG_LCD_HSYNC &= ~LCD_HSYNC_HPS_MASK; \ + REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPS_BIT; \ +} while (0) + +#define __lcd_hsync_get_hpe() \ + ( (REG_LCD_HSYNC & LCD_HSYNC_HPE_MASK) >> LCD_VSYNC_HPE_BIT ) +#define __lcd_hsync_set_hpe(n) \ +do { \ + REG_LCD_HSYNC &= ~LCD_HSYNC_HPE_MASK; \ + REG_LCD_HSYNC |= (n) << LCD_HSYNC_HPE_BIT; \ +} while (0) + +#define __lcd_vat_get_ht() \ + ( (REG_LCD_VAT & LCD_VAT_HT_MASK) >> LCD_VAT_HT_BIT ) +#define __lcd_vat_set_ht(n) \ +do { \ + REG_LCD_VAT &= ~LCD_VAT_HT_MASK; \ + REG_LCD_VAT |= (n) << LCD_VAT_HT_BIT; \ +} while (0) + +#define __lcd_vat_get_vt() \ + ( (REG_LCD_VAT & LCD_VAT_VT_MASK) >> LCD_VAT_VT_BIT ) +#define __lcd_vat_set_vt(n) \ +do { \ + REG_LCD_VAT &= ~LCD_VAT_VT_MASK; \ + REG_LCD_VAT |= (n) << LCD_VAT_VT_BIT; \ +} while (0) + +#define __lcd_dah_get_hds() \ + ( (REG_LCD_DAH & LCD_DAH_HDS_MASK) >> LCD_DAH_HDS_BIT ) +#define __lcd_dah_set_hds(n) \ +do { \ + REG_LCD_DAH &= ~LCD_DAH_HDS_MASK; \ + REG_LCD_DAH |= (n) << LCD_DAH_HDS_BIT; \ +} while (0) + +#define __lcd_dah_get_hde() \ + ( (REG_LCD_DAH & LCD_DAH_HDE_MASK) >> LCD_DAH_HDE_BIT ) +#define __lcd_dah_set_hde(n) \ +do { \ + REG_LCD_DAH &= ~LCD_DAH_HDE_MASK; \ + REG_LCD_DAH |= (n) << LCD_DAH_HDE_BIT; \ +} while (0) + +#define __lcd_dav_get_vds() \ + ( (REG_LCD_DAV & LCD_DAV_VDS_MASK) >> LCD_DAV_VDS_BIT ) +#define __lcd_dav_set_vds(n) \ +do { \ + REG_LCD_DAV &= ~LCD_DAV_VDS_MASK; \ + REG_LCD_DAV |= (n) << LCD_DAV_VDS_BIT; \ +} while (0) + +#define __lcd_dav_get_vde() \ + ( (REG_LCD_DAV & LCD_DAV_VDE_MASK) >> LCD_DAV_VDE_BIT ) +#define __lcd_dav_set_vde(n) \ +do { \ + REG_LCD_DAV &= ~LCD_DAV_VDE_MASK; \ + REG_LCD_DAV |= (n) << LCD_DAV_VDE_BIT; \ +} while (0) + +#define __lcd_cmd0_set_sofint() ( REG_LCD_CMD0 |= LCD_CMD_SOFINT ) +#define __lcd_cmd0_clr_sofint() ( REG_LCD_CMD0 &= ~LCD_CMD_SOFINT ) +#define __lcd_cmd1_set_sofint() ( REG_LCD_CMD1 |= LCD_CMD_SOFINT ) +#define __lcd_cmd1_clr_sofint() ( REG_LCD_CMD1 &= ~LCD_CMD_SOFINT ) + +#define __lcd_cmd0_set_eofint() ( REG_LCD_CMD0 |= LCD_CMD_EOFINT ) +#define __lcd_cmd0_clr_eofint() ( REG_LCD_CMD0 &= ~LCD_CMD_EOFINT ) +#define __lcd_cmd1_set_eofint() ( REG_LCD_CMD1 |= LCD_CMD_EOFINT ) +#define __lcd_cmd1_clr_eofint() ( REG_LCD_CMD1 &= ~LCD_CMD_EOFINT ) + +#define __lcd_cmd0_set_pal() ( REG_LCD_CMD0 |= LCD_CMD_PAL ) +#define __lcd_cmd0_clr_pal() ( REG_LCD_CMD0 &= ~LCD_CMD_PAL ) + +#define __lcd_cmd0_get_len() \ + ( (REG_LCD_CMD0 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) +#define __lcd_cmd1_get_len() \ + ( (REG_LCD_CMD1 & LCD_CMD_LEN_MASK) >> LCD_CMD_LEN_BIT ) + +/******************************************************* + * SMART LCD + *******************************************************/ + +#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) +#define __slcd_dma_disable() \ +do {\ + while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ + REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ +} while(0) + +/******************************************************* + * SMART LCD + *******************************************************/ + +#define __slcd_dma_enable() (REG_SLCD_CTRL |= SLCD_CTRL_DMA_EN) +#define __slcd_dma_disable() \ +do {\ + while (REG_SLCD_STATE & SLCD_STATE_BUSY); \ + REG_SLCD_CTRL &= ~SLCD_CTRL_DMA_EN; \ +} while(0) + +/*************************************************************************** + * RTC ops + ***************************************************************************/ + +#define __rtc_write_ready() ( (REG_RTC_RCR & RTC_RCR_WRDY) >> RTC_RCR_WRDY_BIT ) +#define __rtc_enabled() ( REG_RTC_RCR |= RTC_RCR_RTCE ) +#define __rtc_disabled() ( REG_RTC_RCR &= ~RTC_RCR_RTCE ) +#define __rtc_enable_alarm() ( REG_RTC_RCR |= RTC_RCR_AE ) +#define __rtc_disable_alarm() ( REG_RTC_RCR &= ~RTC_RCR_AE ) +#define __rtc_enable_alarm_irq() ( REG_RTC_RCR |= RTC_RCR_AIE ) +#define __rtc_disable_alarm_irq() ( REG_RTC_RCR &= ~RTC_RCR_AIE ) +#define __rtc_enable_1Hz_irq() ( REG_RTC_RCR |= RTC_RCR_1HZIE ) +#define __rtc_disable_1Hz_irq() ( REG_RTC_RCR &= ~RTC_RCR_1HZIE ) + +#define __rtc_get_1Hz_flag() ( (REG_RTC_RCR >> RTC_RCR_1HZ_BIT) & 0x1 ) +#define __rtc_clear_1Hz_flag() ( REG_RTC_RCR &= ~RTC_RCR_1HZ ) +#define __rtc_get_alarm_flag() ( (REG_RTC_RCR >> RTC_RCR_AF_BIT) & 0x1 ) +#define __rtc_clear_alarm_flag() ( REG_RTC_RCR &= ~RTC_RCR_AF ) + +#define __rtc_get_second() ( REG_RTC_RSR ) +#define __rtc_set_second(v) ( REG_RTC_RSR = v ) + +#define __rtc_get_alarm_second() ( REG_RTC_RSAR ) +#define __rtc_set_alarm_second(v) ( REG_RTC_RSAR = v ) + +#define __rtc_RGR_is_locked() ( (REG_RTC_RGR >> RTC_RGR_LOCK) ) +#define __rtc_lock_RGR() ( REG_RTC_RGR |= RTC_RGR_LOCK ) +#define __rtc_unlock_RGR() ( REG_RTC_RGR &= ~RTC_RGR_LOCK ) +#define __rtc_get_adjc_val() ( (REG_RTC_RGR & RTC_RGR_ADJC_MASK) >> RTC_RGR_ADJC_BIT ) +#define __rtc_set_adjc_val(v) \ + ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_ADJC_MASK) | (v << RTC_RGR_ADJC_BIT) )) +#define __rtc_get_nc1Hz_val() ( (REG_RTC_RGR & RTC_RGR_NC1HZ_MASK) >> RTC_RGR_NC1HZ_BIT ) +#define __rtc_set_nc1Hz_val(v) \ + ( REG_RTC_RGR = ( (REG_RTC_RGR & ~RTC_RGR_NC1HZ_MASK) | (v << RTC_RGR_NC1HZ_BIT) )) + +#define __rtc_power_down() ( REG_RTC_HCR |= RTC_HCR_PD ) + +#define __rtc_get_hwfcr_val() ( REG_RTC_HWFCR & RTC_HWFCR_MASK ) +#define __rtc_set_hwfcr_val(v) ( REG_RTC_HWFCR = (v) & RTC_HWFCR_MASK ) +#define __rtc_get_hrcr_val() ( REG_RTC_HRCR & RTC_HRCR_MASK ) +#define __rtc_set_hrcr_val(v) ( REG_RTC_HRCR = (v) & RTC_HRCR_MASK ) + +#define __rtc_enable_alarm_wakeup() ( REG_RTC_HWCR |= RTC_HWCR_EALM ) +#define __rtc_disable_alarm_wakeup() ( REG_RTC_HWCR &= ~RTC_HWCR_EALM ) + +#define __rtc_status_hib_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_HR) & 0x1 ) +#define __rtc_status_ppr_reset_occur() ( (REG_RTC_HWRSR >> RTC_HWRSR_PPR) & 0x1 ) +#define __rtc_status_wakeup_pin_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_PIN) & 0x1 ) +#define __rtc_status_alarm_waken_up() ( (REG_RTC_HWRSR >> RTC_HWRSR_ALM) & 0x1 ) +#define __rtc_clear_hib_stat_all() ( REG_RTC_HWRSR = 0 ) + +#define __rtc_get_scratch_pattern() (REG_RTC_HSPR) +#define __rtc_set_scratch_pattern(n) (REG_RTC_HSPR = n ) + + + +#endif /* __JZ4740_OPS_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/platform.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/platform.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/platform.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/platform.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,19 @@ + +#ifndef __JZ4740_PLATFORM_H +#define __JZ4740_PLATFORM_H + +#include + +extern struct platform_device jz4740_usb_ohci_device; +extern struct platform_device jz4740_usb_gdt_device; +extern struct platform_device jz4740_mmc_device; +extern struct platform_device jz4740_rtc_device; +extern struct platform_device jz4740_i2c_device; +extern struct platform_device jz4740_nand_device; +extern struct platform_device jz4740_framebuffer_device; +extern struct platform_device jz4740_i2s_device; +extern struct platform_device jz4740_codec_device; +extern struct platform_device jz4740_adc_device; +extern struct platform_device jz4740_battery_device; + +#endif diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/regs.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/regs.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/regs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/regs.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,2397 @@ +/* + * linux/include/asm-mips/mach-jz4740/regs.h + * + * Ingenic's JZ4740 common include. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __JZ4740_REGS_H__ +#define __JZ4740_REGS_H__ + +#if defined(__ASSEMBLY__) || defined(__LANGUAGE_ASSEMBLY) +#define REG8(addr) (addr) +#define REG16(addr) (addr) +#define REG32(addr) (addr) +#else +#define REG8(addr) *((volatile unsigned char *)(addr)) +#define REG16(addr) *((volatile unsigned short *)(addr)) +#define REG32(addr) *((volatile unsigned int *)(addr)) +#endif + +/* + * Define the module base addresses + */ +#define CPM_BASE 0xB0000000 +#define INTC_BASE 0xB0001000 +#define TCU_BASE 0xB0002000 +#define WDT_BASE 0xB0002000 +#define RTC_BASE 0xB0003000 +#define GPIO_BASE 0xB0010000 +#define AIC_BASE 0xB0020000 +#define ICDC_BASE 0xB0020000 +#define MSC_BASE 0xB0021000 +#define UART0_BASE 0xB0030000 +#define UART1_BASE 0xB0031000 +#define I2C_BASE 0xB0042000 +#define SSI_BASE 0xB0043000 +#define SADC_BASE 0xB0070000 +#define EMC_BASE 0xB3010000 +#define DMAC_BASE 0xB3020000 +#define UHC_BASE 0xB3030000 +#define UDC_BASE 0xB3040000 +#define LCD_BASE 0xB3050000 +#define SLCD_BASE 0xB3050000 +#define CIM_BASE 0xB3060000 +#define IPU_BASE 0xB3080000 +#define ETH_BASE 0xB3100000 + + +/************************************************************************* + * INTC (Interrupt Controller) + *************************************************************************/ +#define INTC_ISR (INTC_BASE + 0x00) +#define INTC_IMR (INTC_BASE + 0x04) +#define INTC_IMSR (INTC_BASE + 0x08) +#define INTC_IMCR (INTC_BASE + 0x0c) +#define INTC_IPR (INTC_BASE + 0x10) + +#define REG_INTC_ISR REG32(INTC_ISR) +#define REG_INTC_IMR REG32(INTC_IMR) +#define REG_INTC_IMSR REG32(INTC_IMSR) +#define REG_INTC_IMCR REG32(INTC_IMCR) +#define REG_INTC_IPR REG32(INTC_IPR) + +// 1st-level interrupts +#define JZ_IRQ_BASE 8 +#define JZ_IRQ(x) (JZ_IRQ_BASE + (x)) +#define JZ_IRQ_I2C JZ_IRQ(1) +#define JZ_IRQ_UHC JZ_IRQ(3) +#define JZ_IRQ_UART1 JZ_IRQ(8) +#define JZ_IRQ_UART0 JZ_IRQ(9) +#define JZ_IRQ_SADC JZ_IRQ(12) +#define JZ_IRQ_MSC JZ_IRQ(14) +#define JZ_IRQ_RTC JZ_IRQ(15) +#define JZ_IRQ_SSI JZ_IRQ(16) +#define JZ_IRQ_CIM JZ_IRQ(17) +#define JZ_IRQ_AIC JZ_IRQ(18) +#define JZ_IRQ_ETH JZ_IRQ(19) +#define JZ_IRQ_DMAC JZ_IRQ(20) +#define JZ_IRQ_TCU2 JZ_IRQ(21) +#define JZ_IRQ_TCU1 JZ_IRQ(22) +#define JZ_IRQ_TCU0 JZ_IRQ(23) +#define JZ_IRQ_UDC JZ_IRQ(24) +#define JZ_IRQ_GPIO3 JZ_IRQ(25) +#define JZ_IRQ_GPIO2 JZ_IRQ(26) +#define JZ_IRQ_GPIO1 JZ_IRQ(27) +#define JZ_IRQ_GPIO0 JZ_IRQ(28) +#define JZ_IRQ_IPU JZ_IRQ(29) +#define JZ_IRQ_LCD JZ_IRQ(30) + +/* 2nd-level interrupts */ +#define JZ_IRQ_DMA(x) ((x) + JZ_IRQ(32)) /* 32 to 37 for DMAC channel 0 to 5 */ +#define IRQ_GPIO_0 JZ_IRQ(48) /* 48 to 175 for GPIO pin 0 to 127 */ + +#define JZ_IRQ_INTC_GPIO(x) (JZ_IRQ_GPIO0 - (x)) +#define JZ_IRQ_GPIO(x) (IRQ_GPIO_0 + (x)) + +#define NUM_DMA 6 +#define NUM_GPIO 128 +/************************************************************************* + * RTC + *************************************************************************/ +#define RTC_RCR (RTC_BASE + 0x00) /* RTC Control Register */ +#define RTC_RSR (RTC_BASE + 0x04) /* RTC Second Register */ +#define RTC_RSAR (RTC_BASE + 0x08) /* RTC Second Alarm Register */ +#define RTC_RGR (RTC_BASE + 0x0c) /* RTC Regulator Register */ + +#define RTC_HCR (RTC_BASE + 0x20) /* Hibernate Control Register */ +#define RTC_HWFCR (RTC_BASE + 0x24) /* Hibernate Wakeup Filter Counter Reg */ +#define RTC_HRCR (RTC_BASE + 0x28) /* Hibernate Reset Counter Register */ +#define RTC_HWCR (RTC_BASE + 0x2c) /* Hibernate Wakeup Control Register */ +#define RTC_HWRSR (RTC_BASE + 0x30) /* Hibernate Wakeup Status Register */ +#define RTC_HSPR (RTC_BASE + 0x34) /* Hibernate Scratch Pattern Register */ + +#define REG_RTC_RCR REG32(RTC_RCR) +#define REG_RTC_RSR REG32(RTC_RSR) +#define REG_RTC_RSAR REG32(RTC_RSAR) +#define REG_RTC_RGR REG32(RTC_RGR) +#define REG_RTC_HCR REG32(RTC_HCR) +#define REG_RTC_HWFCR REG32(RTC_HWFCR) +#define REG_RTC_HRCR REG32(RTC_HRCR) +#define REG_RTC_HWCR REG32(RTC_HWCR) +#define REG_RTC_HWRSR REG32(RTC_HWRSR) +#define REG_RTC_HSPR REG32(RTC_HSPR) + +/* RTC Control Register */ +#define RTC_RCR_WRDY_BIT 7 +#define RTC_RCR_WRDY (1 << 7) /* Write Ready Flag */ +#define RTC_RCR_1HZ_BIT 6 +#define RTC_RCR_1HZ (1 << RTC_RCR_1HZ_BIT) /* 1Hz Flag */ +#define RTC_RCR_1HZIE (1 << 5) /* 1Hz Interrupt Enable */ +#define RTC_RCR_AF_BIT 4 +#define RTC_RCR_AF (1 << RTC_RCR_AF_BIT) /* Alarm Flag */ +#define RTC_RCR_AIE (1 << 3) /* Alarm Interrupt Enable */ +#define RTC_RCR_AE (1 << 2) /* Alarm Enable */ +#define RTC_RCR_RTCE (1 << 0) /* RTC Enable */ + +/* RTC Regulator Register */ +#define RTC_RGR_LOCK (1 << 31) /* Lock Bit */ +#define RTC_RGR_ADJC_BIT 16 +#define RTC_RGR_ADJC_MASK (0x3ff << RTC_RGR_ADJC_BIT) +#define RTC_RGR_NC1HZ_BIT 0 +#define RTC_RGR_NC1HZ_MASK (0xffff << RTC_RGR_NC1HZ_BIT) + +/* Hibernate Control Register */ +#define RTC_HCR_PD (1 << 0) /* Power Down */ + +/* Hibernate Wakeup Filter Counter Register */ +#define RTC_HWFCR_BIT 5 +#define RTC_HWFCR_MASK (0x7ff << RTC_HWFCR_BIT) + +/* Hibernate Reset Counter Register */ +#define RTC_HRCR_BIT 5 +#define RTC_HRCR_MASK (0x7f << RTC_HRCR_BIT) + +/* Hibernate Wakeup Control Register */ +#define RTC_HWCR_EALM (1 << 0) /* RTC alarm wakeup enable */ + +/* Hibernate Wakeup Status Register */ +#define RTC_HWRSR_HR (1 << 5) /* Hibernate reset */ +#define RTC_HWRSR_PPR (1 << 4) /* PPR reset */ +#define RTC_HWRSR_PIN (1 << 1) /* Wakeup pin status bit */ +#define RTC_HWRSR_ALM (1 << 0) /* RTC alarm status bit */ + + +/************************************************************************* + * CPM (Clock reset and Power control Management) + *************************************************************************/ +#define CPM_CPCCR (CPM_BASE+0x00) +#define CPM_CPPCR (CPM_BASE+0x10) +#define CPM_I2SCDR (CPM_BASE+0x60) +#define CPM_LPCDR (CPM_BASE+0x64) +#define CPM_MSCCDR (CPM_BASE+0x68) +#define CPM_UHCCDR (CPM_BASE+0x6C) +#define CPM_SSICDR (CPM_BASE+0x74) + +#define CPM_LCR (CPM_BASE+0x04) +#define CPM_CLKGR (CPM_BASE+0x20) +#define CPM_SCR (CPM_BASE+0x24) + +#define CPM_HCR (CPM_BASE+0x30) +#define CPM_HWFCR (CPM_BASE+0x34) +#define CPM_HRCR (CPM_BASE+0x38) +#define CPM_HWCR (CPM_BASE+0x3c) +#define CPM_HWSR (CPM_BASE+0x40) +#define CPM_HSPR (CPM_BASE+0x44) + +#define CPM_RSR (CPM_BASE+0x08) + + +#define REG_CPM_CPCCR REG32(CPM_CPCCR) +#define REG_CPM_CPPCR REG32(CPM_CPPCR) +#define REG_CPM_I2SCDR REG32(CPM_I2SCDR) +#define REG_CPM_LPCDR REG32(CPM_LPCDR) +#define REG_CPM_MSCCDR REG32(CPM_MSCCDR) +#define REG_CPM_UHCCDR REG32(CPM_UHCCDR) +#define REG_CPM_SSICDR REG32(CPM_SSICDR) + +#define REG_CPM_LCR REG32(CPM_LCR) +#define REG_CPM_CLKGR REG32(CPM_CLKGR) +#define REG_CPM_SCR REG32(CPM_SCR) +#define REG_CPM_HCR REG32(CPM_HCR) +#define REG_CPM_HWFCR REG32(CPM_HWFCR) +#define REG_CPM_HRCR REG32(CPM_HRCR) +#define REG_CPM_HWCR REG32(CPM_HWCR) +#define REG_CPM_HWSR REG32(CPM_HWSR) +#define REG_CPM_HSPR REG32(CPM_HSPR) + +#define REG_CPM_RSR REG32(CPM_RSR) + + +/* Clock Control Register */ +#define CPM_CPCCR_I2CS (1 << 31) +#define CPM_CPCCR_CLKOEN (1 << 30) +#define CPM_CPCCR_UCS (1 << 29) +#define CPM_CPCCR_UDIV_BIT 23 +#define CPM_CPCCR_UDIV_MASK (0x3f << CPM_CPCCR_UDIV_BIT) +#define CPM_CPCCR_CE (1 << 22) +#define CPM_CPCCR_PCS (1 << 21) +#define CPM_CPCCR_LDIV_BIT 16 +#define CPM_CPCCR_LDIV_MASK (0x1f << CPM_CPCCR_LDIV_BIT) +#define CPM_CPCCR_MDIV_BIT 12 +#define CPM_CPCCR_MDIV_MASK (0x0f << CPM_CPCCR_MDIV_BIT) +#define CPM_CPCCR_PDIV_BIT 8 +#define CPM_CPCCR_PDIV_MASK (0x0f << CPM_CPCCR_PDIV_BIT) +#define CPM_CPCCR_HDIV_BIT 4 +#define CPM_CPCCR_HDIV_MASK (0x0f << CPM_CPCCR_HDIV_BIT) +#define CPM_CPCCR_CDIV_BIT 0 +#define CPM_CPCCR_CDIV_MASK (0x0f << CPM_CPCCR_CDIV_BIT) + +/* I2S Clock Divider Register */ +#define CPM_I2SCDR_I2SDIV_BIT 0 +#define CPM_I2SCDR_I2SDIV_MASK (0x1ff << CPM_I2SCDR_I2SDIV_BIT) + +/* LCD Pixel Clock Divider Register */ +#define CPM_LPCDR_PIXDIV_BIT 0 +#define CPM_LPCDR_PIXDIV_MASK (0x7ff << CPM_LPCDR_PIXDIV_BIT) + +/* MSC Clock Divider Register */ +#define CPM_MSCCDR_MSCDIV_BIT 0 +#define CPM_MSCCDR_MSCDIV_MASK (0x1f << CPM_MSCCDR_MSCDIV_BIT) + +/* UHC Clock Divider Register */ +#define CPM_UHCCDR_UHCDIV_BIT 0 +#define CPM_UHCCDR_UHCDIV_MASK (0xf << CPM_UHCCDR_UHCDIV_BIT) + +/* SSI Clock Divider Register */ +#define CPM_SSICDR_SCS (1<<31) /* SSI clock source selection, 0:EXCLK, 1: PLL */ +#define CPM_SSICDR_SSIDIV_BIT 0 +#define CPM_SSICDR_SSIDIV_MASK (0xf << CPM_SSICDR_SSIDIV_BIT) + +/* PLL Control Register */ +#define CPM_CPPCR_PLLM_BIT 23 +#define CPM_CPPCR_PLLM_MASK (0x1ff << CPM_CPPCR_PLLM_BIT) +#define CPM_CPPCR_PLLN_BIT 18 +#define CPM_CPPCR_PLLN_MASK (0x1f << CPM_CPPCR_PLLN_BIT) +#define CPM_CPPCR_PLLOD_BIT 16 +#define CPM_CPPCR_PLLOD_MASK (0x03 << CPM_CPPCR_PLLOD_BIT) +#define CPM_CPPCR_PLLS (1 << 10) +#define CPM_CPPCR_PLLBP (1 << 9) +#define CPM_CPPCR_PLLEN (1 << 8) +#define CPM_CPPCR_PLLST_BIT 0 +#define CPM_CPPCR_PLLST_MASK (0xff << CPM_CPPCR_PLLST_BIT) + +/* Low Power Control Register */ +#define CPM_LCR_DOZE_DUTY_BIT 3 +#define CPM_LCR_DOZE_DUTY_MASK (0x1f << CPM_LCR_DOZE_DUTY_BIT) +#define CPM_LCR_DOZE_ON (1 << 2) +#define CPM_LCR_LPM_BIT 0 +#define CPM_LCR_LPM_MASK (0x3 << CPM_LCR_LPM_BIT) + #define CPM_LCR_LPM_IDLE (0x0 << CPM_LCR_LPM_BIT) + #define CPM_LCR_LPM_SLEEP (0x1 << CPM_LCR_LPM_BIT) + +/* Clock Gate Register */ +#define CPM_CLKGR_UART1 (1 << 15) +#define CPM_CLKGR_UHC (1 << 14) +#define CPM_CLKGR_IPU (1 << 13) +#define CPM_CLKGR_DMAC (1 << 12) +#define CPM_CLKGR_UDC (1 << 11) +#define CPM_CLKGR_LCD (1 << 10) +#define CPM_CLKGR_CIM (1 << 9) +#define CPM_CLKGR_SADC (1 << 8) +#define CPM_CLKGR_MSC (1 << 7) +#define CPM_CLKGR_AIC1 (1 << 6) +#define CPM_CLKGR_AIC2 (1 << 5) +#define CPM_CLKGR_SSI (1 << 4) +#define CPM_CLKGR_I2C (1 << 3) +#define CPM_CLKGR_RTC (1 << 2) +#define CPM_CLKGR_TCU (1 << 1) +#define CPM_CLKGR_UART0 (1 << 0) + +/* Sleep Control Register */ +#define CPM_SCR_O1ST_BIT 8 +#define CPM_SCR_O1ST_MASK (0xff << CPM_SCR_O1ST_BIT) +#define CPM_SCR_USBPHY_ENABLE (1 << 6) +#define CPM_SCR_OSC_ENABLE (1 << 4) + +/* Hibernate Control Register */ +#define CPM_HCR_PD (1 << 0) + +/* Wakeup Filter Counter Register in Hibernate Mode */ +#define CPM_HWFCR_TIME_BIT 0 +#define CPM_HWFCR_TIME_MASK (0x3ff << CPM_HWFCR_TIME_BIT) + +/* Reset Counter Register in Hibernate Mode */ +#define CPM_HRCR_TIME_BIT 0 +#define CPM_HRCR_TIME_MASK (0x7f << CPM_HRCR_TIME_BIT) + +/* Wakeup Control Register in Hibernate Mode */ +#define CPM_HWCR_WLE_LOW (0 << 2) +#define CPM_HWCR_WLE_HIGH (1 << 2) +#define CPM_HWCR_PIN_WAKEUP (1 << 1) +#define CPM_HWCR_RTC_WAKEUP (1 << 0) + +/* Wakeup Status Register in Hibernate Mode */ +#define CPM_HWSR_WSR_PIN (1 << 1) +#define CPM_HWSR_WSR_RTC (1 << 0) + +/* Reset Status Register */ +#define CPM_RSR_HR (1 << 2) +#define CPM_RSR_WR (1 << 1) +#define CPM_RSR_PR (1 << 0) + + +/************************************************************************* + * TCU (Timer Counter Unit) + *************************************************************************/ +#define TCU_TSR (TCU_BASE + 0x1C) /* Timer Stop Register */ +#define TCU_TSSR (TCU_BASE + 0x2C) /* Timer Stop Set Register */ +#define TCU_TSCR (TCU_BASE + 0x3C) /* Timer Stop Clear Register */ +#define TCU_TER (TCU_BASE + 0x10) /* Timer Counter Enable Register */ +#define TCU_TESR (TCU_BASE + 0x14) /* Timer Counter Enable Set Register */ +#define TCU_TECR (TCU_BASE + 0x18) /* Timer Counter Enable Clear Register */ +#define TCU_TFR (TCU_BASE + 0x20) /* Timer Flag Register */ +#define TCU_TFSR (TCU_BASE + 0x24) /* Timer Flag Set Register */ +#define TCU_TFCR (TCU_BASE + 0x28) /* Timer Flag Clear Register */ +#define TCU_TMR (TCU_BASE + 0x30) /* Timer Mask Register */ +#define TCU_TMSR (TCU_BASE + 0x34) /* Timer Mask Set Register */ +#define TCU_TMCR (TCU_BASE + 0x38) /* Timer Mask Clear Register */ +#define TCU_TDFR0 (TCU_BASE + 0x40) /* Timer Data Full Register */ +#define TCU_TDHR0 (TCU_BASE + 0x44) /* Timer Data Half Register */ +#define TCU_TCNT0 (TCU_BASE + 0x48) /* Timer Counter Register */ +#define TCU_TCSR0 (TCU_BASE + 0x4C) /* Timer Control Register */ +#define TCU_TDFR1 (TCU_BASE + 0x50) +#define TCU_TDHR1 (TCU_BASE + 0x54) +#define TCU_TCNT1 (TCU_BASE + 0x58) +#define TCU_TCSR1 (TCU_BASE + 0x5C) +#define TCU_TDFR2 (TCU_BASE + 0x60) +#define TCU_TDHR2 (TCU_BASE + 0x64) +#define TCU_TCNT2 (TCU_BASE + 0x68) +#define TCU_TCSR2 (TCU_BASE + 0x6C) +#define TCU_TDFR3 (TCU_BASE + 0x70) +#define TCU_TDHR3 (TCU_BASE + 0x74) +#define TCU_TCNT3 (TCU_BASE + 0x78) +#define TCU_TCSR3 (TCU_BASE + 0x7C) +#define TCU_TDFR4 (TCU_BASE + 0x80) +#define TCU_TDHR4 (TCU_BASE + 0x84) +#define TCU_TCNT4 (TCU_BASE + 0x88) +#define TCU_TCSR4 (TCU_BASE + 0x8C) +#define TCU_TDFR5 (TCU_BASE + 0x90) +#define TCU_TDHR5 (TCU_BASE + 0x94) +#define TCU_TCNT5 (TCU_BASE + 0x98) +#define TCU_TCSR5 (TCU_BASE + 0x9C) + +#define REG_TCU_TSR REG32(TCU_TSR) +#define REG_TCU_TSSR REG32(TCU_TSSR) +#define REG_TCU_TSCR REG32(TCU_TSCR) +#define REG_TCU_TER REG8(TCU_TER) +#define REG_TCU_TESR REG8(TCU_TESR) +#define REG_TCU_TECR REG8(TCU_TECR) +#define REG_TCU_TFR REG32(TCU_TFR) +#define REG_TCU_TFSR REG32(TCU_TFSR) +#define REG_TCU_TFCR REG32(TCU_TFCR) +#define REG_TCU_TMR REG32(TCU_TMR) +#define REG_TCU_TMSR REG32(TCU_TMSR) +#define REG_TCU_TMCR REG32(TCU_TMCR) +#define REG_TCU_TDFR0 REG16(TCU_TDFR0) +#define REG_TCU_TDHR0 REG16(TCU_TDHR0) +#define REG_TCU_TCNT0 REG16(TCU_TCNT0) +#define REG_TCU_TCSR0 REG16(TCU_TCSR0) +#define REG_TCU_TDFR1 REG16(TCU_TDFR1) +#define REG_TCU_TDHR1 REG16(TCU_TDHR1) +#define REG_TCU_TCNT1 REG16(TCU_TCNT1) +#define REG_TCU_TCSR1 REG16(TCU_TCSR1) +#define REG_TCU_TDFR2 REG16(TCU_TDFR2) +#define REG_TCU_TDHR2 REG16(TCU_TDHR2) +#define REG_TCU_TCNT2 REG16(TCU_TCNT2) +#define REG_TCU_TCSR2 REG16(TCU_TCSR2) +#define REG_TCU_TDFR3 REG16(TCU_TDFR3) +#define REG_TCU_TDHR3 REG16(TCU_TDHR3) +#define REG_TCU_TCNT3 REG16(TCU_TCNT3) +#define REG_TCU_TCSR3 REG16(TCU_TCSR3) +#define REG_TCU_TDFR4 REG16(TCU_TDFR4) +#define REG_TCU_TDHR4 REG16(TCU_TDHR4) +#define REG_TCU_TCNT4 REG16(TCU_TCNT4) +#define REG_TCU_TCSR4 REG16(TCU_TCSR4) + +// n = 0,1,2,3,4,5 +#define TCU_TDFR(n) (TCU_BASE + (0x40 + (n)*0x10)) /* Timer Data Full Reg */ +#define TCU_TDHR(n) (TCU_BASE + (0x44 + (n)*0x10)) /* Timer Data Half Reg */ +#define TCU_TCNT(n) (TCU_BASE + (0x48 + (n)*0x10)) /* Timer Counter Reg */ +#define TCU_TCSR(n) (TCU_BASE + (0x4C + (n)*0x10)) /* Timer Control Reg */ + +#define REG_TCU_TDFR(n) REG16(TCU_TDFR((n))) +#define REG_TCU_TDHR(n) REG16(TCU_TDHR((n))) +#define REG_TCU_TCNT(n) REG16(TCU_TCNT((n))) +#define REG_TCU_TCSR(n) REG16(TCU_TCSR((n))) + +// Register definitions +#define TCU_TCSR_PWM_SD (1 << 9) +#define TCU_TCSR_PWM_INITL_HIGH (1 << 8) +#define TCU_TCSR_PWM_EN (1 << 7) +#define TCU_TCSR_PRESCALE_BIT 3 +#define TCU_TCSR_PRESCALE_MASK (0x7 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE1 (0x0 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE4 (0x1 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE16 (0x2 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE64 (0x3 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE256 (0x4 << TCU_TCSR_PRESCALE_BIT) + #define TCU_TCSR_PRESCALE1024 (0x5 << TCU_TCSR_PRESCALE_BIT) +#define TCU_TCSR_EXT_EN (1 << 2) +#define TCU_TCSR_RTC_EN (1 << 1) +#define TCU_TCSR_PCK_EN (1 << 0) + +#define TCU_TER_TCEN5 (1 << 5) +#define TCU_TER_TCEN4 (1 << 4) +#define TCU_TER_TCEN3 (1 << 3) +#define TCU_TER_TCEN2 (1 << 2) +#define TCU_TER_TCEN1 (1 << 1) +#define TCU_TER_TCEN0 (1 << 0) + +#define TCU_TESR_TCST5 (1 << 5) +#define TCU_TESR_TCST4 (1 << 4) +#define TCU_TESR_TCST3 (1 << 3) +#define TCU_TESR_TCST2 (1 << 2) +#define TCU_TESR_TCST1 (1 << 1) +#define TCU_TESR_TCST0 (1 << 0) + +#define TCU_TECR_TCCL5 (1 << 5) +#define TCU_TECR_TCCL4 (1 << 4) +#define TCU_TECR_TCCL3 (1 << 3) +#define TCU_TECR_TCCL2 (1 << 2) +#define TCU_TECR_TCCL1 (1 << 1) +#define TCU_TECR_TCCL0 (1 << 0) + +#define TCU_TFR_HFLAG5 (1 << 21) +#define TCU_TFR_HFLAG4 (1 << 20) +#define TCU_TFR_HFLAG3 (1 << 19) +#define TCU_TFR_HFLAG2 (1 << 18) +#define TCU_TFR_HFLAG1 (1 << 17) +#define TCU_TFR_HFLAG0 (1 << 16) +#define TCU_TFR_FFLAG5 (1 << 5) +#define TCU_TFR_FFLAG4 (1 << 4) +#define TCU_TFR_FFLAG3 (1 << 3) +#define TCU_TFR_FFLAG2 (1 << 2) +#define TCU_TFR_FFLAG1 (1 << 1) +#define TCU_TFR_FFLAG0 (1 << 0) + +#define TCU_TFSR_HFLAG5 (1 << 21) +#define TCU_TFSR_HFLAG4 (1 << 20) +#define TCU_TFSR_HFLAG3 (1 << 19) +#define TCU_TFSR_HFLAG2 (1 << 18) +#define TCU_TFSR_HFLAG1 (1 << 17) +#define TCU_TFSR_HFLAG0 (1 << 16) +#define TCU_TFSR_FFLAG5 (1 << 5) +#define TCU_TFSR_FFLAG4 (1 << 4) +#define TCU_TFSR_FFLAG3 (1 << 3) +#define TCU_TFSR_FFLAG2 (1 << 2) +#define TCU_TFSR_FFLAG1 (1 << 1) +#define TCU_TFSR_FFLAG0 (1 << 0) + +#define TCU_TFCR_HFLAG5 (1 << 21) +#define TCU_TFCR_HFLAG4 (1 << 20) +#define TCU_TFCR_HFLAG3 (1 << 19) +#define TCU_TFCR_HFLAG2 (1 << 18) +#define TCU_TFCR_HFLAG1 (1 << 17) +#define TCU_TFCR_HFLAG0 (1 << 16) +#define TCU_TFCR_FFLAG5 (1 << 5) +#define TCU_TFCR_FFLAG4 (1 << 4) +#define TCU_TFCR_FFLAG3 (1 << 3) +#define TCU_TFCR_FFLAG2 (1 << 2) +#define TCU_TFCR_FFLAG1 (1 << 1) +#define TCU_TFCR_FFLAG0 (1 << 0) + +#define TCU_TMR_HMASK5 (1 << 21) +#define TCU_TMR_HMASK4 (1 << 20) +#define TCU_TMR_HMASK3 (1 << 19) +#define TCU_TMR_HMASK2 (1 << 18) +#define TCU_TMR_HMASK1 (1 << 17) +#define TCU_TMR_HMASK0 (1 << 16) +#define TCU_TMR_FMASK5 (1 << 5) +#define TCU_TMR_FMASK4 (1 << 4) +#define TCU_TMR_FMASK3 (1 << 3) +#define TCU_TMR_FMASK2 (1 << 2) +#define TCU_TMR_FMASK1 (1 << 1) +#define TCU_TMR_FMASK0 (1 << 0) + +#define TCU_TMSR_HMST5 (1 << 21) +#define TCU_TMSR_HMST4 (1 << 20) +#define TCU_TMSR_HMST3 (1 << 19) +#define TCU_TMSR_HMST2 (1 << 18) +#define TCU_TMSR_HMST1 (1 << 17) +#define TCU_TMSR_HMST0 (1 << 16) +#define TCU_TMSR_FMST5 (1 << 5) +#define TCU_TMSR_FMST4 (1 << 4) +#define TCU_TMSR_FMST3 (1 << 3) +#define TCU_TMSR_FMST2 (1 << 2) +#define TCU_TMSR_FMST1 (1 << 1) +#define TCU_TMSR_FMST0 (1 << 0) + +#define TCU_TMCR_HMCL5 (1 << 21) +#define TCU_TMCR_HMCL4 (1 << 20) +#define TCU_TMCR_HMCL3 (1 << 19) +#define TCU_TMCR_HMCL2 (1 << 18) +#define TCU_TMCR_HMCL1 (1 << 17) +#define TCU_TMCR_HMCL0 (1 << 16) +#define TCU_TMCR_FMCL5 (1 << 5) +#define TCU_TMCR_FMCL4 (1 << 4) +#define TCU_TMCR_FMCL3 (1 << 3) +#define TCU_TMCR_FMCL2 (1 << 2) +#define TCU_TMCR_FMCL1 (1 << 1) +#define TCU_TMCR_FMCL0 (1 << 0) + +#define TCU_TSR_WDTS (1 << 16) +#define TCU_TSR_STOP5 (1 << 5) +#define TCU_TSR_STOP4 (1 << 4) +#define TCU_TSR_STOP3 (1 << 3) +#define TCU_TSR_STOP2 (1 << 2) +#define TCU_TSR_STOP1 (1 << 1) +#define TCU_TSR_STOP0 (1 << 0) + +#define TCU_TSSR_WDTSS (1 << 16) +#define TCU_TSSR_STPS5 (1 << 5) +#define TCU_TSSR_STPS4 (1 << 4) +#define TCU_TSSR_STPS3 (1 << 3) +#define TCU_TSSR_STPS2 (1 << 2) +#define TCU_TSSR_STPS1 (1 << 1) +#define TCU_TSSR_STPS0 (1 << 0) + +#define TCU_TSSR_WDTSC (1 << 16) +#define TCU_TSSR_STPC5 (1 << 5) +#define TCU_TSSR_STPC4 (1 << 4) +#define TCU_TSSR_STPC3 (1 << 3) +#define TCU_TSSR_STPC2 (1 << 2) +#define TCU_TSSR_STPC1 (1 << 1) +#define TCU_TSSR_STPC0 (1 << 0) + + +/************************************************************************* + * WDT (WatchDog Timer) + *************************************************************************/ +#define WDT_TDR (WDT_BASE + 0x00) +#define WDT_TCER (WDT_BASE + 0x04) +#define WDT_TCNT (WDT_BASE + 0x08) +#define WDT_TCSR (WDT_BASE + 0x0C) + +#define REG_WDT_TDR REG16(WDT_TDR) +#define REG_WDT_TCER REG8(WDT_TCER) +#define REG_WDT_TCNT REG16(WDT_TCNT) +#define REG_WDT_TCSR REG16(WDT_TCSR) + +// Register definition +#define WDT_TCSR_PRESCALE_BIT 3 +#define WDT_TCSR_PRESCALE_MASK (0x7 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE1 (0x0 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE4 (0x1 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE16 (0x2 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE64 (0x3 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE256 (0x4 << WDT_TCSR_PRESCALE_BIT) + #define WDT_TCSR_PRESCALE1024 (0x5 << WDT_TCSR_PRESCALE_BIT) +#define WDT_TCSR_EXT_EN (1 << 2) +#define WDT_TCSR_RTC_EN (1 << 1) +#define WDT_TCSR_PCK_EN (1 << 0) + +#define WDT_TCER_TCEN (1 << 0) + + +/************************************************************************* + * DMAC (DMA Controller) + *************************************************************************/ + +#define MAX_DMA_NUM 6 /* max 6 channels */ + +#define DMAC_DSAR(n) (DMAC_BASE + (0x00 + (n) * 0x20)) /* DMA source address */ +#define DMAC_DTAR(n) (DMAC_BASE + (0x04 + (n) * 0x20)) /* DMA target address */ +#define DMAC_DTCR(n) (DMAC_BASE + (0x08 + (n) * 0x20)) /* DMA transfer count */ +#define DMAC_DRSR(n) (DMAC_BASE + (0x0c + (n) * 0x20)) /* DMA request source */ +#define DMAC_DCCSR(n) (DMAC_BASE + (0x10 + (n) * 0x20)) /* DMA control/status */ +#define DMAC_DCMD(n) (DMAC_BASE + (0x14 + (n) * 0x20)) /* DMA command */ +#define DMAC_DDA(n) (DMAC_BASE + (0x18 + (n) * 0x20)) /* DMA descriptor address */ +#define DMAC_DMACR (DMAC_BASE + 0x0300) /* DMA control register */ +#define DMAC_DMAIPR (DMAC_BASE + 0x0304) /* DMA interrupt pending */ +#define DMAC_DMADBR (DMAC_BASE + 0x0308) /* DMA doorbell */ +#define DMAC_DMADBSR (DMAC_BASE + 0x030C) /* DMA doorbell set */ + +// channel 0 +#define DMAC_DSAR0 DMAC_DSAR(0) +#define DMAC_DTAR0 DMAC_DTAR(0) +#define DMAC_DTCR0 DMAC_DTCR(0) +#define DMAC_DRSR0 DMAC_DRSR(0) +#define DMAC_DCCSR0 DMAC_DCCSR(0) +#define DMAC_DCMD0 DMAC_DCMD(0) +#define DMAC_DDA0 DMAC_DDA(0) + +// channel 1 +#define DMAC_DSAR1 DMAC_DSAR(1) +#define DMAC_DTAR1 DMAC_DTAR(1) +#define DMAC_DTCR1 DMAC_DTCR(1) +#define DMAC_DRSR1 DMAC_DRSR(1) +#define DMAC_DCCSR1 DMAC_DCCSR(1) +#define DMAC_DCMD1 DMAC_DCMD(1) +#define DMAC_DDA1 DMAC_DDA(1) + +// channel 2 +#define DMAC_DSAR2 DMAC_DSAR(2) +#define DMAC_DTAR2 DMAC_DTAR(2) +#define DMAC_DTCR2 DMAC_DTCR(2) +#define DMAC_DRSR2 DMAC_DRSR(2) +#define DMAC_DCCSR2 DMAC_DCCSR(2) +#define DMAC_DCMD2 DMAC_DCMD(2) +#define DMAC_DDA2 DMAC_DDA(2) + +// channel 3 +#define DMAC_DSAR3 DMAC_DSAR(3) +#define DMAC_DTAR3 DMAC_DTAR(3) +#define DMAC_DTCR3 DMAC_DTCR(3) +#define DMAC_DRSR3 DMAC_DRSR(3) +#define DMAC_DCCSR3 DMAC_DCCSR(3) +#define DMAC_DCMD3 DMAC_DCMD(3) +#define DMAC_DDA3 DMAC_DDA(3) + +// channel 4 +#define DMAC_DSAR4 DMAC_DSAR(4) +#define DMAC_DTAR4 DMAC_DTAR(4) +#define DMAC_DTCR4 DMAC_DTCR(4) +#define DMAC_DRSR4 DMAC_DRSR(4) +#define DMAC_DCCSR4 DMAC_DCCSR(4) +#define DMAC_DCMD4 DMAC_DCMD(4) +#define DMAC_DDA4 DMAC_DDA(4) + +// channel 5 +#define DMAC_DSAR5 DMAC_DSAR(5) +#define DMAC_DTAR5 DMAC_DTAR(5) +#define DMAC_DTCR5 DMAC_DTCR(5) +#define DMAC_DRSR5 DMAC_DRSR(5) +#define DMAC_DCCSR5 DMAC_DCCSR(5) +#define DMAC_DCMD5 DMAC_DCMD(5) +#define DMAC_DDA5 DMAC_DDA(5) + +#define REG_DMAC_DSAR(n) REG32(DMAC_DSAR((n))) +#define REG_DMAC_DTAR(n) REG32(DMAC_DTAR((n))) +#define REG_DMAC_DTCR(n) REG32(DMAC_DTCR((n))) +#define REG_DMAC_DRSR(n) REG32(DMAC_DRSR((n))) +#define REG_DMAC_DCCSR(n) REG32(DMAC_DCCSR((n))) +#define REG_DMAC_DCMD(n) REG32(DMAC_DCMD((n))) +#define REG_DMAC_DDA(n) REG32(DMAC_DDA((n))) +#define REG_DMAC_DMACR REG32(DMAC_DMACR) +#define REG_DMAC_DMAIPR REG32(DMAC_DMAIPR) +#define REG_DMAC_DMADBR REG32(DMAC_DMADBR) +#define REG_DMAC_DMADBSR REG32(DMAC_DMADBSR) + +// DMA request source register +#define DMAC_DRSR_RS_BIT 0 +#define DMAC_DRSR_RS_MASK (0x1f << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AUTO (8 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_UART0OUT (20 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_UART0IN (21 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SSIOUT (22 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SSIIN (23 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AICOUT (24 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_AICIN (25 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_MSCOUT (26 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_MSCIN (27 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_TCU (28 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SADC (29 << DMAC_DRSR_RS_BIT) + #define DMAC_DRSR_RS_SLCD (30 << DMAC_DRSR_RS_BIT) + +// DMA channel control/status register +#define DMAC_DCCSR_NDES (1 << 31) /* descriptor (0) or not (1) ? */ +#define DMAC_DCCSR_CDOA_BIT 16 /* copy of DMA offset address */ +#define DMAC_DCCSR_CDOA_MASK (0xff << DMAC_DCCSR_CDOA_BIT) +#define DMAC_DCCSR_INV (1 << 6) /* descriptor invalid */ +#define DMAC_DCCSR_AR (1 << 4) /* address error */ +#define DMAC_DCCSR_TT (1 << 3) /* transfer terminated */ +#define DMAC_DCCSR_HLT (1 << 2) /* DMA halted */ +#define DMAC_DCCSR_CT (1 << 1) /* count terminated */ +#define DMAC_DCCSR_EN (1 << 0) /* channel enable bit */ + +// DMA channel command register +#define DMAC_DCMD_SAI (1 << 23) /* source address increment */ +#define DMAC_DCMD_DAI (1 << 22) /* dest address increment */ +#define DMAC_DCMD_RDIL_BIT 16 /* request detection interval length */ +#define DMAC_DCMD_RDIL_MASK (0x0f << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_IGN (0 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_2 (1 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_4 (2 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_8 (3 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_12 (4 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_16 (5 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_20 (6 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_24 (7 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_28 (8 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_32 (9 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_48 (10 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_60 (11 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_64 (12 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_124 (13 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_128 (14 << DMAC_DCMD_RDIL_BIT) + #define DMAC_DCMD_RDIL_200 (15 << DMAC_DCMD_RDIL_BIT) +#define DMAC_DCMD_SWDH_BIT 14 /* source port width */ +#define DMAC_DCMD_SWDH_MASK (0x03 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_32 (0 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_8 (1 << DMAC_DCMD_SWDH_BIT) + #define DMAC_DCMD_SWDH_16 (2 << DMAC_DCMD_SWDH_BIT) +#define DMAC_DCMD_DWDH_BIT 12 /* dest port width */ +#define DMAC_DCMD_DWDH_MASK (0x03 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_32 (0 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_8 (1 << DMAC_DCMD_DWDH_BIT) + #define DMAC_DCMD_DWDH_16 (2 << DMAC_DCMD_DWDH_BIT) +#define DMAC_DCMD_DS_BIT 8 /* transfer data size of a data unit */ +#define DMAC_DCMD_DS_MASK (0x07 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_32BIT (0 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_8BIT (1 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_16BIT (2 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_16BYTE (3 << DMAC_DCMD_DS_BIT) + #define DMAC_DCMD_DS_32BYTE (4 << DMAC_DCMD_DS_BIT) +#define DMAC_DCMD_TM (1 << 7) /* transfer mode: 0-single 1-block */ +#define DMAC_DCMD_DES_V (1 << 4) /* descriptor valid flag */ +#define DMAC_DCMD_DES_VM (1 << 3) /* descriptor valid mask: 1:support V-bit */ +#define DMAC_DCMD_DES_VIE (1 << 2) /* DMA valid error interrupt enable */ +#define DMAC_DCMD_TIE (1 << 1) /* DMA transfer interrupt enable */ +#define DMAC_DCMD_LINK (1 << 0) /* descriptor link enable */ + +// DMA descriptor address register +#define DMAC_DDA_BASE_BIT 12 /* descriptor base address */ +#define DMAC_DDA_BASE_MASK (0x0fffff << DMAC_DDA_BASE_BIT) +#define DMAC_DDA_OFFSET_BIT 4 /* descriptor offset address */ +#define DMAC_DDA_OFFSET_MASK (0x0ff << DMAC_DDA_OFFSET_BIT) + +// DMA control register +#define DMAC_DMACR_PR_BIT 8 /* channel priority mode */ +#define DMAC_DMACR_PR_MASK (0x03 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_012345 (0 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_023145 (1 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_201345 (2 << DMAC_DMACR_PR_BIT) + #define DMAC_DMACR_PR_RR (3 << DMAC_DMACR_PR_BIT) /* round robin */ +#define DMAC_DMACR_HLT (1 << 3) /* DMA halt flag */ +#define DMAC_DMACR_AR (1 << 2) /* address error flag */ +#define DMAC_DMACR_DMAE (1 << 0) /* DMA enable bit */ + +// DMA doorbell register +#define DMAC_DMADBR_DB5 (1 << 5) /* doorbell for channel 5 */ +#define DMAC_DMADBR_DB4 (1 << 5) /* doorbell for channel 4 */ +#define DMAC_DMADBR_DB3 (1 << 5) /* doorbell for channel 3 */ +#define DMAC_DMADBR_DB2 (1 << 5) /* doorbell for channel 2 */ +#define DMAC_DMADBR_DB1 (1 << 5) /* doorbell for channel 1 */ +#define DMAC_DMADBR_DB0 (1 << 5) /* doorbell for channel 0 */ + +// DMA doorbell set register +#define DMAC_DMADBSR_DBS5 (1 << 5) /* enable doorbell for channel 5 */ +#define DMAC_DMADBSR_DBS4 (1 << 5) /* enable doorbell for channel 4 */ +#define DMAC_DMADBSR_DBS3 (1 << 5) /* enable doorbell for channel 3 */ +#define DMAC_DMADBSR_DBS2 (1 << 5) /* enable doorbell for channel 2 */ +#define DMAC_DMADBSR_DBS1 (1 << 5) /* enable doorbell for channel 1 */ +#define DMAC_DMADBSR_DBS0 (1 << 5) /* enable doorbell for channel 0 */ + +// DMA interrupt pending register +#define DMAC_DMAIPR_CIRQ5 (1 << 5) /* irq pending status for channel 5 */ +#define DMAC_DMAIPR_CIRQ4 (1 << 4) /* irq pending status for channel 4 */ +#define DMAC_DMAIPR_CIRQ3 (1 << 3) /* irq pending status for channel 3 */ +#define DMAC_DMAIPR_CIRQ2 (1 << 2) /* irq pending status for channel 2 */ +#define DMAC_DMAIPR_CIRQ1 (1 << 1) /* irq pending status for channel 1 */ +#define DMAC_DMAIPR_CIRQ0 (1 << 0) /* irq pending status for channel 0 */ + + +/************************************************************************* + * GPIO (General-Purpose I/O Ports) + *************************************************************************/ +#define MAX_GPIO_NUM 128 + +//n = 0,1,2,3 +#define GPIO_PXPIN(n) (GPIO_BASE + (0x00 + (n)*0x100)) /* PIN Level Register */ +#define GPIO_PXDAT(n) (GPIO_BASE + (0x10 + (n)*0x100)) /* Port Data Register */ +#define GPIO_PXDATS(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Data Set Register */ +#define GPIO_PXDATC(n) (GPIO_BASE + (0x18 + (n)*0x100)) /* Port Data Clear Register */ +#define GPIO_PXIM(n) (GPIO_BASE + (0x20 + (n)*0x100)) /* Interrupt Mask Register */ +#define GPIO_PXIMS(n) (GPIO_BASE + (0x24 + (n)*0x100)) /* Interrupt Mask Set Reg */ +#define GPIO_PXIMC(n) (GPIO_BASE + (0x28 + (n)*0x100)) /* Interrupt Mask Clear Reg */ +#define GPIO_PXPE(n) (GPIO_BASE + (0x30 + (n)*0x100)) /* Pull Enable Register */ +#define GPIO_PXPES(n) (GPIO_BASE + (0x34 + (n)*0x100)) /* Pull Enable Set Reg. */ +#define GPIO_PXPEC(n) (GPIO_BASE + (0x38 + (n)*0x100)) /* Pull Enable Clear Reg. */ +#define GPIO_PXFUN(n) (GPIO_BASE + (0x40 + (n)*0x100)) /* Function Register */ +#define GPIO_PXFUNS(n) (GPIO_BASE + (0x44 + (n)*0x100)) /* Function Set Register */ +#define GPIO_PXFUNC(n) (GPIO_BASE + (0x48 + (n)*0x100)) /* Function Clear Register */ +#define GPIO_PXSEL(n) (GPIO_BASE + (0x50 + (n)*0x100)) /* Select Register */ +#define GPIO_PXSELS(n) (GPIO_BASE + (0x54 + (n)*0x100)) /* Select Set Register */ +#define GPIO_PXSELC(n) (GPIO_BASE + (0x58 + (n)*0x100)) /* Select Clear Register */ +#define GPIO_PXDIR(n) (GPIO_BASE + (0x60 + (n)*0x100)) /* Direction Register */ +#define GPIO_PXDIRS(n) (GPIO_BASE + (0x64 + (n)*0x100)) /* Direction Set Register */ +#define GPIO_PXDIRC(n) (GPIO_BASE + (0x68 + (n)*0x100)) /* Direction Clear Register */ +#define GPIO_PXTRG(n) (GPIO_BASE + (0x70 + (n)*0x100)) /* Trigger Register */ +#define GPIO_PXTRGS(n) (GPIO_BASE + (0x74 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXTRGC(n) (GPIO_BASE + (0x78 + (n)*0x100)) /* Trigger Set Register */ +#define GPIO_PXFLG(n) (GPIO_BASE + (0x80 + (n)*0x100)) /* Port Flag Register */ +#define GPIO_PXFLGC(n) (GPIO_BASE + (0x14 + (n)*0x100)) /* Port Flag Clear Register */ + +#define REG_GPIO_PXPIN(n) REG32(GPIO_PXPIN((n))) /* PIN level */ +#define REG_GPIO_PXDAT(n) REG32(GPIO_PXDAT((n))) /* 1: interrupt pending */ +#define REG_GPIO_PXDATS(n) REG32(GPIO_PXDATS((n))) +#define REG_GPIO_PXDATC(n) REG32(GPIO_PXDATC((n))) +#define REG_GPIO_PXIM(n) REG32(GPIO_PXIM((n))) /* 1: mask pin interrupt */ +#define REG_GPIO_PXIMS(n) REG32(GPIO_PXIMS((n))) +#define REG_GPIO_PXIMC(n) REG32(GPIO_PXIMC((n))) +#define REG_GPIO_PXPE(n) REG32(GPIO_PXPE((n))) /* 1: disable pull up/down */ +#define REG_GPIO_PXPES(n) REG32(GPIO_PXPES((n))) +#define REG_GPIO_PXPEC(n) REG32(GPIO_PXPEC((n))) +#define REG_GPIO_PXFUN(n) REG32(GPIO_PXFUN((n))) /* 0:GPIO or intr, 1:FUNC */ +#define REG_GPIO_PXFUNS(n) REG32(GPIO_PXFUNS((n))) +#define REG_GPIO_PXFUNC(n) REG32(GPIO_PXFUNC((n))) +#define REG_GPIO_PXSEL(n) REG32(GPIO_PXSEL((n))) /* 0:GPIO/Fun0,1:intr/fun1*/ +#define REG_GPIO_PXSELS(n) REG32(GPIO_PXSELS((n))) +#define REG_GPIO_PXSELC(n) REG32(GPIO_PXSELC((n))) +#define REG_GPIO_PXDIR(n) REG32(GPIO_PXDIR((n))) /* 0:input/low-level-trig/falling-edge-trig, 1:output/high-level-trig/rising-edge-trig */ +#define REG_GPIO_PXDIRS(n) REG32(GPIO_PXDIRS((n))) +#define REG_GPIO_PXDIRC(n) REG32(GPIO_PXDIRC((n))) +#define REG_GPIO_PXTRG(n) REG32(GPIO_PXTRG((n))) /* 0:level-trigger, 1:edge-trigger */ +#define REG_GPIO_PXTRGS(n) REG32(GPIO_PXTRGS((n))) +#define REG_GPIO_PXTRGC(n) REG32(GPIO_PXTRGC((n))) +#define REG_GPIO_PXFLG(n) REG32(GPIO_PXFLG((n))) /* interrupt flag */ +#define REG_GPIO_PXFLGC(n) REG32(GPIO_PXFLGC((n))) /* interrupt flag */ + + +/************************************************************************* + * UART + *************************************************************************/ + +#define IRDA_BASE UART0_BASE +#define UART_BASE UART0_BASE +#define UART_OFF 0x1000 + +/* Register Offset */ +#define OFF_RDR (0x00) /* R 8b H'xx */ +#define OFF_TDR (0x00) /* W 8b H'xx */ +#define OFF_DLLR (0x00) /* RW 8b H'00 */ +#define OFF_DLHR (0x04) /* RW 8b H'00 */ +#define OFF_IER (0x04) /* RW 8b H'00 */ +#define OFF_ISR (0x08) /* R 8b H'01 */ +#define OFF_FCR (0x08) /* W 8b H'00 */ +#define OFF_LCR (0x0C) /* RW 8b H'00 */ +#define OFF_MCR (0x10) /* RW 8b H'00 */ +#define OFF_LSR (0x14) /* R 8b H'00 */ +#define OFF_MSR (0x18) /* R 8b H'00 */ +#define OFF_SPR (0x1C) /* RW 8b H'00 */ +#define OFF_SIRCR (0x20) /* RW 8b H'00, UART0 */ +#define OFF_UMR (0x24) /* RW 8b H'00, UART M Register */ +#define OFF_UACR (0x28) /* RW 8b H'00, UART Add Cycle Register */ + +/* Register Address */ +#define UART0_RDR (UART0_BASE + OFF_RDR) +#define UART0_TDR (UART0_BASE + OFF_TDR) +#define UART0_DLLR (UART0_BASE + OFF_DLLR) +#define UART0_DLHR (UART0_BASE + OFF_DLHR) +#define UART0_IER (UART0_BASE + OFF_IER) +#define UART0_ISR (UART0_BASE + OFF_ISR) +#define UART0_FCR (UART0_BASE + OFF_FCR) +#define UART0_LCR (UART0_BASE + OFF_LCR) +#define UART0_MCR (UART0_BASE + OFF_MCR) +#define UART0_LSR (UART0_BASE + OFF_LSR) +#define UART0_MSR (UART0_BASE + OFF_MSR) +#define UART0_SPR (UART0_BASE + OFF_SPR) +#define UART0_SIRCR (UART0_BASE + OFF_SIRCR) +#define UART0_UMR (UART0_BASE + OFF_UMR) +#define UART0_UACR (UART0_BASE + OFF_UACR) + +/* + * Define macros for UARTIER + * UART Interrupt Enable Register + */ +#define UARTIER_RIE (1 << 0) /* 0: receive fifo full interrupt disable */ +#define UARTIER_TIE (1 << 1) /* 0: transmit fifo empty interrupt disable */ +#define UARTIER_RLIE (1 << 2) /* 0: receive line status interrupt disable */ +#define UARTIER_MIE (1 << 3) /* 0: modem status interrupt disable */ +#define UARTIER_RTIE (1 << 4) /* 0: receive timeout interrupt disable */ + +/* + * Define macros for UARTISR + * UART Interrupt Status Register + */ +#define UARTISR_IP (1 << 0) /* 0: interrupt is pending 1: no interrupt */ +#define UARTISR_IID (7 << 1) /* Source of Interrupt */ +#define UARTISR_IID_MSI (0 << 1) /* Modem status interrupt */ +#define UARTISR_IID_THRI (1 << 1) /* Transmitter holding register empty */ +#define UARTISR_IID_RDI (2 << 1) /* Receiver data interrupt */ +#define UARTISR_IID_RLSI (3 << 1) /* Receiver line status interrupt */ +#define UARTISR_IID_RTO (6 << 1) /* Receive timeout */ +#define UARTISR_FFMS (3 << 6) /* FIFO mode select, set when UARTFCR.FE is set to 1 */ +#define UARTISR_FFMS_NO_FIFO (0 << 6) +#define UARTISR_FFMS_FIFO_MODE (3 << 6) + +/* + * Define macros for UARTFCR + * UART FIFO Control Register + */ +#define UARTFCR_FE (1 << 0) /* 0: non-FIFO mode 1: FIFO mode */ +#define UARTFCR_RFLS (1 << 1) /* write 1 to flush receive FIFO */ +#define UARTFCR_TFLS (1 << 2) /* write 1 to flush transmit FIFO */ +#define UARTFCR_DMS (1 << 3) /* 0: disable DMA mode */ +#define UARTFCR_UUE (1 << 4) /* 0: disable UART */ +#define UARTFCR_RTRG (3 << 6) /* Receive FIFO Data Trigger */ +#define UARTFCR_RTRG_1 (0 << 6) +#define UARTFCR_RTRG_4 (1 << 6) +#define UARTFCR_RTRG_8 (2 << 6) +#define UARTFCR_RTRG_15 (3 << 6) + +/* + * Define macros for UARTLCR + * UART Line Control Register + */ +#define UARTLCR_WLEN (3 << 0) /* word length */ +#define UARTLCR_WLEN_5 (0 << 0) +#define UARTLCR_WLEN_6 (1 << 0) +#define UARTLCR_WLEN_7 (2 << 0) +#define UARTLCR_WLEN_8 (3 << 0) +#define UARTLCR_STOP (1 << 2) /* 0: 1 stop bit when word length is 5,6,7,8 + 1: 1.5 stop bits when 5; 2 stop bits when 6,7,8 */ +#define UARTLCR_STOP1 (0 << 2) +#define UARTLCR_STOP2 (1 << 2) +#define UARTLCR_PE (1 << 3) /* 0: parity disable */ +#define UARTLCR_PROE (1 << 4) /* 0: even parity 1: odd parity */ +#define UARTLCR_SPAR (1 << 5) /* 0: sticky parity disable */ +#define UARTLCR_SBRK (1 << 6) /* write 0 normal, write 1 send break */ +#define UARTLCR_DLAB (1 << 7) /* 0: access UARTRDR/TDR/IER 1: access UARTDLLR/DLHR */ + +/* + * Define macros for UARTLSR + * UART Line Status Register + */ +#define UARTLSR_DR (1 << 0) /* 0: receive FIFO is empty 1: receive data is ready */ +#define UARTLSR_ORER (1 << 1) /* 0: no overrun error */ +#define UARTLSR_PER (1 << 2) /* 0: no parity error */ +#define UARTLSR_FER (1 << 3) /* 0; no framing error */ +#define UARTLSR_BRK (1 << 4) /* 0: no break detected 1: receive a break signal */ +#define UARTLSR_TDRQ (1 << 5) /* 1: transmit FIFO half "empty" */ +#define UARTLSR_TEMT (1 << 6) /* 1: transmit FIFO and shift registers empty */ +#define UARTLSR_RFER (1 << 7) /* 0: no receive error 1: receive error in FIFO mode */ + +/* + * Define macros for UARTMCR + * UART Modem Control Register + */ +#define UARTMCR_RTS (1 << 1) /* 0: RTS_ output high, 1: RTS_ output low */ +#define UARTMCR_LOOP (1 << 4) /* 0: normal 1: loopback mode */ +#define UARTMCR_MCE (1 << 7) /* 0: modem function is disable */ + +/* + * Define macros for UARTMSR + * UART Modem Status Register + */ +#define UARTMSR_CCTS (1 << 0) /* 1: a change on CTS_ pin */ +#define UARTMSR_CTS (1 << 4) /* 0: CTS_ pin is high */ + +/* + * Define macros for SIRCR + * Slow IrDA Control Register + */ +#define SIRCR_TSIRE (1 << 0) /* 0: transmitter is in UART mode 1: SIR mode */ +#define SIRCR_RSIRE (1 << 1) /* 0: receiver is in UART mode 1: SIR mode */ +#define SIRCR_TPWS (1 << 2) /* 0: transmit 0 pulse width is 3/16 of bit length + 1: 0 pulse width is 1.6us for 115.2Kbps */ +#define SIRCR_TDPL (1 << 3) /* 0: encoder generates a positive pulse for 0 */ +#define SIRCR_RDPL (1 << 4) /* 0: decoder interprets positive pulse as 0 */ + + +/************************************************************************* + * AIC (AC97/I2S Controller) + *************************************************************************/ +#define AIC_FR (AIC_BASE + 0x000) +#define AIC_CR (AIC_BASE + 0x004) +#define AIC_ACCR1 (AIC_BASE + 0x008) +#define AIC_ACCR2 (AIC_BASE + 0x00C) +#define AIC_I2SCR (AIC_BASE + 0x010) +#define AIC_SR (AIC_BASE + 0x014) +#define AIC_ACSR (AIC_BASE + 0x018) +#define AIC_I2SSR (AIC_BASE + 0x01C) +#define AIC_ACCAR (AIC_BASE + 0x020) +#define AIC_ACCDR (AIC_BASE + 0x024) +#define AIC_ACSAR (AIC_BASE + 0x028) +#define AIC_ACSDR (AIC_BASE + 0x02C) +#define AIC_I2SDIV (AIC_BASE + 0x030) +#define AIC_DR (AIC_BASE + 0x034) + +#define REG_AIC_FR REG32(AIC_FR) +#define REG_AIC_CR REG32(AIC_CR) +#define REG_AIC_ACCR1 REG32(AIC_ACCR1) +#define REG_AIC_ACCR2 REG32(AIC_ACCR2) +#define REG_AIC_I2SCR REG32(AIC_I2SCR) +#define REG_AIC_SR REG32(AIC_SR) +#define REG_AIC_ACSR REG32(AIC_ACSR) +#define REG_AIC_I2SSR REG32(AIC_I2SSR) +#define REG_AIC_ACCAR REG32(AIC_ACCAR) +#define REG_AIC_ACCDR REG32(AIC_ACCDR) +#define REG_AIC_ACSAR REG32(AIC_ACSAR) +#define REG_AIC_ACSDR REG32(AIC_ACSDR) +#define REG_AIC_I2SDIV REG32(AIC_I2SDIV) +#define REG_AIC_DR REG32(AIC_DR) + +/* AIC Controller Configuration Register (AIC_FR) */ + +#define AIC_FR_RFTH_BIT 12 /* Receive FIFO Threshold */ +#define AIC_FR_RFTH_MASK (0xf << AIC_FR_RFTH_BIT) +#define AIC_FR_TFTH_BIT 8 /* Transmit FIFO Threshold */ +#define AIC_FR_TFTH_MASK (0xf << AIC_FR_TFTH_BIT) +#define AIC_FR_LSMP (1 << 6) /* Play Zero sample or last sample */ +#define AIC_FR_ICDC (1 << 5) /* External(0) or Internal CODEC(1) */ +#define AIC_FR_AUSEL (1 << 4) /* AC97(0) or I2S/MSB-justified(1) */ +#define AIC_FR_RST (1 << 3) /* AIC registers reset */ +#define AIC_FR_BCKD (1 << 2) /* I2S BIT_CLK direction, 0:input,1:output */ +#define AIC_FR_SYNCD (1 << 1) /* I2S SYNC direction, 0:input,1:output */ +#define AIC_FR_ENB (1 << 0) /* AIC enable bit */ + +/* AIC Controller Common Control Register (AIC_CR) */ + +#define AIC_CR_OSS_BIT 19 /* Output Sample Size from memory (AIC V2 only) */ +#define AIC_CR_OSS_MASK (0x7 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_8BIT (0x0 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_16BIT (0x1 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_18BIT (0x2 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_20BIT (0x3 << AIC_CR_OSS_BIT) + #define AIC_CR_OSS_24BIT (0x4 << AIC_CR_OSS_BIT) +#define AIC_CR_ISS_BIT 16 /* Input Sample Size from memory (AIC V2 only) */ +#define AIC_CR_ISS_MASK (0x7 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_8BIT (0x0 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_16BIT (0x1 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_18BIT (0x2 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_20BIT (0x3 << AIC_CR_ISS_BIT) + #define AIC_CR_ISS_24BIT (0x4 << AIC_CR_ISS_BIT) +#define AIC_CR_RDMS (1 << 15) /* Receive DMA enable */ +#define AIC_CR_TDMS (1 << 14) /* Transmit DMA enable */ +#define AIC_CR_M2S (1 << 11) /* Mono to Stereo enable */ +#define AIC_CR_ENDSW (1 << 10) /* Endian switch enable */ +#define AIC_CR_AVSTSU (1 << 9) /* Signed <-> Unsigned toggle enable */ +#define AIC_CR_FLUSH (1 << 8) /* Flush FIFO */ +#define AIC_CR_EROR (1 << 6) /* Enable ROR interrupt */ +#define AIC_CR_ETUR (1 << 5) /* Enable TUR interrupt */ +#define AIC_CR_ERFS (1 << 4) /* Enable RFS interrupt */ +#define AIC_CR_ETFS (1 << 3) /* Enable TFS interrupt */ +#define AIC_CR_ENLBF (1 << 2) /* Enable Loopback Function */ +#define AIC_CR_ERPL (1 << 1) /* Enable Playback Function */ +#define AIC_CR_EREC (1 << 0) /* Enable Record Function */ + +/* AIC Controller AC-link Control Register 1 (AIC_ACCR1) */ + +#define AIC_ACCR1_RS_BIT 16 /* Receive Valid Slots */ +#define AIC_ACCR1_RS_MASK (0x3ff << AIC_ACCR1_RS_BIT) + #define AIC_ACCR1_RS_SLOT12 (1 << 25) /* Slot 12 valid bit */ + #define AIC_ACCR1_RS_SLOT11 (1 << 24) /* Slot 11 valid bit */ + #define AIC_ACCR1_RS_SLOT10 (1 << 23) /* Slot 10 valid bit */ + #define AIC_ACCR1_RS_SLOT9 (1 << 22) /* Slot 9 valid bit, LFE */ + #define AIC_ACCR1_RS_SLOT8 (1 << 21) /* Slot 8 valid bit, Surround Right */ + #define AIC_ACCR1_RS_SLOT7 (1 << 20) /* Slot 7 valid bit, Surround Left */ + #define AIC_ACCR1_RS_SLOT6 (1 << 19) /* Slot 6 valid bit, PCM Center */ + #define AIC_ACCR1_RS_SLOT5 (1 << 18) /* Slot 5 valid bit */ + #define AIC_ACCR1_RS_SLOT4 (1 << 17) /* Slot 4 valid bit, PCM Right */ + #define AIC_ACCR1_RS_SLOT3 (1 << 16) /* Slot 3 valid bit, PCM Left */ +#define AIC_ACCR1_XS_BIT 0 /* Transmit Valid Slots */ +#define AIC_ACCR1_XS_MASK (0x3ff << AIC_ACCR1_XS_BIT) + #define AIC_ACCR1_XS_SLOT12 (1 << 9) /* Slot 12 valid bit */ + #define AIC_ACCR1_XS_SLOT11 (1 << 8) /* Slot 11 valid bit */ + #define AIC_ACCR1_XS_SLOT10 (1 << 7) /* Slot 10 valid bit */ + #define AIC_ACCR1_XS_SLOT9 (1 << 6) /* Slot 9 valid bit, LFE */ + #define AIC_ACCR1_XS_SLOT8 (1 << 5) /* Slot 8 valid bit, Surround Right */ + #define AIC_ACCR1_XS_SLOT7 (1 << 4) /* Slot 7 valid bit, Surround Left */ + #define AIC_ACCR1_XS_SLOT6 (1 << 3) /* Slot 6 valid bit, PCM Center */ + #define AIC_ACCR1_XS_SLOT5 (1 << 2) /* Slot 5 valid bit */ + #define AIC_ACCR1_XS_SLOT4 (1 << 1) /* Slot 4 valid bit, PCM Right */ + #define AIC_ACCR1_XS_SLOT3 (1 << 0) /* Slot 3 valid bit, PCM Left */ + +/* AIC Controller AC-link Control Register 2 (AIC_ACCR2) */ + +#define AIC_ACCR2_ERSTO (1 << 18) /* Enable RSTO interrupt */ +#define AIC_ACCR2_ESADR (1 << 17) /* Enable SADR interrupt */ +#define AIC_ACCR2_ECADT (1 << 16) /* Enable CADT interrupt */ +#define AIC_ACCR2_OASS_BIT 8 /* Output Sample Size for AC-link */ +#define AIC_ACCR2_OASS_MASK (0x3 << AIC_ACCR2_OASS_BIT) + #define AIC_ACCR2_OASS_20BIT (0 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 20-bit */ + #define AIC_ACCR2_OASS_18BIT (1 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 18-bit */ + #define AIC_ACCR2_OASS_16BIT (2 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 16-bit */ + #define AIC_ACCR2_OASS_8BIT (3 << AIC_ACCR2_OASS_BIT) /* Output Audio Sample Size is 8-bit */ +#define AIC_ACCR2_IASS_BIT 6 /* Output Sample Size for AC-link */ +#define AIC_ACCR2_IASS_MASK (0x3 << AIC_ACCR2_IASS_BIT) + #define AIC_ACCR2_IASS_20BIT (0 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 20-bit */ + #define AIC_ACCR2_IASS_18BIT (1 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 18-bit */ + #define AIC_ACCR2_IASS_16BIT (2 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 16-bit */ + #define AIC_ACCR2_IASS_8BIT (3 << AIC_ACCR2_IASS_BIT) /* Input Audio Sample Size is 8-bit */ +#define AIC_ACCR2_SO (1 << 3) /* SDATA_OUT output value */ +#define AIC_ACCR2_SR (1 << 2) /* RESET# pin level */ +#define AIC_ACCR2_SS (1 << 1) /* SYNC pin level */ +#define AIC_ACCR2_SA (1 << 0) /* SYNC and SDATA_OUT alternation */ + +/* AIC Controller I2S/MSB-justified Control Register (AIC_I2SCR) */ + +#define AIC_I2SCR_STPBK (1 << 12) /* Stop BIT_CLK for I2S/MSB-justified */ +#define AIC_I2SCR_WL_BIT 1 /* Input/Output Sample Size for I2S/MSB-justified */ +#define AIC_I2SCR_WL_MASK (0x7 << AIC_I2SCR_WL_BIT) + #define AIC_I2SCR_WL_24BIT (0 << AIC_I2SCR_WL_BIT) /* Word Length is 24 bit */ + #define AIC_I2SCR_WL_20BIT (1 << AIC_I2SCR_WL_BIT) /* Word Length is 20 bit */ + #define AIC_I2SCR_WL_18BIT (2 << AIC_I2SCR_WL_BIT) /* Word Length is 18 bit */ + #define AIC_I2SCR_WL_16BIT (3 << AIC_I2SCR_WL_BIT) /* Word Length is 16 bit */ + #define AIC_I2SCR_WL_8BIT (4 << AIC_I2SCR_WL_BIT) /* Word Length is 8 bit */ +#define AIC_I2SCR_AMSL (1 << 0) /* 0:I2S, 1:MSB-justified */ + +/* AIC Controller FIFO Status Register (AIC_SR) */ + +#define AIC_SR_RFL_BIT 24 /* Receive FIFO Level */ +#define AIC_SR_RFL_MASK (0x3f << AIC_SR_RFL_BIT) +#define AIC_SR_TFL_BIT 8 /* Transmit FIFO level */ +#define AIC_SR_TFL_MASK (0x3f << AIC_SR_TFL_BIT) +#define AIC_SR_ROR (1 << 6) /* Receive FIFO Overrun */ +#define AIC_SR_TUR (1 << 5) /* Transmit FIFO Underrun */ +#define AIC_SR_RFS (1 << 4) /* Receive FIFO Service Request */ +#define AIC_SR_TFS (1 << 3) /* Transmit FIFO Service Request */ + +/* AIC Controller AC-link Status Register (AIC_ACSR) */ + +#define AIC_ACSR_SLTERR (1 << 21) /* Slot Error Flag */ +#define AIC_ACSR_CRDY (1 << 20) /* External CODEC Ready Flag */ +#define AIC_ACSR_CLPM (1 << 19) /* External CODEC low power mode flag */ +#define AIC_ACSR_RSTO (1 << 18) /* External CODEC regs read status timeout */ +#define AIC_ACSR_SADR (1 << 17) /* External CODEC regs status addr and data received */ +#define AIC_ACSR_CADT (1 << 16) /* Command Address and Data Transmitted */ + +/* AIC Controller I2S/MSB-justified Status Register (AIC_I2SSR) */ + +#define AIC_I2SSR_BSY (1 << 2) /* AIC Busy in I2S/MSB-justified format */ + +/* AIC Controller AC97 codec Command Address Register (AIC_ACCAR) */ + +#define AIC_ACCAR_CAR_BIT 0 +#define AIC_ACCAR_CAR_MASK (0xfffff << AIC_ACCAR_CAR_BIT) + +/* AIC Controller AC97 codec Command Data Register (AIC_ACCDR) */ + +#define AIC_ACCDR_CDR_BIT 0 +#define AIC_ACCDR_CDR_MASK (0xfffff << AIC_ACCDR_CDR_BIT) + +/* AIC Controller AC97 codec Status Address Register (AIC_ACSAR) */ + +#define AIC_ACSAR_SAR_BIT 0 +#define AIC_ACSAR_SAR_MASK (0xfffff << AIC_ACSAR_SAR_BIT) + +/* AIC Controller AC97 codec Status Data Register (AIC_ACSDR) */ + +#define AIC_ACSDR_SDR_BIT 0 +#define AIC_ACSDR_SDR_MASK (0xfffff << AIC_ACSDR_SDR_BIT) + +/* AIC Controller I2S/MSB-justified Clock Divider Register (AIC_I2SDIV) */ + +#define AIC_I2SDIV_DIV_BIT 0 +#define AIC_I2SDIV_DIV_MASK (0x7f << AIC_I2SDIV_DIV_BIT) + #define AIC_I2SDIV_BITCLK_3072KHZ (0x0C << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 3.072MHz */ + #define AIC_I2SDIV_BITCLK_2836KHZ (0x0D << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 2.836MHz */ + #define AIC_I2SDIV_BITCLK_1418KHZ (0x1A << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.418MHz */ + #define AIC_I2SDIV_BITCLK_1024KHZ (0x24 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 1.024MHz */ + #define AIC_I2SDIV_BITCLK_7089KHZ (0x34 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 708.92KHz */ + #define AIC_I2SDIV_BITCLK_512KHZ (0x48 << AIC_I2SDIV_DIV_BIT) /* BIT_CLK of 512.00KHz */ + + +/************************************************************************* + * ICDC (Internal CODEC) + *************************************************************************/ +#define ICDC_CR (ICDC_BASE + 0x0400) /* ICDC Control Register */ +#define ICDC_APWAIT (ICDC_BASE + 0x0404) /* Anti-Pop WAIT Stage Timing Control Register */ +#define ICDC_APPRE (ICDC_BASE + 0x0408) /* Anti-Pop HPEN-PRE Stage Timing Control Register */ +#define ICDC_APHPEN (ICDC_BASE + 0x040C) /* Anti-Pop HPEN Stage Timing Control Register */ +#define ICDC_APSR (ICDC_BASE + 0x0410) /* Anti-Pop Status Register */ +#define ICDC_CDCCR1 (ICDC_BASE + 0x0080) +#define ICDC_CDCCR2 (ICDC_BASE + 0x0084) + +#define REG_ICDC_CR REG32(ICDC_CR) +#define REG_ICDC_APWAIT REG32(ICDC_APWAIT) +#define REG_ICDC_APPRE REG32(ICDC_APPRE) +#define REG_ICDC_APHPEN REG32(ICDC_APHPEN) +#define REG_ICDC_APSR REG32(ICDC_APSR) +#define REG_ICDC_CDCCR1 REG32(ICDC_CDCCR1) +#define REG_ICDC_CDCCR2 REG32(ICDC_CDCCR2) + +/* ICDC Control Register */ +#define ICDC_CR_LINVOL_BIT 24 /* LINE Input Volume Gain: GAIN=LINVOL*1.5-34.5 */ +#define ICDC_CR_LINVOL_MASK (0x1f << ICDC_CR_LINVOL_BIT) +#define ICDC_CR_ASRATE_BIT 20 /* Audio Sample Rate */ +#define ICDC_CR_ASRATE_MASK (0x0f << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_8000 (0x0 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_11025 (0x1 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_12000 (0x2 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_16000 (0x3 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_22050 (0x4 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_24000 (0x5 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_32000 (0x6 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_44100 (0x7 << ICDC_CR_ASRATE_BIT) + #define ICDC_CR_ASRATE_48000 (0x8 << ICDC_CR_ASRATE_BIT) +#define ICDC_CR_MICBG_BIT 18 /* MIC Boost Gain */ +#define ICDC_CR_MICBG_MASK (0x3 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_0DB (0x0 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_6DB (0x1 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_12DB (0x2 << ICDC_CR_MICBG_BIT) + #define ICDC_CR_MICBG_20DB (0x3 << ICDC_CR_MICBG_BIT) +#define ICDC_CR_HPVOL_BIT 16 /* Headphone Volume Gain */ +#define ICDC_CR_HPVOL_MASK (0x3 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_0DB (0x0 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_2DB (0x1 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_4DB (0x2 << ICDC_CR_HPVOL_BIT) + #define ICDC_CR_HPVOL_6DB (0x3 << ICDC_CR_HPVOL_BIT) +#define ICDC_CR_ELINEIN (1 << 13) /* Enable LINE Input */ +#define ICDC_CR_EMIC (1 << 12) /* Enable MIC Input */ +#define ICDC_CR_SW1ON (1 << 11) /* Switch 1 in CODEC is on */ +#define ICDC_CR_EADC (1 << 10) /* Enable ADC */ +#define ICDC_CR_SW2ON (1 << 9) /* Switch 2 in CODEC is on */ +#define ICDC_CR_EDAC (1 << 8) /* Enable DAC */ +#define ICDC_CR_HPMUTE (1 << 5) /* Headphone Mute */ +#define ICDC_CR_HPTON (1 << 4) /* Headphone Amplifier Trun On */ +#define ICDC_CR_HPTOFF (1 << 3) /* Headphone Amplifier Trun Off */ +#define ICDC_CR_TAAP (1 << 2) /* Turn Around of the Anti-Pop Procedure */ +#define ICDC_CR_EAP (1 << 1) /* Enable Anti-Pop Procedure */ +#define ICDC_CR_SUSPD (1 << 0) /* CODEC Suspend */ + +/* Anti-Pop WAIT Stage Timing Control Register */ +#define ICDC_APWAIT_WAITSN_BIT 0 +#define ICDC_APWAIT_WAITSN_MASK (0x7ff << ICDC_APWAIT_WAITSN_BIT) + +/* Anti-Pop HPEN-PRE Stage Timing Control Register */ +#define ICDC_APPRE_PRESN_BIT 0 +#define ICDC_APPRE_PRESN_MASK (0x1ff << ICDC_APPRE_PRESN_BIT) + +/* Anti-Pop HPEN Stage Timing Control Register */ +#define ICDC_APHPEN_HPENSN_BIT 0 +#define ICDC_APHPEN_HPENSN_MASK (0x3fff << ICDC_APHPEN_HPENSN_BIT) + +/* Anti-Pop Status Register */ +#define ICDC_SR_HPST_BIT 14 /* Headphone Amplifier State */ +#define ICDC_SR_HPST_MASK (0x7 << ICDC_SR_HPST_BIT) +#define ICDC_SR_HPST_HP_OFF (0x0 << ICDC_SR_HPST_BIT) /* HP amplifier is off */ +#define ICDC_SR_HPST_TON_WAIT (0x1 << ICDC_SR_HPST_BIT) /* wait state in turn-on */ + #define ICDC_SR_HPST_TON_PRE (0x2 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-on */ +#define ICDC_SR_HPST_TON_HPEN (0x3 << ICDC_SR_HPST_BIT) /* HP enable state in turn-on */ + #define ICDC_SR_HPST_TOFF_HPEN (0x4 << ICDC_SR_HPST_BIT) /* HP enable state in turn-off */ + #define ICDC_SR_HPST_TOFF_PRE (0x5 << ICDC_SR_HPST_BIT) /* pre-enable state in turn-off */ + #define ICDC_SR_HPST_TOFF_WAIT (0x6 << ICDC_SR_HPST_BIT) /* wait state in turn-off */ + #define ICDC_SR_HPST_HP_ON (0x7 << ICDC_SR_HPST_BIT) /* HP amplifier is on */ +#define ICDC_SR_SNCNT_BIT 0 /* Sample Number Counter */ +#define ICDC_SR_SNCNT_MASK (0x3fff << ICDC_SR_SNCNT_BIT) + + +/************************************************************************* + * I2C + *************************************************************************/ +#define I2C_DR (I2C_BASE + 0x000) +#define I2C_CR (I2C_BASE + 0x004) +#define I2C_SR (I2C_BASE + 0x008) +#define I2C_GR (I2C_BASE + 0x00C) + +#define REG_I2C_DR REG8(I2C_DR) +#define REG_I2C_CR REG8(I2C_CR) +#define REG_I2C_SR REG8(I2C_SR) +#define REG_I2C_GR REG16(I2C_GR) + +/* I2C Control Register (I2C_CR) */ + +#define I2C_CR_IEN (1 << 4) +#define I2C_CR_STA (1 << 3) +#define I2C_CR_STO (1 << 2) +#define I2C_CR_AC (1 << 1) +#define I2C_CR_I2CE (1 << 0) + +/* I2C Status Register (I2C_SR) */ + +#define I2C_SR_STX (1 << 4) +#define I2C_SR_BUSY (1 << 3) +#define I2C_SR_TEND (1 << 2) +#define I2C_SR_DRF (1 << 1) +#define I2C_SR_ACKF (1 << 0) + + +/************************************************************************* + * SSI + *************************************************************************/ +#define SSI_DR (SSI_BASE + 0x000) +#define SSI_CR0 (SSI_BASE + 0x004) +#define SSI_CR1 (SSI_BASE + 0x008) +#define SSI_SR (SSI_BASE + 0x00C) +#define SSI_ITR (SSI_BASE + 0x010) +#define SSI_ICR (SSI_BASE + 0x014) +#define SSI_GR (SSI_BASE + 0x018) + +#define REG_SSI_DR REG32(SSI_DR) +#define REG_SSI_CR0 REG16(SSI_CR0) +#define REG_SSI_CR1 REG32(SSI_CR1) +#define REG_SSI_SR REG32(SSI_SR) +#define REG_SSI_ITR REG16(SSI_ITR) +#define REG_SSI_ICR REG8(SSI_ICR) +#define REG_SSI_GR REG16(SSI_GR) + +/* SSI Data Register (SSI_DR) */ + +#define SSI_DR_GPC_BIT 0 +#define SSI_DR_GPC_MASK (0x1ff << SSI_DR_GPC_BIT) + +/* SSI Control Register 0 (SSI_CR0) */ + +#define SSI_CR0_SSIE (1 << 15) +#define SSI_CR0_TIE (1 << 14) +#define SSI_CR0_RIE (1 << 13) +#define SSI_CR0_TEIE (1 << 12) +#define SSI_CR0_REIE (1 << 11) +#define SSI_CR0_LOOP (1 << 10) +#define SSI_CR0_RFINE (1 << 9) +#define SSI_CR0_RFINC (1 << 8) +#define SSI_CR0_FSEL (1 << 6) +#define SSI_CR0_TFLUSH (1 << 2) +#define SSI_CR0_RFLUSH (1 << 1) +#define SSI_CR0_DISREV (1 << 0) + +/* SSI Control Register 1 (SSI_CR1) */ + +#define SSI_CR1_FRMHL_BIT 30 +#define SSI_CR1_FRMHL_MASK (0x3 << SSI_CR1_FRMHL_BIT) + #define SSI_CR1_FRMHL_CELOW_CE2LOW (0 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is low valid */ + #define SSI_CR1_FRMHL_CEHIGH_CE2LOW (1 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is low valid */ + #define SSI_CR1_FRMHL_CELOW_CE2HIGH (2 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is low valid and SSI_CE2_ is high valid */ + #define SSI_CR1_FRMHL_CEHIGH_CE2HIGH (3 << SSI_CR1_FRMHL_BIT) /* SSI_CE_ is high valid and SSI_CE2_ is high valid */ +#define SSI_CR1_TFVCK_BIT 28 +#define SSI_CR1_TFVCK_MASK (0x3 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_0 (0 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_1 (1 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_2 (2 << SSI_CR1_TFVCK_BIT) + #define SSI_CR1_TFVCK_3 (3 << SSI_CR1_TFVCK_BIT) +#define SSI_CR1_TCKFI_BIT 26 +#define SSI_CR1_TCKFI_MASK (0x3 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_0 (0 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_1 (1 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_2 (2 << SSI_CR1_TCKFI_BIT) + #define SSI_CR1_TCKFI_3 (3 << SSI_CR1_TCKFI_BIT) +#define SSI_CR1_LFST (1 << 25) +#define SSI_CR1_ITFRM (1 << 24) +#define SSI_CR1_UNFIN (1 << 23) +#define SSI_CR1_MULTS (1 << 22) +#define SSI_CR1_FMAT_BIT 20 +#define SSI_CR1_FMAT_MASK (0x3 << SSI_CR1_FMAT_BIT) + #define SSI_CR1_FMAT_SPI (0 << SSI_CR1_FMAT_BIT) /* Motorola¡¯s SPI format */ + #define SSI_CR1_FMAT_SSP (1 << SSI_CR1_FMAT_BIT) /* TI's SSP format */ + #define SSI_CR1_FMAT_MW1 (2 << SSI_CR1_FMAT_BIT) /* National Microwire 1 format */ + #define SSI_CR1_FMAT_MW2 (3 << SSI_CR1_FMAT_BIT) /* National Microwire 2 format */ +#define SSI_CR1_TTRG_BIT 16 +#define SSI_CR1_TTRG_MASK (0xf << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_1 (0 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_8 (1 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_16 (2 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_24 (3 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_32 (4 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_40 (5 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_48 (6 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_56 (7 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_64 (8 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_72 (9 << SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_80 (10<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_88 (11<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_96 (12<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_104 (13<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_112 (14<< SSI_CR1_TTRG_BIT) + #define SSI_CR1_TTRG_120 (15<< SSI_CR1_TTRG_BIT) +#define SSI_CR1_MCOM_BIT 12 +#define SSI_CR1_MCOM_MASK (0xf << SSI_CR1_MCOM_BIT) + #define SSI_CR1_MCOM_1BIT (0x0 << SSI_CR1_MCOM_BIT) /* 1-bit command selected */ + #define SSI_CR1_MCOM_2BIT (0x1 << SSI_CR1_MCOM_BIT) /* 2-bit command selected */ + #define SSI_CR1_MCOM_3BIT (0x2 << SSI_CR1_MCOM_BIT) /* 3-bit command selected */ + #define SSI_CR1_MCOM_4BIT (0x3 << SSI_CR1_MCOM_BIT) /* 4-bit command selected */ + #define SSI_CR1_MCOM_5BIT (0x4 << SSI_CR1_MCOM_BIT) /* 5-bit command selected */ + #define SSI_CR1_MCOM_6BIT (0x5 << SSI_CR1_MCOM_BIT) /* 6-bit command selected */ + #define SSI_CR1_MCOM_7BIT (0x6 << SSI_CR1_MCOM_BIT) /* 7-bit command selected */ + #define SSI_CR1_MCOM_8BIT (0x7 << SSI_CR1_MCOM_BIT) /* 8-bit command selected */ + #define SSI_CR1_MCOM_9BIT (0x8 << SSI_CR1_MCOM_BIT) /* 9-bit command selected */ + #define SSI_CR1_MCOM_10BIT (0x9 << SSI_CR1_MCOM_BIT) /* 10-bit command selected */ + #define SSI_CR1_MCOM_11BIT (0xA << SSI_CR1_MCOM_BIT) /* 11-bit command selected */ + #define SSI_CR1_MCOM_12BIT (0xB << SSI_CR1_MCOM_BIT) /* 12-bit command selected */ + #define SSI_CR1_MCOM_13BIT (0xC << SSI_CR1_MCOM_BIT) /* 13-bit command selected */ + #define SSI_CR1_MCOM_14BIT (0xD << SSI_CR1_MCOM_BIT) /* 14-bit command selected */ + #define SSI_CR1_MCOM_15BIT (0xE << SSI_CR1_MCOM_BIT) /* 15-bit command selected */ + #define SSI_CR1_MCOM_16BIT (0xF << SSI_CR1_MCOM_BIT) /* 16-bit command selected */ +#define SSI_CR1_RTRG_BIT 8 +#define SSI_CR1_RTRG_MASK (0xf << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_1 (0 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_8 (1 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_16 (2 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_24 (3 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_32 (4 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_40 (5 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_48 (6 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_56 (7 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_64 (8 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_72 (9 << SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_80 (10<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_88 (11<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_96 (12<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_104 (13<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_112 (14<< SSI_CR1_RTRG_BIT) + #define SSI_CR1_RTRG_120 (15<< SSI_CR1_RTRG_BIT) +#define SSI_CR1_FLEN_BIT 4 +#define SSI_CR1_FLEN_MASK (0xf << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_2BIT (0x0 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_3BIT (0x1 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_4BIT (0x2 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_5BIT (0x3 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_6BIT (0x4 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_7BIT (0x5 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_8BIT (0x6 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_9BIT (0x7 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_10BIT (0x8 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_11BIT (0x9 << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_12BIT (0xA << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_13BIT (0xB << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_14BIT (0xC << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_15BIT (0xD << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_16BIT (0xE << SSI_CR1_FLEN_BIT) + #define SSI_CR1_FLEN_17BIT (0xF << SSI_CR1_FLEN_BIT) +#define SSI_CR1_PHA (1 << 1) +#define SSI_CR1_POL (1 << 0) + +/* SSI Status Register (SSI_SR) */ + +#define SSI_SR_TFIFONUM_BIT 16 +#define SSI_SR_TFIFONUM_MASK (0xff << SSI_SR_TFIFONUM_BIT) +#define SSI_SR_RFIFONUM_BIT 8 +#define SSI_SR_RFIFONUM_MASK (0xff << SSI_SR_RFIFONUM_BIT) +#define SSI_SR_END (1 << 7) +#define SSI_SR_BUSY (1 << 6) +#define SSI_SR_TFF (1 << 5) +#define SSI_SR_RFE (1 << 4) +#define SSI_SR_TFHE (1 << 3) +#define SSI_SR_RFHF (1 << 2) +#define SSI_SR_UNDR (1 << 1) +#define SSI_SR_OVER (1 << 0) + +/* SSI Interval Time Control Register (SSI_ITR) */ + +#define SSI_ITR_CNTCLK (1 << 15) +#define SSI_ITR_IVLTM_BIT 0 +#define SSI_ITR_IVLTM_MASK (0x7fff << SSI_ITR_IVLTM_BIT) + + +/************************************************************************* + * MSC + *************************************************************************/ +#define MSC_STRPCL (MSC_BASE + 0x000) +#define MSC_STAT (MSC_BASE + 0x004) +#define MSC_CLKRT (MSC_BASE + 0x008) +#define MSC_CMDAT (MSC_BASE + 0x00C) +#define MSC_RESTO (MSC_BASE + 0x010) +#define MSC_RDTO (MSC_BASE + 0x014) +#define MSC_BLKLEN (MSC_BASE + 0x018) +#define MSC_NOB (MSC_BASE + 0x01C) +#define MSC_SNOB (MSC_BASE + 0x020) +#define MSC_IMASK (MSC_BASE + 0x024) +#define MSC_IREG (MSC_BASE + 0x028) +#define MSC_CMD (MSC_BASE + 0x02C) +#define MSC_ARG (MSC_BASE + 0x030) +#define MSC_RES (MSC_BASE + 0x034) +#define MSC_RXFIFO (MSC_BASE + 0x038) +#define MSC_TXFIFO (MSC_BASE + 0x03C) + +#define REG_MSC_STRPCL REG16(MSC_STRPCL) +#define REG_MSC_STAT REG32(MSC_STAT) +#define REG_MSC_CLKRT REG16(MSC_CLKRT) +#define REG_MSC_CMDAT REG32(MSC_CMDAT) +#define REG_MSC_RESTO REG16(MSC_RESTO) +#define REG_MSC_RDTO REG16(MSC_RDTO) +#define REG_MSC_BLKLEN REG16(MSC_BLKLEN) +#define REG_MSC_NOB REG16(MSC_NOB) +#define REG_MSC_SNOB REG16(MSC_SNOB) +#define REG_MSC_IMASK REG16(MSC_IMASK) +#define REG_MSC_IREG REG16(MSC_IREG) +#define REG_MSC_CMD REG8(MSC_CMD) +#define REG_MSC_ARG REG32(MSC_ARG) +#define REG_MSC_RES REG16(MSC_RES) +#define REG_MSC_RXFIFO REG32(MSC_RXFIFO) +#define REG_MSC_TXFIFO REG32(MSC_TXFIFO) + +/* MSC Clock and Control Register (MSC_STRPCL) */ + +#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7) +#define MSC_STRPCL_EXIT_TRANSFER (1 << 6) +#define MSC_STRPCL_START_READWAIT (1 << 5) +#define MSC_STRPCL_STOP_READWAIT (1 << 4) +#define MSC_STRPCL_RESET (1 << 3) +#define MSC_STRPCL_START_OP (1 << 2) +#define MSC_STRPCL_CLOCK_CONTROL_BIT 0 +#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT) + #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */ + #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */ + +/* MSC Status Register (MSC_STAT) */ + +#define MSC_STAT_IS_RESETTING (1 << 15) +#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14) +#define MSC_STAT_PRG_DONE (1 << 13) +#define MSC_STAT_DATA_TRAN_DONE (1 << 12) +#define MSC_STAT_END_CMD_RES (1 << 11) +#define MSC_STAT_DATA_FIFO_AFULL (1 << 10) +#define MSC_STAT_IS_READWAIT (1 << 9) +#define MSC_STAT_CLK_EN (1 << 8) +#define MSC_STAT_DATA_FIFO_FULL (1 << 7) +#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6) +#define MSC_STAT_CRC_RES_ERR (1 << 5) +#define MSC_STAT_CRC_READ_ERROR (1 << 4) +#define MSC_STAT_CRC_WRITE_ERROR_BIT 2 +#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT) + #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */ + #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */ + #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */ +#define MSC_STAT_TIME_OUT_RES (1 << 1) +#define MSC_STAT_TIME_OUT_READ (1 << 0) + +/* MSC Bus Clock Control Register (MSC_CLKRT) */ + +#define MSC_CLKRT_CLK_RATE_BIT 0 +#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT) + #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */ + #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */ + +/* MSC Command Sequence Control Register (MSC_CMDAT) */ + +#define MSC_CMDAT_IO_ABORT (1 << 11) +#define MSC_CMDAT_BUS_WIDTH_BIT 9 +#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT) + #define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) /* 1-bit data bus */ + #define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) /* 4-bit data bus */ + #define CMDAT_BUS_WIDTH1 (0x0 << MSC_CMDAT_BUS_WIDTH_BIT) + #define CMDAT_BUS_WIDTH4 (0x2 << MSC_CMDAT_BUS_WIDTH_BIT) +#define MSC_CMDAT_DMA_EN (1 << 8) +#define MSC_CMDAT_INIT (1 << 7) +#define MSC_CMDAT_BUSY (1 << 6) +#define MSC_CMDAT_STREAM_BLOCK (1 << 5) +#define MSC_CMDAT_WRITE (1 << 4) +#define MSC_CMDAT_READ (0 << 4) +#define MSC_CMDAT_DATA_EN (1 << 3) +#define MSC_CMDAT_RESPONSE_BIT 0 +#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT) + #define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT) /* No response */ + #define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT) /* Format R1 and R1b */ + #define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT) /* Format R2 */ + #define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT) /* Format R3 */ + #define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT) /* Format R4 */ + #define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT) /* Format R5 */ + #define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT) /* Format R6 */ + +#define CMDAT_DMA_EN (1 << 8) +#define CMDAT_INIT (1 << 7) +#define CMDAT_BUSY (1 << 6) +#define CMDAT_STREAM (1 << 5) +#define CMDAT_WRITE (1 << 4) +#define CMDAT_DATA_EN (1 << 3) + +/* MSC Interrupts Mask Register (MSC_IMASK) */ + +#define MSC_IMASK_SDIO (1 << 7) +#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6) +#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5) +#define MSC_IMASK_END_CMD_RES (1 << 2) +#define MSC_IMASK_PRG_DONE (1 << 1) +#define MSC_IMASK_DATA_TRAN_DONE (1 << 0) + + +/* MSC Interrupts Status Register (MSC_IREG) */ + +#define MSC_IREG_SDIO (1 << 7) +#define MSC_IREG_TXFIFO_WR_REQ (1 << 6) +#define MSC_IREG_RXFIFO_RD_REQ (1 << 5) +#define MSC_IREG_END_CMD_RES (1 << 2) +#define MSC_IREG_PRG_DONE (1 << 1) +#define MSC_IREG_DATA_TRAN_DONE (1 << 0) + + +/************************************************************************* + * EMC (External Memory Controller) + *************************************************************************/ +#define EMC_SMCR0 (EMC_BASE + 0x10) /* Static Memory Control Register 0 */ +#define EMC_SMCR1 (EMC_BASE + 0x14) /* Static Memory Control Register 1 */ +#define EMC_SMCR2 (EMC_BASE + 0x18) /* Static Memory Control Register 2 */ +#define EMC_SMCR3 (EMC_BASE + 0x1c) /* Static Memory Control Register 3 */ +#define EMC_SMCR4 (EMC_BASE + 0x20) /* Static Memory Control Register 4 */ +#define EMC_SACR0 (EMC_BASE + 0x30) /* Static Memory Bank 0 Addr Config Reg */ +#define EMC_SACR1 (EMC_BASE + 0x34) /* Static Memory Bank 1 Addr Config Reg */ +#define EMC_SACR2 (EMC_BASE + 0x38) /* Static Memory Bank 2 Addr Config Reg */ +#define EMC_SACR3 (EMC_BASE + 0x3c) /* Static Memory Bank 3 Addr Config Reg */ +#define EMC_SACR4 (EMC_BASE + 0x40) /* Static Memory Bank 4 Addr Config Reg */ + +#define EMC_NFCSR (EMC_BASE + 0x050) /* NAND Flash Control/Status Register */ +#define EMC_NFECR (EMC_BASE + 0x100) /* NAND Flash ECC Control Register */ +#define EMC_NFECC (EMC_BASE + 0x104) /* NAND Flash ECC Data Register */ +#define EMC_NFPAR0 (EMC_BASE + 0x108) /* NAND Flash RS Parity 0 Register */ +#define EMC_NFPAR1 (EMC_BASE + 0x10c) /* NAND Flash RS Parity 1 Register */ +#define EMC_NFPAR2 (EMC_BASE + 0x110) /* NAND Flash RS Parity 2 Register */ +#define EMC_NFINTS (EMC_BASE + 0x114) /* NAND Flash Interrupt Status Register */ +#define EMC_NFINTE (EMC_BASE + 0x118) /* NAND Flash Interrupt Enable Register */ +#define EMC_NFERR0 (EMC_BASE + 0x11c) /* NAND Flash RS Error Report 0 Register */ +#define EMC_NFERR1 (EMC_BASE + 0x120) /* NAND Flash RS Error Report 1 Register */ +#define EMC_NFERR2 (EMC_BASE + 0x124) /* NAND Flash RS Error Report 2 Register */ +#define EMC_NFERR3 (EMC_BASE + 0x128) /* NAND Flash RS Error Report 3 Register */ + +#define EMC_DMCR (EMC_BASE + 0x80) /* DRAM Control Register */ +#define EMC_RTCSR (EMC_BASE + 0x84) /* Refresh Time Control/Status Register */ +#define EMC_RTCNT (EMC_BASE + 0x88) /* Refresh Timer Counter */ +#define EMC_RTCOR (EMC_BASE + 0x8c) /* Refresh Time Constant Register */ +#define EMC_DMAR0 (EMC_BASE + 0x90) /* SDRAM Bank 0 Addr Config Register */ +#define EMC_SDMR0 (EMC_BASE + 0xa000) /* Mode Register of SDRAM bank 0 */ + + +#define REG_EMC_SMCR0 REG32(EMC_SMCR0) +#define REG_EMC_SMCR1 REG32(EMC_SMCR1) +#define REG_EMC_SMCR2 REG32(EMC_SMCR2) +#define REG_EMC_SMCR3 REG32(EMC_SMCR3) +#define REG_EMC_SMCR4 REG32(EMC_SMCR4) +#define REG_EMC_SACR0 REG32(EMC_SACR0) +#define REG_EMC_SACR1 REG32(EMC_SACR1) +#define REG_EMC_SACR2 REG32(EMC_SACR2) +#define REG_EMC_SACR3 REG32(EMC_SACR3) +#define REG_EMC_SACR4 REG32(EMC_SACR4) + +#define REG_EMC_NFCSR REG32(EMC_NFCSR) +#define REG_EMC_NFECR REG32(EMC_NFECR) +#define REG_EMC_NFECC REG32(EMC_NFECC) +#define REG_EMC_NFPAR0 REG32(EMC_NFPAR0) +#define REG_EMC_NFPAR1 REG32(EMC_NFPAR1) +#define REG_EMC_NFPAR2 REG32(EMC_NFPAR2) +#define REG_EMC_NFINTS REG32(EMC_NFINTS) +#define REG_EMC_NFINTE REG32(EMC_NFINTE) +#define REG_EMC_NFERR0 REG32(EMC_NFERR0) +#define REG_EMC_NFERR1 REG32(EMC_NFERR1) +#define REG_EMC_NFERR2 REG32(EMC_NFERR2) +#define REG_EMC_NFERR3 REG32(EMC_NFERR3) + +#define REG_EMC_DMCR REG32(EMC_DMCR) +#define REG_EMC_RTCSR REG16(EMC_RTCSR) +#define REG_EMC_RTCNT REG16(EMC_RTCNT) +#define REG_EMC_RTCOR REG16(EMC_RTCOR) +#define REG_EMC_DMAR0 REG32(EMC_DMAR0) + +/* Static Memory Control Register */ +#define EMC_SMCR_STRV_BIT 24 +#define EMC_SMCR_STRV_MASK (0x0f << EMC_SMCR_STRV_BIT) +#define EMC_SMCR_TAW_BIT 20 +#define EMC_SMCR_TAW_MASK (0x0f << EMC_SMCR_TAW_BIT) +#define EMC_SMCR_TBP_BIT 16 +#define EMC_SMCR_TBP_MASK (0x0f << EMC_SMCR_TBP_BIT) +#define EMC_SMCR_TAH_BIT 12 +#define EMC_SMCR_TAH_MASK (0x07 << EMC_SMCR_TAH_BIT) +#define EMC_SMCR_TAS_BIT 8 +#define EMC_SMCR_TAS_MASK (0x07 << EMC_SMCR_TAS_BIT) +#define EMC_SMCR_BW_BIT 6 +#define EMC_SMCR_BW_MASK (0x03 << EMC_SMCR_BW_BIT) + #define EMC_SMCR_BW_8BIT (0 << EMC_SMCR_BW_BIT) + #define EMC_SMCR_BW_16BIT (1 << EMC_SMCR_BW_BIT) + #define EMC_SMCR_BW_32BIT (2 << EMC_SMCR_BW_BIT) +#define EMC_SMCR_BCM (1 << 3) +#define EMC_SMCR_BL_BIT 1 +#define EMC_SMCR_BL_MASK (0x03 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_4 (0 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_8 (1 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_16 (2 << EMC_SMCR_BL_BIT) + #define EMC_SMCR_BL_32 (3 << EMC_SMCR_BL_BIT) +#define EMC_SMCR_SMT (1 << 0) + +/* Static Memory Bank Addr Config Reg */ +#define EMC_SACR_BASE_BIT 8 +#define EMC_SACR_BASE_MASK (0xff << EMC_SACR_BASE_BIT) +#define EMC_SACR_MASK_BIT 0 +#define EMC_SACR_MASK_MASK (0xff << EMC_SACR_MASK_BIT) + +/* NAND Flash Control/Status Register */ +#define EMC_NFCSR_NFCE4 (1 << 7) /* NAND Flash Enable */ +#define EMC_NFCSR_NFE4 (1 << 6) /* NAND Flash FCE# Assertion Enable */ +#define EMC_NFCSR_NFCE3 (1 << 5) +#define EMC_NFCSR_NFE3 (1 << 4) +#define EMC_NFCSR_NFCE2 (1 << 3) +#define EMC_NFCSR_NFE2 (1 << 2) +#define EMC_NFCSR_NFCE1 (1 << 1) +#define EMC_NFCSR_NFE1 (1 << 0) + +/* NAND Flash ECC Control Register */ +#define EMC_NFECR_PRDY (1 << 4) /* Parity Ready */ +#define EMC_NFECR_RS_DECODING (0 << 3) /* RS is in decoding phase */ +#define EMC_NFECR_RS_ENCODING (1 << 3) /* RS is in encoding phase */ +#define EMC_NFECR_HAMMING (0 << 2) /* Select HAMMING Correction Algorithm */ +#define EMC_NFECR_RS (1 << 2) /* Select RS Correction Algorithm */ +#define EMC_NFECR_ERST (1 << 1) /* ECC Reset */ +#define EMC_NFECR_ECCE (1 << 0) /* ECC Enable */ + +/* NAND Flash ECC Data Register */ +#define EMC_NFECC_ECC2_BIT 16 +#define EMC_NFECC_ECC2_MASK (0xff << EMC_NFECC_ECC2_BIT) +#define EMC_NFECC_ECC1_BIT 8 +#define EMC_NFECC_ECC1_MASK (0xff << EMC_NFECC_ECC1_BIT) +#define EMC_NFECC_ECC0_BIT 0 +#define EMC_NFECC_ECC0_MASK (0xff << EMC_NFECC_ECC0_BIT) + +/* NAND Flash Interrupt Status Register */ +#define EMC_NFINTS_ERRCNT_BIT 29 /* Error Count */ +#define EMC_NFINTS_ERRCNT_MASK (0x7 << EMC_NFINTS_ERRCNT_BIT) +#define EMC_NFINTS_PADF (1 << 4) /* Padding Finished */ +#define EMC_NFINTS_DECF (1 << 3) /* Decoding Finished */ +#define EMC_NFINTS_ENCF (1 << 2) /* Encoding Finished */ +#define EMC_NFINTS_UNCOR (1 << 1) /* Uncorrectable Error Occurred */ +#define EMC_NFINTS_ERR (1 << 0) /* Error Occurred */ + +/* NAND Flash Interrupt Enable Register */ +#define EMC_NFINTE_PADFE (1 << 4) /* Padding Finished Interrupt Enable */ +#define EMC_NFINTE_DECFE (1 << 3) /* Decoding Finished Interrupt Enable */ +#define EMC_NFINTE_ENCFE (1 << 2) /* Encoding Finished Interrupt Enable */ +#define EMC_NFINTE_UNCORE (1 << 1) /* Uncorrectable Error Occurred Intr Enable */ +#define EMC_NFINTE_ERRE (1 << 0) /* Error Occurred Interrupt */ + +/* NAND Flash RS Error Report Register */ +#define EMC_NFERR_INDEX_BIT 16 /* Error Symbol Index */ +#define EMC_NFERR_INDEX_MASK (0x1ff << EMC_NFERR_INDEX_BIT) +#define EMC_NFERR_MASK_BIT 0 /* Error Symbol Value */ +#define EMC_NFERR_MASK_MASK (0x1ff << EMC_NFERR_MASK_BIT) + + +/* DRAM Control Register */ +#define EMC_DMCR_BW_BIT 31 +#define EMC_DMCR_BW (1 << EMC_DMCR_BW_BIT) +#define EMC_DMCR_CA_BIT 26 +#define EMC_DMCR_CA_MASK (0x07 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_8 (0 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_9 (1 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_10 (2 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_11 (3 << EMC_DMCR_CA_BIT) + #define EMC_DMCR_CA_12 (4 << EMC_DMCR_CA_BIT) +#define EMC_DMCR_RMODE (1 << 25) +#define EMC_DMCR_RFSH (1 << 24) +#define EMC_DMCR_MRSET (1 << 23) +#define EMC_DMCR_RA_BIT 20 +#define EMC_DMCR_RA_MASK (0x03 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_11 (0 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_12 (1 << EMC_DMCR_RA_BIT) + #define EMC_DMCR_RA_13 (2 << EMC_DMCR_RA_BIT) +#define EMC_DMCR_BA_BIT 19 +#define EMC_DMCR_BA (1 << EMC_DMCR_BA_BIT) +#define EMC_DMCR_PDM (1 << 18) +#define EMC_DMCR_EPIN (1 << 17) +#define EMC_DMCR_TRAS_BIT 13 +#define EMC_DMCR_TRAS_MASK (0x07 << EMC_DMCR_TRAS_BIT) +#define EMC_DMCR_RCD_BIT 11 +#define EMC_DMCR_RCD_MASK (0x03 << EMC_DMCR_RCD_BIT) +#define EMC_DMCR_TPC_BIT 8 +#define EMC_DMCR_TPC_MASK (0x07 << EMC_DMCR_TPC_BIT) +#define EMC_DMCR_TRWL_BIT 5 +#define EMC_DMCR_TRWL_MASK (0x03 << EMC_DMCR_TRWL_BIT) +#define EMC_DMCR_TRC_BIT 2 +#define EMC_DMCR_TRC_MASK (0x07 << EMC_DMCR_TRC_BIT) +#define EMC_DMCR_TCL_BIT 0 +#define EMC_DMCR_TCL_MASK (0x03 << EMC_DMCR_TCL_BIT) + +/* Refresh Time Control/Status Register */ +#define EMC_RTCSR_CMF (1 << 7) +#define EMC_RTCSR_CKS_BIT 0 +#define EMC_RTCSR_CKS_MASK (0x07 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_DISABLE (0 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_4 (1 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_16 (2 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_64 (3 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_256 (4 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_1024 (5 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_2048 (6 << EMC_RTCSR_CKS_BIT) + #define EMC_RTCSR_CKS_4096 (7 << EMC_RTCSR_CKS_BIT) + +/* SDRAM Bank Address Configuration Register */ +#define EMC_DMAR_BASE_BIT 8 +#define EMC_DMAR_BASE_MASK (0xff << EMC_DMAR_BASE_BIT) +#define EMC_DMAR_MASK_BIT 0 +#define EMC_DMAR_MASK_MASK (0xff << EMC_DMAR_MASK_BIT) + +/* Mode Register of SDRAM bank 0 */ +#define EMC_SDMR_BM (1 << 9) /* Write Burst Mode */ +#define EMC_SDMR_OM_BIT 7 /* Operating Mode */ +#define EMC_SDMR_OM_MASK (3 << EMC_SDMR_OM_BIT) + #define EMC_SDMR_OM_NORMAL (0 << EMC_SDMR_OM_BIT) +#define EMC_SDMR_CAS_BIT 4 /* CAS Latency */ +#define EMC_SDMR_CAS_MASK (7 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_1 (1 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_2 (2 << EMC_SDMR_CAS_BIT) + #define EMC_SDMR_CAS_3 (3 << EMC_SDMR_CAS_BIT) +#define EMC_SDMR_BT_BIT 3 /* Burst Type */ +#define EMC_SDMR_BT_MASK (1 << EMC_SDMR_BT_BIT) + #define EMC_SDMR_BT_SEQ (0 << EMC_SDMR_BT_BIT) /* Sequential */ + #define EMC_SDMR_BT_INT (1 << EMC_SDMR_BT_BIT) /* Interleave */ +#define EMC_SDMR_BL_BIT 0 /* Burst Length */ +#define EMC_SDMR_BL_MASK (7 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_1 (0 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_2 (1 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_4 (2 << EMC_SDMR_BL_BIT) + #define EMC_SDMR_BL_8 (3 << EMC_SDMR_BL_BIT) + +#define EMC_SDMR_CAS2_16BIT \ + (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) +#define EMC_SDMR_CAS2_32BIT \ + (EMC_SDMR_CAS_2 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) +#define EMC_SDMR_CAS3_16BIT \ + (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_2) +#define EMC_SDMR_CAS3_32BIT \ + (EMC_SDMR_CAS_3 | EMC_SDMR_BT_SEQ | EMC_SDMR_BL_4) + + +/************************************************************************* + * CIM + *************************************************************************/ +#define CIM_CFG (CIM_BASE + 0x0000) +#define CIM_CTRL (CIM_BASE + 0x0004) +#define CIM_STATE (CIM_BASE + 0x0008) +#define CIM_IID (CIM_BASE + 0x000C) +#define CIM_RXFIFO (CIM_BASE + 0x0010) +#define CIM_DA (CIM_BASE + 0x0020) +#define CIM_FA (CIM_BASE + 0x0024) +#define CIM_FID (CIM_BASE + 0x0028) +#define CIM_CMD (CIM_BASE + 0x002C) + +#define REG_CIM_CFG REG32(CIM_CFG) +#define REG_CIM_CTRL REG32(CIM_CTRL) +#define REG_CIM_STATE REG32(CIM_STATE) +#define REG_CIM_IID REG32(CIM_IID) +#define REG_CIM_RXFIFO REG32(CIM_RXFIFO) +#define REG_CIM_DA REG32(CIM_DA) +#define REG_CIM_FA REG32(CIM_FA) +#define REG_CIM_FID REG32(CIM_FID) +#define REG_CIM_CMD REG32(CIM_CMD) + +/* CIM Configuration Register (CIM_CFG) */ + +#define CIM_CFG_INV_DAT (1 << 15) +#define CIM_CFG_VSP (1 << 14) +#define CIM_CFG_HSP (1 << 13) +#define CIM_CFG_PCP (1 << 12) +#define CIM_CFG_DUMMY_ZERO (1 << 9) +#define CIM_CFG_EXT_VSYNC (1 << 8) +#define CIM_CFG_PACK_BIT 4 +#define CIM_CFG_PACK_MASK (0x7 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_0 (0 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_1 (1 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_2 (2 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_3 (3 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_4 (4 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_5 (5 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_6 (6 << CIM_CFG_PACK_BIT) + #define CIM_CFG_PACK_7 (7 << CIM_CFG_PACK_BIT) +#define CIM_CFG_DSM_BIT 0 +#define CIM_CFG_DSM_MASK (0x3 << CIM_CFG_DSM_BIT) + #define CIM_CFG_DSM_CPM (0 << CIM_CFG_DSM_BIT) /* CCIR656 Progressive Mode */ + #define CIM_CFG_DSM_CIM (1 << CIM_CFG_DSM_BIT) /* CCIR656 Interlace Mode */ + #define CIM_CFG_DSM_GCM (2 << CIM_CFG_DSM_BIT) /* Gated Clock Mode */ + #define CIM_CFG_DSM_NGCM (3 << CIM_CFG_DSM_BIT) /* Non-Gated Clock Mode */ + +/* CIM Control Register (CIM_CTRL) */ + +#define CIM_CTRL_MCLKDIV_BIT 24 +#define CIM_CTRL_MCLKDIV_MASK (0xff << CIM_CTRL_MCLKDIV_BIT) +#define CIM_CTRL_FRC_BIT 16 +#define CIM_CTRL_FRC_MASK (0xf << CIM_CTRL_FRC_BIT) + #define CIM_CTRL_FRC_1 (0x0 << CIM_CTRL_FRC_BIT) /* Sample every frame */ + #define CIM_CTRL_FRC_2 (0x1 << CIM_CTRL_FRC_BIT) /* Sample 1/2 frame */ + #define CIM_CTRL_FRC_3 (0x2 << CIM_CTRL_FRC_BIT) /* Sample 1/3 frame */ + #define CIM_CTRL_FRC_4 (0x3 << CIM_CTRL_FRC_BIT) /* Sample 1/4 frame */ + #define CIM_CTRL_FRC_5 (0x4 << CIM_CTRL_FRC_BIT) /* Sample 1/5 frame */ + #define CIM_CTRL_FRC_6 (0x5 << CIM_CTRL_FRC_BIT) /* Sample 1/6 frame */ + #define CIM_CTRL_FRC_7 (0x6 << CIM_CTRL_FRC_BIT) /* Sample 1/7 frame */ + #define CIM_CTRL_FRC_8 (0x7 << CIM_CTRL_FRC_BIT) /* Sample 1/8 frame */ + #define CIM_CTRL_FRC_9 (0x8 << CIM_CTRL_FRC_BIT) /* Sample 1/9 frame */ + #define CIM_CTRL_FRC_10 (0x9 << CIM_CTRL_FRC_BIT) /* Sample 1/10 frame */ + #define CIM_CTRL_FRC_11 (0xA << CIM_CTRL_FRC_BIT) /* Sample 1/11 frame */ + #define CIM_CTRL_FRC_12 (0xB << CIM_CTRL_FRC_BIT) /* Sample 1/12 frame */ + #define CIM_CTRL_FRC_13 (0xC << CIM_CTRL_FRC_BIT) /* Sample 1/13 frame */ + #define CIM_CTRL_FRC_14 (0xD << CIM_CTRL_FRC_BIT) /* Sample 1/14 frame */ + #define CIM_CTRL_FRC_15 (0xE << CIM_CTRL_FRC_BIT) /* Sample 1/15 frame */ + #define CIM_CTRL_FRC_16 (0xF << CIM_CTRL_FRC_BIT) /* Sample 1/16 frame */ +#define CIM_CTRL_VDDM (1 << 13) +#define CIM_CTRL_DMA_SOFM (1 << 12) +#define CIM_CTRL_DMA_EOFM (1 << 11) +#define CIM_CTRL_DMA_STOPM (1 << 10) +#define CIM_CTRL_RXF_TRIGM (1 << 9) +#define CIM_CTRL_RXF_OFM (1 << 8) +#define CIM_CTRL_RXF_TRIG_BIT 4 +#define CIM_CTRL_RXF_TRIG_MASK (0x7 << CIM_CTRL_RXF_TRIG_BIT) + #define CIM_CTRL_RXF_TRIG_4 (0 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 4 */ + #define CIM_CTRL_RXF_TRIG_8 (1 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 8 */ + #define CIM_CTRL_RXF_TRIG_12 (2 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 12 */ + #define CIM_CTRL_RXF_TRIG_16 (3 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 16 */ + #define CIM_CTRL_RXF_TRIG_20 (4 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 20 */ + #define CIM_CTRL_RXF_TRIG_24 (5 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 24 */ + #define CIM_CTRL_RXF_TRIG_28 (6 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 28 */ + #define CIM_CTRL_RXF_TRIG_32 (7 << CIM_CTRL_RXF_TRIG_BIT) /* RXFIFO Trigger Value is 32 */ +#define CIM_CTRL_DMA_EN (1 << 2) +#define CIM_CTRL_RXF_RST (1 << 1) +#define CIM_CTRL_ENA (1 << 0) + +/* CIM State Register (CIM_STATE) */ + +#define CIM_STATE_DMA_SOF (1 << 6) +#define CIM_STATE_DMA_EOF (1 << 5) +#define CIM_STATE_DMA_STOP (1 << 4) +#define CIM_STATE_RXF_OF (1 << 3) +#define CIM_STATE_RXF_TRIG (1 << 2) +#define CIM_STATE_RXF_EMPTY (1 << 1) +#define CIM_STATE_VDD (1 << 0) + +/* CIM DMA Command Register (CIM_CMD) */ + +#define CIM_CMD_SOFINT (1 << 31) +#define CIM_CMD_EOFINT (1 << 30) +#define CIM_CMD_STOP (1 << 28) +#define CIM_CMD_LEN_BIT 0 +#define CIM_CMD_LEN_MASK (0xffffff << CIM_CMD_LEN_BIT) + + +/************************************************************************* + * SADC (Smart A/D Controller) + *************************************************************************/ + +#define SADC_ENA (SADC_BASE + 0x00) /* ADC Enable Register */ +#define SADC_CFG (SADC_BASE + 0x04) /* ADC Configure Register */ +#define SADC_CTRL (SADC_BASE + 0x08) /* ADC Control Register */ +#define SADC_STATE (SADC_BASE + 0x0C) /* ADC Status Register*/ +#define SADC_SAMETIME (SADC_BASE + 0x10) /* ADC Same Point Time Register */ +#define SADC_WAITTIME (SADC_BASE + 0x14) /* ADC Wait Time Register */ +#define SADC_TSDAT (SADC_BASE + 0x18) /* ADC Touch Screen Data Register */ +#define SADC_BATDAT (SADC_BASE + 0x1C) /* ADC PBAT Data Register */ +#define SADC_SADDAT (SADC_BASE + 0x20) /* ADC SADCIN Data Register */ + +#define REG_SADC_ENA REG8(SADC_ENA) +#define REG_SADC_CFG REG32(SADC_CFG) +#define REG_SADC_CTRL REG8(SADC_CTRL) +#define REG_SADC_STATE REG8(SADC_STATE) +#define REG_SADC_SAMETIME REG16(SADC_SAMETIME) +#define REG_SADC_WAITTIME REG16(SADC_WAITTIME) +#define REG_SADC_TSDAT REG32(SADC_TSDAT) +#define REG_SADC_BATDAT REG16(SADC_BATDAT) +#define REG_SADC_SADDAT REG16(SADC_SADDAT) + +/* ADC Enable Register */ +#define SADC_ENA_ADEN (1 << 7) /* Touch Screen Enable */ +#define SADC_ENA_TSEN (1 << 2) /* Touch Screen Enable */ +#define SADC_ENA_PBATEN (1 << 1) /* PBAT Enable */ +#define SADC_ENA_SADCINEN (1 << 0) /* SADCIN Enable */ + +/* ADC Configure Register */ +#define SADC_CFG_EXIN (1 << 30) +#define SADC_CFG_CLKOUT_NUM_BIT 16 +#define SADC_CFG_CLKOUT_NUM_MASK (0x7 << SADC_CFG_CLKOUT_NUM_BIT) +#define SADC_CFG_TS_DMA (1 << 15) /* Touch Screen DMA Enable */ +#define SADC_CFG_XYZ_BIT 13 /* XYZ selection */ +#define SADC_CFG_XYZ_MASK (0x3 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XY (0 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XYZ (1 << SADC_CFG_XYZ_BIT) + #define SADC_CFG_XYZ1Z2 (2 << SADC_CFG_XYZ_BIT) +#define SADC_CFG_SNUM_BIT 10 /* Sample Number */ +#define SADC_CFG_SNUM_MASK (0x7 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_1 (0x0 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_2 (0x1 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_3 (0x2 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_4 (0x3 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_5 (0x4 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_6 (0x5 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_8 (0x6 << SADC_CFG_SNUM_BIT) + #define SADC_CFG_SNUM_9 (0x7 << SADC_CFG_SNUM_BIT) +#define SADC_CFG_CLKDIV_BIT 5 /* AD Converter frequency clock divider */ +#define SADC_CFG_CLKDIV_MASK (0x1f << SADC_CFG_CLKDIV_BIT) +#define SADC_CFG_PBAT_HIGH (0 << 4) /* PBAT >= 2.5V */ +#define SADC_CFG_PBAT_LOW (1 << 4) /* PBAT < 2.5V */ +#define SADC_CFG_CMD_BIT 0 /* ADC Command */ +#define SADC_CFG_CMD_MASK (0xf << SADC_CFG_CMD_BIT) + #define SADC_CFG_CMD_X_SE (0x0 << SADC_CFG_CMD_BIT) /* X Single-End */ + #define SADC_CFG_CMD_Y_SE (0x1 << SADC_CFG_CMD_BIT) /* Y Single-End */ + #define SADC_CFG_CMD_X_DIFF (0x2 << SADC_CFG_CMD_BIT) /* X Differential */ + #define SADC_CFG_CMD_Y_DIFF (0x3 << SADC_CFG_CMD_BIT) /* Y Differential */ + #define SADC_CFG_CMD_Z1_DIFF (0x4 << SADC_CFG_CMD_BIT) /* Z1 Differential */ + #define SADC_CFG_CMD_Z2_DIFF (0x5 << SADC_CFG_CMD_BIT) /* Z2 Differential */ + #define SADC_CFG_CMD_Z3_DIFF (0x6 << SADC_CFG_CMD_BIT) /* Z3 Differential */ + #define SADC_CFG_CMD_Z4_DIFF (0x7 << SADC_CFG_CMD_BIT) /* Z4 Differential */ + #define SADC_CFG_CMD_TP_SE (0x8 << SADC_CFG_CMD_BIT) /* Touch Pressure */ + #define SADC_CFG_CMD_PBATH_SE (0x9 << SADC_CFG_CMD_BIT) /* PBAT >= 2.5V */ + #define SADC_CFG_CMD_PBATL_SE (0xa << SADC_CFG_CMD_BIT) /* PBAT < 2.5V */ + #define SADC_CFG_CMD_SADCIN_SE (0xb << SADC_CFG_CMD_BIT) /* Measure SADCIN */ + #define SADC_CFG_CMD_INT_PEN (0xc << SADC_CFG_CMD_BIT) /* INT_PEN Enable */ + +/* ADC Control Register */ +#define SADC_CTRL_PENDM (1 << 4) /* Pen Down Interrupt Mask */ +#define SADC_CTRL_PENUM (1 << 3) /* Pen Up Interrupt Mask */ +#define SADC_CTRL_TSRDYM (1 << 2) /* Touch Screen Data Ready Interrupt Mask */ +#define SADC_CTRL_PBATRDYM (1 << 1) /* PBAT Data Ready Interrupt Mask */ +#define SADC_CTRL_SRDYM (1 << 0) /* SADCIN Data Ready Interrupt Mask */ + +/* ADC Status Register */ +#define SADC_STATE_TSBUSY (1 << 7) /* TS A/D is working */ +#define SADC_STATE_PBATBUSY (1 << 6) /* PBAT A/D is working */ +#define SADC_STATE_SBUSY (1 << 5) /* SADCIN A/D is working */ +#define SADC_STATE_PEND (1 << 4) /* Pen Down Interrupt Flag */ +#define SADC_STATE_PENU (1 << 3) /* Pen Up Interrupt Flag */ +#define SADC_STATE_TSRDY (1 << 2) /* Touch Screen Data Ready Interrupt Flag */ +#define SADC_STATE_PBATRDY (1 << 1) /* PBAT Data Ready Interrupt Flag */ +#define SADC_STATE_SRDY (1 << 0) /* SADCIN Data Ready Interrupt Flag */ + +/* ADC Touch Screen Data Register */ +#define SADC_TSDAT_DATA0_BIT 0 +#define SADC_TSDAT_DATA0_MASK (0xfff << SADC_TSDAT_DATA0_BIT) +#define SADC_TSDAT_TYPE0 (1 << 15) +#define SADC_TSDAT_DATA1_BIT 16 +#define SADC_TSDAT_DATA1_MASK (0xfff << SADC_TSDAT_DATA1_BIT) +#define SADC_TSDAT_TYPE1 (1 << 31) + + +/************************************************************************* + * SLCD (Smart LCD Controller) + *************************************************************************/ + +#define SLCD_CFG (SLCD_BASE + 0xA0) /* SLCD Configure Register */ +#define SLCD_CTRL (SLCD_BASE + 0xA4) /* SLCD Control Register */ +#define SLCD_STATE (SLCD_BASE + 0xA8) /* SLCD Status Register */ +#define SLCD_DATA (SLCD_BASE + 0xAC) /* SLCD Data Register */ +#define SLCD_FIFO (SLCD_BASE + 0xB0) /* SLCD FIFO Register */ + +#define REG_SLCD_CFG REG32(SLCD_CFG) +#define REG_SLCD_CTRL REG8(SLCD_CTRL) +#define REG_SLCD_STATE REG8(SLCD_STATE) +#define REG_SLCD_DATA REG32(SLCD_DATA) +#define REG_SLCD_FIFO REG32(SLCD_FIFO) + +/* SLCD Configure Register */ +#define SLCD_CFG_BURST_BIT 14 +#define SLCD_CFG_BURST_MASK (0x3 << SLCD_CFG_BURST_BIT) + #define SLCD_CFG_BURST_4_WORD (0 << SLCD_CFG_BURST_BIT) + #define SLCD_CFG_BURST_8_WORD (1 << SLCD_CFG_BURST_BIT) +#define SLCD_CFG_DWIDTH_BIT 10 +#define SLCD_CFG_DWIDTH_MASK (0x7 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_18 (0 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_16 (1 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x3 (2 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x2 (3 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_8_x1 (4 << SLCD_CFG_DWIDTH_BIT) + #define SLCD_CFG_DWIDTH_9_x2 (7 << SLCD_CFG_DWIDTH_BIT) +#define SLCD_CFG_CWIDTH_16BIT (0 << 8) +#define SLCD_CFG_CWIDTH_8BIT (1 << 8) +#define SLCD_CFG_CWIDTH_18BIT (2 << 8) +#define SLCD_CFG_CS_ACTIVE_LOW (0 << 4) +#define SLCD_CFG_CS_ACTIVE_HIGH (1 << 4) +#define SLCD_CFG_RS_CMD_LOW (0 << 3) +#define SLCD_CFG_RS_CMD_HIGH (1 << 3) +#define SLCD_CFG_CLK_ACTIVE_FALLING (0 << 1) +#define SLCD_CFG_CLK_ACTIVE_RISING (1 << 1) +#define SLCD_CFG_TYPE_PARALLEL (0 << 0) +#define SLCD_CFG_TYPE_SERIAL (1 << 0) + +/* SLCD Control Register */ +#define SLCD_CTRL_DMA_EN (1 << 0) + +/* SLCD Status Register */ +#define SLCD_STATE_BUSY (1 << 0) + +/* SLCD Data Register */ +#define SLCD_DATA_RS_DATA (0 << 31) +#define SLCD_DATA_RS_COMMAND (1 << 31) + +/* SLCD FIFO Register */ +#define SLCD_FIFO_RS_DATA (0 << 31) +#define SLCD_FIFO_RS_COMMAND (1 << 31) + + +/************************************************************************* + * LCD (LCD Controller) + *************************************************************************/ +#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */ +#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */ +#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */ +#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */ +#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */ +#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */ +#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */ +#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */ +#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */ +#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */ +#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */ +#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */ +#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */ +#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */ +#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */ +#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */ +#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */ +#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */ +#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */ +#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */ +#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */ + +#define REG_LCD_CFG REG32(LCD_CFG) +#define REG_LCD_VSYNC REG32(LCD_VSYNC) +#define REG_LCD_HSYNC REG32(LCD_HSYNC) +#define REG_LCD_VAT REG32(LCD_VAT) +#define REG_LCD_DAH REG32(LCD_DAH) +#define REG_LCD_DAV REG32(LCD_DAV) +#define REG_LCD_PS REG32(LCD_PS) +#define REG_LCD_CLS REG32(LCD_CLS) +#define REG_LCD_SPL REG32(LCD_SPL) +#define REG_LCD_REV REG32(LCD_REV) +#define REG_LCD_CTRL REG32(LCD_CTRL) +#define REG_LCD_STATE REG32(LCD_STATE) +#define REG_LCD_IID REG32(LCD_IID) +#define REG_LCD_DA0 REG32(LCD_DA0) +#define REG_LCD_SA0 REG32(LCD_SA0) +#define REG_LCD_FID0 REG32(LCD_FID0) +#define REG_LCD_CMD0 REG32(LCD_CMD0) +#define REG_LCD_DA1 REG32(LCD_DA1) +#define REG_LCD_SA1 REG32(LCD_SA1) +#define REG_LCD_FID1 REG32(LCD_FID1) +#define REG_LCD_CMD1 REG32(LCD_CMD1) + +/* LCD Configure Register */ +#define LCD_CFG_LCDPIN_BIT 31 /* LCD pins selection */ +#define LCD_CFG_LCDPIN_MASK (0x1 << LCD_CFG_LCDPIN_BIT) + #define LCD_CFG_LCDPIN_LCD (0x0 << LCD_CFG_LCDPIN_BIT) + #define LCD_CFG_LCDPIN_SLCD (0x1 << LCD_CFG_LCDPIN_BIT) +#define LCD_CFG_PSM (1 << 23) /* PS signal mode */ +#define LCD_CFG_CLSM (1 << 22) /* CLS signal mode */ +#define LCD_CFG_SPLM (1 << 21) /* SPL signal mode */ +#define LCD_CFG_REVM (1 << 20) /* REV signal mode */ +#define LCD_CFG_HSYNM (1 << 19) /* HSYNC signal mode */ +#define LCD_CFG_PCLKM (1 << 18) /* PCLK signal mode */ +#define LCD_CFG_INVDAT (1 << 17) /* Inverse output data */ +#define LCD_CFG_SYNDIR_IN (1 << 16) /* VSYNC&HSYNC direction */ +#define LCD_CFG_PSP (1 << 15) /* PS pin reset state */ +#define LCD_CFG_CLSP (1 << 14) /* CLS pin reset state */ +#define LCD_CFG_SPLP (1 << 13) /* SPL pin reset state */ +#define LCD_CFG_REVP (1 << 12) /* REV pin reset state */ +#define LCD_CFG_HSP (1 << 11) /* HSYNC pority:0-active high,1-active low */ +#define LCD_CFG_PCP (1 << 10) /* PCLK pority:0-rising,1-falling */ +#define LCD_CFG_DEP (1 << 9) /* DE pority:0-active high,1-active low */ +#define LCD_CFG_VSP (1 << 8) /* VSYNC pority:0-rising,1-falling */ +#define LCD_CFG_PDW_BIT 4 /* STN pins utilization */ +#define LCD_CFG_PDW_MASK (0x3 << LCD_DEV_PDW_BIT) +#define LCD_CFG_PDW_1 (0 << LCD_CFG_PDW_BIT) /* LCD_D[0] */ + #define LCD_CFG_PDW_2 (1 << LCD_CFG_PDW_BIT) /* LCD_D[0:1] */ + #define LCD_CFG_PDW_4 (2 << LCD_CFG_PDW_BIT) /* LCD_D[0:3]/LCD_D[8:11] */ + #define LCD_CFG_PDW_8 (3 << LCD_CFG_PDW_BIT) /* LCD_D[0:7]/LCD_D[8:15] */ +#define LCD_CFG_MODE_BIT 0 /* Display Device Mode Select */ +#define LCD_CFG_MODE_MASK (0x0f << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_GENERIC_TFT (0 << LCD_CFG_MODE_BIT) /* 16,18 bit TFT */ + #define LCD_CFG_MODE_SPECIAL_TFT_1 (1 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SPECIAL_TFT_2 (2 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SPECIAL_TFT_3 (3 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_NONINTER_CCIR656 (4 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_INTER_CCIR656 (6 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SINGLE_CSTN (8 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SINGLE_MSTN (9 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_DUAL_CSTN (10 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_DUAL_MSTN (11 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SERIAL_TFT (12 << LCD_CFG_MODE_BIT) + /* JZ47XX defines */ + #define LCD_CFG_MODE_SHARP_HR (1 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_CASIO_TFT (2 << LCD_CFG_MODE_BIT) + #define LCD_CFG_MODE_SAMSUNG_ALPHA (3 << LCD_CFG_MODE_BIT) + + + +/* Vertical Synchronize Register */ +#define LCD_VSYNC_VPS_BIT 16 /* VSYNC pulse start in line clock, fixed to 0 */ +#define LCD_VSYNC_VPS_MASK (0xffff << LCD_VSYNC_VPS_BIT) +#define LCD_VSYNC_VPE_BIT 0 /* VSYNC pulse end in line clock */ +#define LCD_VSYNC_VPE_MASK (0xffff << LCD_VSYNC_VPS_BIT) + +/* Horizontal Synchronize Register */ +#define LCD_HSYNC_HPS_BIT 16 /* HSYNC pulse start position in dot clock */ +#define LCD_HSYNC_HPS_MASK (0xffff << LCD_HSYNC_HPS_BIT) +#define LCD_HSYNC_HPE_BIT 0 /* HSYNC pulse end position in dot clock */ +#define LCD_HSYNC_HPE_MASK (0xffff << LCD_HSYNC_HPE_BIT) + +/* Virtual Area Setting Register */ +#define LCD_VAT_HT_BIT 16 /* Horizontal Total size in dot clock */ +#define LCD_VAT_HT_MASK (0xffff << LCD_VAT_HT_BIT) +#define LCD_VAT_VT_BIT 0 /* Vertical Total size in dot clock */ +#define LCD_VAT_VT_MASK (0xffff << LCD_VAT_VT_BIT) + +/* Display Area Horizontal Start/End Point Register */ +#define LCD_DAH_HDS_BIT 16 /* Horizontal display area start in dot clock */ +#define LCD_DAH_HDS_MASK (0xffff << LCD_DAH_HDS_BIT) +#define LCD_DAH_HDE_BIT 0 /* Horizontal display area end in dot clock */ +#define LCD_DAH_HDE_MASK (0xffff << LCD_DAH_HDE_BIT) + +/* Display Area Vertical Start/End Point Register */ +#define LCD_DAV_VDS_BIT 16 /* Vertical display area start in line clock */ +#define LCD_DAV_VDS_MASK (0xffff << LCD_DAV_VDS_BIT) +#define LCD_DAV_VDE_BIT 0 /* Vertical display area end in line clock */ +#define LCD_DAV_VDE_MASK (0xffff << LCD_DAV_VDE_BIT) + +/* PS Signal Setting */ +#define LCD_PS_PSS_BIT 16 /* PS signal start position in dot clock */ +#define LCD_PS_PSS_MASK (0xffff << LCD_PS_PSS_BIT) +#define LCD_PS_PSE_BIT 0 /* PS signal end position in dot clock */ +#define LCD_PS_PSE_MASK (0xffff << LCD_PS_PSE_BIT) + +/* CLS Signal Setting */ +#define LCD_CLS_CLSS_BIT 16 /* CLS signal start position in dot clock */ +#define LCD_CLS_CLSS_MASK (0xffff << LCD_CLS_CLSS_BIT) +#define LCD_CLS_CLSE_BIT 0 /* CLS signal end position in dot clock */ +#define LCD_CLS_CLSE_MASK (0xffff << LCD_CLS_CLSE_BIT) + +/* SPL Signal Setting */ +#define LCD_SPL_SPLS_BIT 16 /* SPL signal start position in dot clock */ +#define LCD_SPL_SPLS_MASK (0xffff << LCD_SPL_SPLS_BIT) +#define LCD_SPL_SPLE_BIT 0 /* SPL signal end position in dot clock */ +#define LCD_SPL_SPLE_MASK (0xffff << LCD_SPL_SPLE_BIT) + +/* REV Signal Setting */ +#define LCD_REV_REVS_BIT 16 /* REV signal start position in dot clock */ +#define LCD_REV_REVS_MASK (0xffff << LCD_REV_REVS_BIT) + +/* LCD Control Register */ +#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */ +#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT) + #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */ + #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */ + #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */ +#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */ +#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */ +#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */ +#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */ +#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT) + #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */ + #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */ + #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */ +#define LCD_CTRL_PDD_BIT 16 /* Load Palette Delay Counter */ +#define LCD_CTRL_PDD_MASK (0xff << LCD_CTRL_PDD_BIT) +#define LCD_CTRL_EOFM (1 << 13) /* EOF interrupt mask */ +#define LCD_CTRL_SOFM (1 << 12) /* SOF interrupt mask */ +#define LCD_CTRL_OFUM (1 << 11) /* Output FIFO underrun interrupt mask */ +#define LCD_CTRL_IFUM0 (1 << 10) /* Input FIFO 0 underrun interrupt mask */ +#define LCD_CTRL_IFUM1 (1 << 9) /* Input FIFO 1 underrun interrupt mask */ +#define LCD_CTRL_LDDM (1 << 8) /* LCD disable done interrupt mask */ +#define LCD_CTRL_QDM (1 << 7) /* LCD quick disable done interrupt mask */ +#define LCD_CTRL_BEDN (1 << 6) /* Endian selection */ +#define LCD_CTRL_PEDN (1 << 5) /* Endian in byte:0-msb first, 1-lsb first */ +#define LCD_CTRL_DIS (1 << 4) /* Disable indicate bit */ +#define LCD_CTRL_ENA (1 << 3) /* LCD enable bit */ +#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */ +#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT) + #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */ + #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */ + #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */ + #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */ + #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */ + #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */ + +/* LCD Status Register */ +#define LCD_STATE_QD (1 << 7) /* Quick Disable Done */ +#define LCD_STATE_EOF (1 << 5) /* EOF Flag */ +#define LCD_STATE_SOF (1 << 4) /* SOF Flag */ +#define LCD_STATE_OFU (1 << 3) /* Output FIFO Underrun */ +#define LCD_STATE_IFU0 (1 << 2) /* Input FIFO 0 Underrun */ +#define LCD_STATE_IFU1 (1 << 1) /* Input FIFO 1 Underrun */ +#define LCD_STATE_LDD (1 << 0) /* LCD Disabled */ + +/* DMA Command Register */ +#define LCD_CMD_SOFINT (1 << 31) +#define LCD_CMD_EOFINT (1 << 30) +#define LCD_CMD_PAL (1 << 28) +#define LCD_CMD_LEN_BIT 0 +#define LCD_CMD_LEN_MASK (0xffffff << LCD_CMD_LEN_BIT) + + +/************************************************************************* + * USB Device + *************************************************************************/ +#define USB_BASE UDC_BASE + +#define USB_REG_FADDR (USB_BASE + 0x00) /* Function Address 8-bit */ +#define USB_REG_POWER (USB_BASE + 0x01) /* Power Managemetn 8-bit */ +#define USB_REG_INTRIN (USB_BASE + 0x02) /* Interrupt IN 16-bit */ +#define USB_REG_INTROUT (USB_BASE + 0x04) /* Interrupt OUT 16-bit */ +#define USB_REG_INTRINE (USB_BASE + 0x06) /* Intr IN enable 16-bit */ +#define USB_REG_INTROUTE (USB_BASE + 0x08) /* Intr OUT enable 16-bit */ +#define USB_REG_INTRUSB (USB_BASE + 0x0a) /* Interrupt USB 8-bit */ +#define USB_REG_INTRUSBE (USB_BASE + 0x0b) /* Interrupt USB Enable 8-bit */ +#define USB_REG_FRAME (USB_BASE + 0x0c) /* Frame number 16-bit */ +#define USB_REG_INDEX (USB_BASE + 0x0e) /* Index register 8-bit */ +#define USB_REG_TESTMODE (USB_BASE + 0x0f) /* USB test mode 8-bit */ + +#define USB_REG_CSR0 (USB_BASE + 0x12) /* EP0 CSR 8-bit */ +#define USB_REG_INMAXP (USB_BASE + 0x10) /* EP1-2 IN Max Pkt Size 16-bit */ +#define USB_REG_INCSR (USB_BASE + 0x12) /* EP1-2 IN CSR LSB 8/16bit */ +#define USB_REG_INCSRH (USB_BASE + 0x13) /* EP1-2 IN CSR MSB 8-bit */ +#define USB_REG_OUTMAXP (USB_BASE + 0x14) /* EP1 OUT Max Pkt Size 16-bit */ +#define USB_REG_OUTCSR (USB_BASE + 0x16) /* EP1 OUT CSR LSB 8/16bit */ +#define USB_REG_OUTCSRH (USB_BASE + 0x17) /* EP1 OUT CSR MSB 8-bit */ +#define USB_REG_OUTCOUNT (USB_BASE + 0x18) /* bytes in EP0/1 OUT FIFO 16-bit */ + +#define USB_FIFO_EP0 (USB_BASE + 0x20) +#define USB_FIFO_EP1 (USB_BASE + 0x24) +#define USB_FIFO_EP2 (USB_BASE + 0x28) + +#define USB_REG_EPINFO (USB_BASE + 0x78) /* Endpoint information */ +#define USB_REG_RAMINFO (USB_BASE + 0x79) /* RAM information */ + +#define USB_REG_INTR (USB_BASE + 0x200) /* DMA pending interrupts */ +#define USB_REG_CNTL1 (USB_BASE + 0x204) /* DMA channel 1 control */ +#define USB_REG_ADDR1 (USB_BASE + 0x208) /* DMA channel 1 AHB memory addr */ +#define USB_REG_COUNT1 (USB_BASE + 0x20c) /* DMA channel 1 byte count */ +#define USB_REG_CNTL2 (USB_BASE + 0x214) /* DMA channel 2 control */ +#define USB_REG_ADDR2 (USB_BASE + 0x218) /* DMA channel 2 AHB memory addr */ +#define USB_REG_COUNT2 (USB_BASE + 0x21c) /* DMA channel 2 byte count */ + + +/* Power register bit masks */ +#define USB_POWER_SUSPENDM 0x01 +#define USB_POWER_RESUME 0x04 +#define USB_POWER_HSMODE 0x10 +#define USB_POWER_HSENAB 0x20 +#define USB_POWER_SOFTCONN 0x40 + +/* Interrupt register bit masks */ +#define USB_INTR_SUSPEND 0x01 +#define USB_INTR_RESUME 0x02 +#define USB_INTR_RESET 0x04 + +#define USB_INTR_EP0 0x0001 +#define USB_INTR_INEP1 0x0002 +#define USB_INTR_INEP2 0x0004 +#define USB_INTR_OUTEP1 0x0002 + +/* CSR0 bit masks */ +#define USB_CSR0_OUTPKTRDY 0x01 +#define USB_CSR0_INPKTRDY 0x02 +#define USB_CSR0_SENTSTALL 0x04 +#define USB_CSR0_DATAEND 0x08 +#define USB_CSR0_SETUPEND 0x10 +#define USB_CSR0_SENDSTALL 0x20 +#define USB_CSR0_SVDOUTPKTRDY 0x40 +#define USB_CSR0_SVDSETUPEND 0x80 + +/* Endpoint CSR register bits */ +#define USB_INCSRH_AUTOSET 0x80 +#define USB_INCSRH_ISO 0x40 +#define USB_INCSRH_MODE 0x20 +#define USB_INCSRH_DMAREQENAB 0x10 +#define USB_INCSRH_DMAREQMODE 0x04 +#define USB_INCSR_CDT 0x40 +#define USB_INCSR_SENTSTALL 0x20 +#define USB_INCSR_SENDSTALL 0x10 +#define USB_INCSR_FF 0x08 +#define USB_INCSR_UNDERRUN 0x04 +#define USB_INCSR_FFNOTEMPT 0x02 +#define USB_INCSR_INPKTRDY 0x01 +#define USB_OUTCSRH_AUTOCLR 0x80 +#define USB_OUTCSRH_ISO 0x40 +#define USB_OUTCSRH_DMAREQENAB 0x20 +#define USB_OUTCSRH_DNYT 0x10 +#define USB_OUTCSRH_DMAREQMODE 0x08 +#define USB_OUTCSR_CDT 0x80 +#define USB_OUTCSR_SENTSTALL 0x40 +#define USB_OUTCSR_SENDSTALL 0x20 +#define USB_OUTCSR_FF 0x10 +#define USB_OUTCSR_DATAERR 0x08 +#define USB_OUTCSR_OVERRUN 0x04 +#define USB_OUTCSR_FFFULL 0x02 +#define USB_OUTCSR_OUTPKTRDY 0x01 + +/* Testmode register bits */ +#define USB_TEST_SE0NAK 0x01 +#define USB_TEST_J 0x02 +#define USB_TEST_K 0x04 +#define USB_TEST_PACKET 0x08 + +/* DMA control bits */ +#define USB_CNTL_ENA 0x01 +#define USB_CNTL_DIR_IN 0x02 +#define USB_CNTL_MODE_1 0x04 +#define USB_CNTL_INTR_EN 0x08 +#define USB_CNTL_EP(n) ((n) << 4) +#define USB_CNTL_BURST_0 (0 << 9) +#define USB_CNTL_BURST_4 (1 << 9) +#define USB_CNTL_BURST_8 (2 << 9) +#define USB_CNTL_BURST_16 (3 << 9) + +#endif /* __JZ4740_REGS_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/serial.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/serial.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/serial.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/serial.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,30 @@ +/* + * linux/include/asm-mips/mach-jz4740/serial.h + * + * Ingenic's JZ4740 common include. + * + * Copyright (C) 2006 - 2007 Ingenic Semiconductor Inc. + * + * Author: + * + * 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 __ASM_BOARD_SERIAL_H__ +#define __ASM_BOARD_SERIAL_H__ + +#ifndef CONFIG_SERIAL_MANY_PORTS +#undef RS_TABLE_SIZE +#define RS_TABLE_SIZE 1 +#endif + +#define JZ_BASE_BAUD (12000000/16) + +#define JZ_SERIAL_PORT_DEFNS \ + { .baud_base = JZ_BASE_BAUD, .irq = IRQ_UART0, \ + .flags = STD_COM_FLAGS, .iomem_base = (u8 *)UART0_BASE, \ + .iomem_reg_shift = 2, .io_type = SERIAL_IO_MEM }, + +#endif /* __ASM_BORAD_SERIAL_H__ */ diff -ruN linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/war.h linux-2.6.31/arch/mips/include/asm/mach-jz4740/war.h --- linux-2.6.31-vanilla/arch/mips/include/asm/mach-jz4740/war.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/include/asm/mach-jz4740/war.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,25 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2002, 2004, 2007 by Ralf Baechle + */ +#ifndef __ASM_MIPS_MACH_JZ4740_WAR_H +#define __ASM_MIPS_MACH_JZ4740_WAR_H + +#define R4600_V1_INDEX_ICACHEOP_WAR 0 +#define R4600_V1_HIT_CACHEOP_WAR 0 +#define R4600_V2_HIT_CACHEOP_WAR 0 +#define R5432_CP0_INTERRUPT_WAR 0 +#define BCM1250_M3_WAR 0 +#define SIBYTE_1956_WAR 0 +#define MIPS4K_ICACHE_REFILL_WAR 0 +#define MIPS_CACHE_SYNC_WAR 0 +#define TX49XX_ICACHE_INDEX_INV_WAR 0 +#define RM9000_CDEX_SMP_WAR 0 +#define ICACHE_REFILLS_WORKAROUND_WAR 0 +#define R10000_LLSC_WAR 0 +#define MIPS34K_MISSED_ITLB_WAR 0 + +#endif /* __ASM_MIPS_MACH_JZ4740_WAR_H */ diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/Kconfig linux-2.6.31/arch/mips/jz4740/Kconfig --- linux-2.6.31-vanilla/arch/mips/jz4740/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/Kconfig 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,29 @@ +choice + prompt "Machine type" + depends on MACH_JZ + default JZ4740_QI_LB60 + +config JZ4740_QI_LB60 + bool "Qi Hardware Ben NanoNote" + select DMA_NONCOHERENT + select SOC_JZ4740 + +endchoice + +config SOC_JZ4740 + bool + select JZSOC + select GENERIC_GPIO + select ARCH_REQUIRE_GPIOLIB + select SYS_HAS_EARLY_PRINTK + select SYS_SUPPORTS_LITTLE_ENDIAN + select IRQ_CPU + +config JZSOC + bool + select JZRISC + select SYS_HAS_CPU_MIPS32_R1 + select SYS_SUPPORTS_32BIT_KERNEL + +config JZRISC + bool diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/Makefile linux-2.6.31/arch/mips/jz4740/Makefile --- linux-2.6.31-vanilla/arch/mips/jz4740/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/Makefile 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,27 @@ +# +# Makefile for the Ingenic JZ4740. +# + +# Object file lists. + +obj-y += prom.o irq.o time.o reset.o setup.o dma.o \ + gpio.o clock.o platform.o + +obj-$(CONFIG_PROC_FS) += proc.o + +# board specific support + +obj-$(CONFIG_JZ4740_PAVO) += board-pavo.o +obj-$(CONFIG_JZ4740_LEO) += board-leo.o +obj-$(CONFIG_JZ4740_LYRA) += board-lyra.o +obj-$(CONFIG_JZ4725_DIPPER) += board-dipper.o +obj-$(CONFIG_JZ4720_VIRGO) += board-virgo.o +obj-$(CONFIG_JZ4740_QI_LB60) += board-qi_lb60.o + +# PM support + +obj-$(CONFIG_PM) +=pm.o + +# CPU Frequency scaling support + +obj-$(CONFIG_CPU_FREQ_JZ) +=cpufreq.o diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/board-qi_lb60.c linux-2.6.31/arch/mips/jz4740/board-qi_lb60.c --- linux-2.6.31-vanilla/arch/mips/jz4740/board-qi_lb60.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/board-qi_lb60.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,389 @@ +/* + * linux/arch/mips/jz4740/board-qi_lb60.c + * + * QI_LB60 setup routines. + * + * Copyright (c) 2009 Qi Hardware inc., + * Author: Xiangfu Liu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* NAND */ +static struct nand_ecclayout qi_lb60_ecclayout_1gb = { + .eccbytes = 36, + .eccpos = { + 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41}, + .oobfree = { + {.offset = 2, + .length = 4}, + {.offset = 42, + .length = 22}} +}; + +static struct mtd_partition qi_lb60_partitions_1gb[] = { + { .name = "NAND BOOT partition", + .offset = 0 * 0x100000, + .size = 4 * 0x100000, + }, + { .name = "NAND KERNEL partition", + .offset = 4 * 0x100000, + .size = 4 * 0x100000, + }, + { .name = "NAND ROOTFS partition", + .offset = 8 * 0x100000, + .size = 504 * 0x100000, + }, + { .name = "NAND DATA partition", + .offset = 512 * 0x100000, + .size = 512 * 0x100000, + }, +}; + +static struct nand_ecclayout qi_lb60_ecclayout_2gb = { + .eccbytes = 72, + .eccpos = { + 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83}, + .oobfree = { + {.offset = 2, + .length = 10}, + {.offset = 84, + .length = 44}} +}; + +static struct mtd_partition qi_lb60_partitions_2gb[] = { + { .name = "NAND BOOT partition", + .offset = 0 * 0x100000, + .size = 4 * 0x100000, + }, + { .name = "NAND KERNEL partition", + .offset = 4 * 0x100000, + .size = 4 * 0x100000, + }, + { .name = "NAND ROOTFS partition", + .offset = 8 * 0x100000, + .size = 504 * 0x100000, + }, + { .name = "NAND DATA partition", + .offset = 512 * 0x100000, + .size = (512 + 1024) * 0x100000, + }, +}; + +static void qi_lb60_nand_ident(struct platform_device *pdev, + struct nand_chip *chip, + struct mtd_partition **partitions, + int *num_partitions) +{ + if (chip->page_shift == 12) { + chip->ecc.layout = &qi_lb60_ecclayout_2gb; + *partitions = qi_lb60_partitions_2gb; + *num_partitions = ARRAY_SIZE(qi_lb60_partitions_2gb); + } else { + chip->ecc.layout = &qi_lb60_ecclayout_1gb; + *partitions = qi_lb60_partitions_1gb; + *num_partitions = ARRAY_SIZE(qi_lb60_partitions_1gb); + } +} + +static struct jz_nand_platform_data qi_lb60_nand_pdata = { + .ident_callback = qi_lb60_nand_ident, + .busy_gpio = 94, +}; + + +/* Keyboard*/ + +/* #define KEEP_UART_ALIVE + * don't define this. the keyboard and keyboard both work + */ + +#define KEY_QI_QI KEY_F13 +#define KEY_QI_UPRED KEY_RIGHTSHIFT +#define KEY_QI_VOLUP KEY_F15 +#define KEY_QI_VOLDOWN KEY_F16 +#define KEY_QI_FN KEY_RIGHTCTRL + +static const uint32_t qi_lb60_keymap[] = { + KEY(0, 0, KEY_F1), /* S2 */ + KEY(0, 1, KEY_F2), /* S3 */ + KEY(0, 2, KEY_F3), /* S4 */ + KEY(0, 3, KEY_F4), /* S5 */ + KEY(0, 4, KEY_F5), /* S6 */ + KEY(0, 5, KEY_F6), /* S7 */ + KEY(0, 6, KEY_F7), /* S8 */ + + KEY(1, 0, KEY_Q), /* S10 */ + KEY(1, 1, KEY_W), /* S11 */ + KEY(1, 2, KEY_E), /* S12 */ + KEY(1, 3, KEY_R), /* S13 */ + KEY(1, 4, KEY_T), /* S14 */ + KEY(1, 5, KEY_Y), /* S15 */ + KEY(1, 6, KEY_U), /* S16 */ + KEY(1, 7, KEY_I), /* S17 */ + KEY(2, 0, KEY_A), /* S18 */ + KEY(2, 1, KEY_S), /* S19 */ + KEY(2, 2, KEY_D), /* S20 */ + KEY(2, 3, KEY_F), /* S21 */ + KEY(2, 4, KEY_G), /* S22 */ + KEY(2, 5, KEY_H), /* S23 */ + KEY(2, 6, KEY_J), /* S24 */ + KEY(2, 7, KEY_K), /* S25 */ + KEY(3, 0, KEY_ESC), /* S26 */ + KEY(3, 1, KEY_Z), /* S27 */ + KEY(3, 2, KEY_X), /* S28 */ + KEY(3, 3, KEY_C), /* S29 */ + KEY(3, 4, KEY_V), /* S30 */ + KEY(3, 5, KEY_B), /* S31 */ + KEY(3, 6, KEY_N), /* S32 */ + KEY(3, 7, KEY_M), /* S33 */ + KEY(4, 0, KEY_TAB), /* S34 */ + KEY(4, 1, KEY_CAPSLOCK), /* S35 */ + KEY(4, 2, KEY_BACKSLASH), /* S36 */ + KEY(4, 3, KEY_APOSTROPHE), /* S37 */ + KEY(4, 4, KEY_COMMA), /* S38 */ + KEY(4, 5, KEY_DOT), /* S39 */ + KEY(4, 6, KEY_SLASH), /* S40 */ + KEY(4, 7, KEY_UP), /* S41 */ + KEY(5, 0, KEY_O), /* S42 */ + KEY(5, 1, KEY_L), /* S43 */ + KEY(5, 2, KEY_EQUAL), /* S44 */ + KEY(5, 3, KEY_QI_UPRED), /* S45 */ + KEY(5, 4, KEY_SPACE), /* S46 */ + KEY(5, 5, KEY_QI_QI), /* S47 */ + KEY(5, 6, KEY_LEFTCTRL), /* S48 */ + KEY(5, 7, KEY_LEFT), /* S49 */ + KEY(6, 0, KEY_F8), /* S50 */ + KEY(6, 1, KEY_P), /* S51 */ + KEY(6, 2, KEY_BACKSPACE),/* S52 */ + KEY(6, 3, KEY_ENTER), /* S53 */ + KEY(6, 4, KEY_QI_VOLUP), /* S54 */ + KEY(6, 5, KEY_QI_VOLDOWN), /* S55 */ + KEY(6, 6, KEY_DOWN), /* S56 */ + KEY(6, 7, KEY_RIGHT), /* S57 */ + +#ifndef KEEP_UART_ALIVE + KEY(7, 0, KEY_LEFTSHIFT), /* S58 */ + KEY(7, 1, KEY_LEFTALT), /* S59 */ + KEY(7, 2, KEY_QI_FN), /* S60 */ +#endif +}; + +static const struct matrix_keymap_data qi_lb60_keymap_data = { + .keymap = qi_lb60_keymap, + .keymap_size = ARRAY_SIZE(qi_lb60_keymap), +}; + +static const unsigned int qi_lb60_keypad_cols[] = { + 74, 75, 76, 77, 78, 79, 80, 81, +}; + +static const unsigned int qi_lb60_keypad_rows[] = { + 114, 115, 116, 117, 118, 119, 120, +#ifndef KEEP_UART_ALIVE + 122, +#endif +}; + +static struct matrix_keypad_platform_data qi_lb60_pdata = { + .keymap_data = &qi_lb60_keymap_data, + .col_gpios = qi_lb60_keypad_cols, + .row_gpios = qi_lb60_keypad_rows, + .num_col_gpios = ARRAY_SIZE(qi_lb60_keypad_cols), + .num_row_gpios = ARRAY_SIZE(qi_lb60_keypad_rows), + .col_scan_delay_us = 10, + .debounce_ms = 10, + .wakeup = 1, + .active_low = 1, +}; + +static struct platform_device qi_lb60_keypad = { + .name = "matrix-keypad", + .id = -1, + .dev = { + .platform_data = &qi_lb60_pdata, + }, +}; + +/* Display */ +static struct fb_videomode qi_lb60_video_modes[] = { + { + .name = "320x240", + .xres = 320, + .yres = 240, + .pixclock = 700000, + .left_margin = 140, + .right_margin = 273, + .upper_margin = 20, + .lower_margin = 2, + .hsync_len = 1, + .vsync_len = 1, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; + +static struct jz4740_fb_platform_data qi_lb60_fb_pdata = { + .width = 60, + .height = 45, + .num_modes = ARRAY_SIZE(qi_lb60_video_modes), + .modes = qi_lb60_video_modes, + .bpp = 24, + .lcd_type = JZ_LCD_TYPE_8BIT_SERIAL, +}; + + +struct spi_gpio_platform_data spigpio_platform_data = { + .sck = JZ_GPIO_PORTC(23), + .mosi = JZ_GPIO_PORTC(22), + .miso = JZ_GPIO_PORTC(22), + .num_chipselect = 1, +}; + +static struct platform_device spigpio_device = { + .name = "spi_gpio", + .id = 1, + .dev = { + .platform_data = &spigpio_platform_data, + }, +}; + +static struct spi_board_info qi_lb60_spi_board_info[] = { + { + .modalias = "gpm940b0", + .controller_data = (void*)JZ_GPIO_PORTC(21), + .chip_select = 0, + .bus_num = 1, + .max_speed_hz = 30 * 1000, + }, +}; + +/* Battery */ +static struct jz_batt_info qi_lb60_battery_pdata = { + .dc_dect_gpio = GPIO_DC_DETE_N, + .usb_dect_gpio = GPIO_USB_DETE, + .charg_stat_gpio = GPIO_CHARG_STAT_N, + + .min_voltag = 3600000, + .max_voltag = 4200000, + .batt_tech = POWER_SUPPLY_TECHNOLOGY_LIPO, +}; + +/* GPIO Key: power */ +static struct gpio_keys_button qi_lb60_gpio_keys_buttons[] = { + [0] = { + .code = KEY_POWER, + .gpio = GPIO_WAKEUP_N, + .active_low = 1, + .desc = "Power", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data qi_lb60_gpio_keys_data = { + .nbuttons = ARRAY_SIZE(qi_lb60_gpio_keys_buttons), + .buttons = qi_lb60_gpio_keys_buttons, +}; + +static struct platform_device qi_lb60_gpio_keys = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &qi_lb60_gpio_keys_data, + } +}; +/* +static struct jz_mmc_platform_data jz_mmc_pdata = { + .card_detect_gpio = JZ_GPIO_PORTD(0), + .read_only_gpio = JZ_GPIO_PORTD(16), + .power_gpio = JZ_GPIO_PORTD(2), +};*/ + +static struct platform_device *jz_platform_devices[] __initdata = { + &jz4740_usb_ohci_device, + &jz4740_usb_gdt_device, + &jz4740_mmc_device, + &jz4740_nand_device, + &qi_lb60_keypad, + &spigpio_device, + &jz4740_framebuffer_device, + &jz4740_i2s_device, + &jz4740_codec_device, + &jz4740_rtc_device, + &jz4740_adc_device, + &jz4740_battery_device, + &qi_lb60_gpio_keys, +}; + +static void __init board_gpio_setup(void) +{ + /* We only need to enable/disable pullup here for pins used in generic + * drivers. Everything else is done by the drivers themselfs. */ + jz_gpio_disable_pullup(GPIO_SD_VCC_EN_N); + jz_gpio_disable_pullup(GPIO_SD_CD_N); + jz_gpio_disable_pullup(GPIO_SD_WP); +} + +static int __init qi_lb60_init_platform_devices(void) +{ + jz4740_framebuffer_device.dev.platform_data = &qi_lb60_fb_pdata; + jz4740_nand_device.dev.platform_data = &qi_lb60_nand_pdata; + jz4740_battery_device.dev.platform_data = &qi_lb60_battery_pdata; + + spi_register_board_info(qi_lb60_spi_board_info, + ARRAY_SIZE(qi_lb60_spi_board_info)); + + return platform_add_devices(jz_platform_devices, + ARRAY_SIZE(jz_platform_devices)); + +} +extern int jz_gpiolib_init(void); + +static int __init qi_lb60_board_setup(void) +{ + printk("Qi Hardware JZ4740 QI_LB60 setup\n"); + if (jz_gpiolib_init()) + panic("Failed to initalize jz gpio\n"); + + board_gpio_setup(); + + if (qi_lb60_init_platform_devices()) + panic("Failed to initalize platform devices\n"); + + return 0; +} + +arch_initcall(qi_lb60_board_setup); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/clock.c linux-2.6.31/arch/mips/jz4740/clock.c --- linux-2.6.31-vanilla/arch/mips/jz4740/clock.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/clock.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,777 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define JZ_REG_CLOCK_CTRL 0x00 +#define JZ_REG_CLOCK_PLL 0x10 +#define JZ_REG_CLOCK_GATE 0x20 +#define JZ_REG_CLOCK_I2S 0x60 +#define JZ_REG_CLOCK_LCD 0x64 +#define JZ_REG_CLOCK_MMC 0x68 +#define JZ_REG_CLOCK_UHC 0x6C +#define JZ_REG_CLOCK_SPI 0x74 + +#define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31) +#define JZ_CLOCK_CTRL_KO_ENABLE BIT(30) +#define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29) +#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000 +#define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22) +#define JZ_CLOCK_CTRL_PLL_HALF BIT(21) +#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000 +#define JZ_CLOCK_CTRL_UDIV_OFFSET 23 +#define JZ_CLOCK_CTRL_LDIV_OFFSET 16 +#define JZ_CLOCK_CTRL_MDIV_OFFSET 12 +#define JZ_CLOCK_CTRL_PDIV_OFFSET 8 +#define JZ_CLOCK_CTRL_HDIV_OFFSET 4 +#define JZ_CLOCK_CTRL_CDIV_OFFSET 0 + +#define JZ_CLOCK_GATE_UART0 BIT(0) +#define JZ_CLOCK_GATE_TCU BIT(1) +#define JZ_CLOCK_GATE_RTC BIT(2) +#define JZ_CLOCK_GATE_I2C BIT(3) +#define JZ_CLOCK_GATE_SPI BIT(4) +#define JZ_CLOCK_GATE_AIC_PCLK BIT(5) +#define JZ_CLOCK_GATE_AIC BIT(6) +#define JZ_CLOCK_GATE_MMC BIT(7) +#define JZ_CLOCK_GATE_ADC BIT(8) +#define JZ_CLOCK_GATE_CIM BIT(9) +#define JZ_CLOCK_GATE_LCD BIT(10) +#define JZ_CLOCK_GATE_UDC BIT(11) +#define JZ_CLOCK_GATE_DMAC BIT(12) +#define JZ_CLOCK_GATE_IPU BIT(13) +#define JZ_CLOCK_GATE_UHC BIT(14) +#define JZ_CLOCK_GATE_UART1 BIT(15) + +#define JZ_CLOCK_I2S_DIV_MASK 0x01ff + +#define JZ_CLOCK_LCD_DIV_MASK 0x01ff + +#define JZ_CLOCK_MMC_DIV_MASK 0x001f + +#define JZ_CLOCK_UHC_DIV_MASK 0x000f + +#define JZ_CLOCK_SPI_SRC_PLL BIT(31) +#define JZ_CLOCK_SPI_DIV_MASK 0x000f + +#define JZ_CLOCK_PLL_M_MASK 0x01ff +#define JZ_CLOCK_PLL_N_MASK 0x001f +#define JZ_CLOCK_PLL_OD_MASK 0x0003 +#define JZ_CLOCK_PLL_STABLE BIT(10) +#define JZ_CLOCK_PLL_BYPASS BIT(9) +#define JZ_CLOCK_PLL_ENABLED BIT(8) +#define JZ_CLOCK_PLL_STABLIZE_MASK 0x000f +#define JZ_CLOCK_PLL_M_OFFSET 23 +#define JZ_CLOCK_PLL_N_OFFSET 18 +#define JZ_CLOCK_PLL_OD_OFFSET 16 + +static void __iomem *jz_clock_base; +spinlock_t jz_clock_lock; +static LIST_HEAD(jz_clocks); + +struct clk { + const char *name; + struct clk* parent; + + uint32_t gate_bit; + + unsigned long (*get_rate)(struct clk* clk); + unsigned long (*round_rate)(struct clk *clk, unsigned long rate); + int (*set_rate)(struct clk* clk, unsigned long rate); + int (*enable)(struct clk* clk); + int (*disable)(struct clk* clk); + + int (*set_parent)(struct clk* clk, struct clk *parent); + struct list_head list; +}; + +struct main_clk { + struct clk clk; + uint32_t div_offset; +}; + +struct divided_clk { + struct clk clk; + uint32_t reg; + uint32_t mask; +}; + +struct static_clk { + struct clk clk; + unsigned long rate; +}; + +static uint32_t jz_clk_reg_read(int reg) +{ + return readl(jz_clock_base + reg); +} + +static void jz_clk_reg_write_mask(int reg, uint32_t val, uint32_t mask) +{ + uint32_t val2; + + spin_lock(&jz_clock_lock); + val2 = readl(jz_clock_base + reg); + val2 &= ~mask; + val2 |= val; + writel(val2, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static void jz_clk_reg_set_bits(int reg, uint32_t mask) +{ + uint32_t val; + + spin_lock(&jz_clock_lock); + val = readl(jz_clock_base + reg); + val |= mask; + writel(val, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static void jz_clk_reg_clear_bits(int reg, uint32_t mask) +{ + uint32_t val; + + spin_lock(&jz_clock_lock); + val = readl(jz_clock_base + reg); + val &= ~mask; + writel(val, jz_clock_base + reg); + spin_unlock(&jz_clock_lock); +} + +static int jz_clk_enable_gating(struct clk *clk) +{ + jz_clk_reg_clear_bits(JZ_REG_CLOCK_GATE, clk->gate_bit); + return 0; +} + +static int jz_clk_disable_gating(struct clk *clk) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_GATE, clk->gate_bit); + return 0; +} + +static unsigned long jz_clk_static_get_rate(struct clk *clk) +{ + return ((struct static_clk*)clk)->rate; +} + +static int jz_clk_ko_enable(struct clk* clk) +{ + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE); + return 0; +} + +static int jz_clk_ko_disable(struct clk* clk) +{ + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_KO_ENABLE); + return 0; +} + + +static const int pllno[] = {1, 2, 2, 4}; + +static unsigned long jz_clk_pll_get_rate(struct clk *clk) +{ + uint32_t val; + int m; + int n; + int od; + + val = jz_clk_reg_read(JZ_REG_CLOCK_PLL); + + if (val & JZ_CLOCK_PLL_BYPASS) + return clk_get_rate(clk->parent); + + m = ((val >> 23) & 0x1ff) + 2; + n = ((val >> 18) & 0x1f) + 2; + od = (val >> 16) & 0x3; + + return clk_get_rate(clk->parent) * (m / n) / pllno[od]; +} + +static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) +{ + uint32_t reg; + + reg = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + if (reg & JZ_CLOCK_CTRL_PLL_HALF) + return jz_clk_pll_get_rate(NULL) >> 1; + return jz_clk_pll_get_rate(NULL); +} + + + +static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + +static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent_rate = jz_clk_pll_get_rate(NULL); + int div; + + div = parent_rate / rate; + if (div > 32) + return parent_rate / 32; + else if (div < 1) + return parent_rate; + + div &= (0x3 << (ffs(div) - 1)); + + return parent_rate / div; +} + +static unsigned long jz_clk_main_get_rate(struct clk *clk) { + struct main_clk *mclk = (struct main_clk*)clk; + uint32_t div; + + div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + + div >>= mclk->div_offset; + div &= 0xf; + + if (div >= ARRAY_SIZE(jz_clk_main_divs)) + div = ARRAY_SIZE(jz_clk_main_divs) - 1; + + return jz_clk_pll_get_rate(NULL) / jz_clk_main_divs[div]; +} + +static int jz_clk_main_set_rate(struct clk *clk, unsigned long rate) +{ + struct main_clk *mclk = (struct main_clk*)clk; + int i; + int div; + unsigned long parent_rate = jz_clk_pll_get_rate(NULL); + + rate = jz_clk_main_round_rate(clk, rate); + + div = parent_rate / rate; + + i = (ffs(div) - 1) << 1; + if (i > 0 && !(div & BIT(i-1))) + i -= 1; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, i << mclk->div_offset, + 0xf << mclk->div_offset); + + return 0; +} + + +static struct static_clk jz_clk_ext = { + .clk = { + .name = "ext", + .get_rate = jz_clk_static_get_rate, + }, +}; + +static struct clk jz_clk_pll = { + .name = "pll", + .parent = &jz_clk_ext.clk, + .get_rate = jz_clk_pll_get_rate, +}; + +static struct clk jz_clk_pll_half = { + .name = "pll half", + .parent = &jz_clk_pll, + .get_rate = jz_clk_pll_half_get_rate, +}; + +static struct main_clk jz_clk_cpu = { + .clk = { + .name = "cclk", + .parent = &jz_clk_pll, + .get_rate = jz_clk_main_get_rate, + .set_rate = jz_clk_main_set_rate, + .round_rate = jz_clk_main_round_rate, + }, + .div_offset = JZ_CLOCK_CTRL_CDIV_OFFSET, +}; + +static struct main_clk jz_clk_memory = { + .clk = { + .name = "mclk", + .parent = &jz_clk_pll, + .get_rate = jz_clk_main_get_rate, + .set_rate = jz_clk_main_set_rate, + .round_rate = jz_clk_main_round_rate, + }, + .div_offset = JZ_CLOCK_CTRL_MDIV_OFFSET, +}; + +static struct main_clk jz_clk_high_speed_peripheral = { + .clk = { + .name = "hclk", + .parent = &jz_clk_pll, + .get_rate = jz_clk_main_get_rate, + .set_rate = jz_clk_main_set_rate, + .round_rate = jz_clk_main_round_rate, + }, + .div_offset = JZ_CLOCK_CTRL_HDIV_OFFSET, +}; + + +static struct main_clk jz_clk_low_speed_peripheral = { + .clk = { + .name = "pclk", + .parent = &jz_clk_pll, + .get_rate = jz_clk_main_get_rate, + .set_rate = jz_clk_main_set_rate, + }, + .div_offset = JZ_CLOCK_CTRL_PDIV_OFFSET, +}; + +static struct clk jz_clk_ko = { + .name = "cko", + .parent = &jz_clk_memory.clk, + .enable = jz_clk_ko_enable, + .disable = jz_clk_ko_disable, +}; + +static int jz_clk_spi_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll) + jz_clk_reg_set_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI); + else if(parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_CLOCK_SPI_SRC_PLL, JZ_REG_CLOCK_SPI); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_i2s_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll_half) + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL); + else if(parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_I2S_SRC_PLL); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_udc_set_parent(struct clk *clk, struct clk *parent) +{ + if (parent == &jz_clk_pll_half) + jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL); + else if(parent == &jz_clk_ext.clk) + jz_clk_reg_clear_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_UDC_SRC_PLL); + else + return -EINVAL; + + clk->parent = parent; + + return 0; +} + +static int jz_clk_udc_set_rate(struct clk *clk, unsigned long rate) +{ + int div; + + if (clk->parent == &jz_clk_ext.clk) + return -EINVAL; + + div = clk_get_rate(clk->parent) / rate - 1; + + if (div < 0) + div = 0; + else if (div > 63) + div = 63; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_UDIV_OFFSET, + JZ_CLOCK_CTRL_UDIV_MASK); + return 0; +} + +static unsigned long jz_clk_udc_get_rate(struct clk *clk) +{ + int div; + + if (clk->parent == &jz_clk_ext.clk) + return clk_get_rate(clk->parent); + + div = (jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_UDIV_MASK); + div >>= JZ_CLOCK_CTRL_UDIV_OFFSET; + div += 1; + + return clk_get_rate(clk->parent) / div; +} + +static unsigned long jz_clk_divided_get_rate(struct clk *clk) +{ + struct divided_clk *dclk = (struct divided_clk*)clk; + int div; + + if (clk->parent == &jz_clk_ext.clk) + return clk_get_rate(clk->parent); + + div = (jz_clk_reg_read(dclk->reg) & dclk->mask) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int jz_clk_divided_set_rate(struct clk *clk, unsigned long rate) +{ + struct divided_clk *dclk = (struct divided_clk*)clk; + int div; + + if (clk->parent == &jz_clk_ext.clk) + return -EINVAL; + + div = clk_get_rate(clk->parent) / rate - 1; + + if (div < 0) + div = 0; + else if(div > dclk->mask) + div = dclk->mask; + + jz_clk_reg_write_mask(dclk->reg, div, dclk->mask); + + return 0; +} + +static unsigned long jz_clk_ldclk_round_rate(struct clk *clk, unsigned long rate) +{ + int div; + unsigned long parent_rate = jz_clk_pll_half_get_rate(NULL); + + if (rate > 150000000) + return 150000000; + + div = parent_rate / rate; + if (div < 1) + div = 1; + else if(div > 32) + div = 32; + + return parent_rate / div; +} + +static int jz_clk_ldclk_set_rate(struct clk *clk, unsigned long rate) +{ + int div; + + if (rate > 150000000) + return -EINVAL; + + div = jz_clk_pll_half_get_rate(NULL) / rate - 1; + if (div < 0) + div = 0; + else if(div > 31) + div = 31; + + jz_clk_reg_write_mask(JZ_REG_CLOCK_CTRL, div << JZ_CLOCK_CTRL_LDIV_OFFSET, + JZ_CLOCK_CTRL_LDIV_MASK); +} + +static unsigned long jz_clk_ldclk_get_rate(struct clk *clk) +{ + int div; + + div = jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_LDIV_MASK; + div >>= JZ_CLOCK_CTRL_LDIV_OFFSET; + + return jz_clk_pll_half_get_rate(NULL) / (div + 1); +} + +static struct clk jz_clk_ld = { + .name = "lcd", + .parent = &jz_clk_pll_half, + .set_rate = jz_clk_ldclk_set_rate, + .get_rate = jz_clk_ldclk_get_rate, + .round_rate = jz_clk_ldclk_round_rate, +}; + +static struct divided_clk jz_clk_lp = { + .clk = { + .name = "lcd_pclk", + .parent = &jz_clk_pll_half, + }, + .reg = JZ_REG_CLOCK_LCD, + .mask = JZ_CLOCK_LCD_DIV_MASK, +}; + +static struct clk jz_clk_cim_mclk = { + .name = "cim_mclk", + .parent = &jz_clk_high_speed_peripheral.clk, +}; + +static struct static_clk jz_clk_cim_pclk = { + .clk = { + .name = "cim_pclk", + .gate_bit = JZ_CLOCK_GATE_CIM, + .get_rate = jz_clk_static_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + }, +}; + +static struct divided_clk jz_clk_i2s = { + .clk = { + .name = "i2s", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_AIC, + .set_parent = jz_clk_i2s_set_parent, + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + }, + .reg = JZ_REG_CLOCK_I2S, + .mask = JZ_CLOCK_I2S_DIV_MASK, +}; + +static struct divided_clk jz_clk_mmc = { + .clk = { + .name = "mmc", + .parent = &jz_clk_pll_half, + .gate_bit = JZ_CLOCK_GATE_MMC, + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + }, + .reg = JZ_REG_CLOCK_MMC, + .mask = JZ_CLOCK_MMC_DIV_MASK, +}; + +static struct divided_clk jz_clk_uhc = { + .clk = { + .name = "uhc", + .parent = &jz_clk_pll_half, + .gate_bit = JZ_CLOCK_GATE_UHC, + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + }, + .reg = JZ_REG_CLOCK_UHC, + .mask = JZ_CLOCK_UHC_DIV_MASK, +}; + +static struct clk jz_clk_udc = { + .name = "udc", + .parent = &jz_clk_ext.clk, + .set_parent = jz_clk_udc_set_parent, + .set_rate = jz_clk_udc_set_rate, + .get_rate = jz_clk_udc_get_rate, +}; + +static struct divided_clk jz_clk_spi = { + .clk = { + .name = "spi", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_SPI, + .set_rate = jz_clk_divided_set_rate, + .get_rate = jz_clk_divided_get_rate, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + .set_parent = jz_clk_spi_set_parent, + }, + .reg = JZ_REG_CLOCK_SPI, + .mask = JZ_CLOCK_SPI_DIV_MASK, +}; + +static struct clk jz_clk_uart0 = { + .name = "uart0", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_UART0, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct clk jz_clk_uart1 = { + .name = "uart1", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_UART1, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct clk jz_clk_dma = { + .name = "dma", + .parent = &jz_clk_high_speed_peripheral.clk, + .gate_bit = JZ_CLOCK_GATE_UART0, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct clk jz_clk_ipu = { + .name = "ipu", + .parent = &jz_clk_high_speed_peripheral.clk, + .gate_bit = JZ_CLOCK_GATE_IPU, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct clk jz_clk_adc = { + .name = "adc", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_ADC, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct clk jz_clk_i2c = { + .name = "i2c", + .parent = &jz_clk_ext.clk, + .gate_bit = JZ_CLOCK_GATE_I2C, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, +}; + +static struct static_clk jz_clk_rtc = { + .clk = { + .name = "rtc", + .gate_bit = JZ_CLOCK_GATE_RTC, + .enable = jz_clk_enable_gating, + .disable = jz_clk_disable_gating, + }, + .rate = 32768, +}; + +int clk_enable(struct clk *clk) +{ + if (!clk->enable) + return -EINVAL; + + return clk->enable(clk); +} +EXPORT_SYMBOL_GPL(clk_enable); + +void clk_disable(struct clk *clk) +{ + if (clk->disable) + clk->disable(clk); +} +EXPORT_SYMBOL_GPL(clk_disable); + +unsigned long clk_get_rate(struct clk *clk) +{ + if (clk->get_rate) + return clk->get_rate(clk); + if (clk->parent) + return clk_get_rate(clk->parent); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(clk_get_rate); + +int clk_set_rate(struct clk *clk, unsigned long rate) +{ + if (!clk->set_rate) + return -EINVAL; + return clk->set_rate(clk, rate); +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +long clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk->round_rate) + return clk->round_rate(clk, rate); + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(clk_round_rate); + +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret; + + if (!clk->set_parent) + return -EINVAL; + + clk->disable(clk); + ret = clk->set_parent(clk, parent); + clk->enable(clk); + + return ret; +} +EXPORT_SYMBOL_GPL(clk_set_parent); + + +struct clk *clk_get(struct device *dev, const char *name) +{ + struct clk *clk; + + list_for_each_entry(clk, &jz_clocks, list) { + if (strcmp(clk->name, name)) + return clk; + } + return ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL_GPL(clk_get); + +void clk_put(struct clk *clk) +{ +} +EXPORT_SYMBOL_GPL(clk_put); + +inline static void clk_add(struct clk *clk) +{ + list_add_tail(&clk->list, &jz_clocks); +} + +static void clk_register_clks(void) +{ + clk_add(&jz_clk_ext.clk); + clk_add(&jz_clk_pll); + clk_add(&jz_clk_pll_half); + clk_add(&jz_clk_cpu.clk); + clk_add(&jz_clk_high_speed_peripheral.clk); + clk_add(&jz_clk_low_speed_peripheral.clk); + clk_add(&jz_clk_ko); + clk_add(&jz_clk_ld); + clk_add(&jz_clk_lp.clk); + clk_add(&jz_clk_cim_mclk); + clk_add(&jz_clk_cim_pclk.clk); + clk_add(&jz_clk_i2s.clk); + clk_add(&jz_clk_mmc.clk); + clk_add(&jz_clk_uhc.clk); + clk_add(&jz_clk_udc); + clk_add(&jz_clk_uart0); + clk_add(&jz_clk_uart1); + clk_add(&jz_clk_dma); + clk_add(&jz_clk_ipu); + clk_add(&jz_clk_adc); + clk_add(&jz_clk_i2c); + clk_add(&jz_clk_rtc.clk); +} + +int jz_init_clocks(unsigned long ext_rate) +{ + uint32_t val; + + jz_clock_base = ioremap(0x10000000, 0x100); + if (!jz_clock_base) + return -EBUSY; + + jz_clk_ext.rate = ext_rate; + + val = jz_clk_reg_read(JZ_REG_CLOCK_SPI); + + if (val & JZ_CLOCK_SPI_SRC_PLL) + jz_clk_spi.clk.parent = &jz_clk_pll_half; + + val = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); + + if (val & JZ_CLOCK_CTRL_I2S_SRC_PLL) + jz_clk_i2s.clk.parent = &jz_clk_pll_half; + + if (val & JZ_CLOCK_CTRL_UDC_SRC_PLL) + jz_clk_udc.parent = &jz_clk_pll_half; + + clk_register_clks(); + + return 0; +} +EXPORT_SYMBOL_GPL(jz_init_clocks); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/cpufreq.c linux-2.6.31/arch/mips/jz4740/cpufreq.c --- linux-2.6.31-vanilla/arch/mips/jz4740/cpufreq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/cpufreq.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,602 @@ +/* + * linux/arch/mips/jz4740/cpufreq.c + * + * cpufreq driver for JZ4740 + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include + +#include + +#include +#include + +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, \ + "cpufreq-jz4740", msg) + +#undef CHANGE_PLL + +#define PLL_UNCHANGED 0 +#define PLL_GOES_UP 1 +#define PLL_GOES_DOWN 2 + +#define PLL_WAIT_500NS (500*(__cpm_get_cclk()/1000000000)) + +/* Saved the boot-time parameters */ +static struct { + /* SDRAM parameters */ + unsigned int mclk; /* memory clock, KHz */ + unsigned int tras; /* RAS pulse width, cycles of mclk */ + unsigned int rcd; /* RAS to CAS Delay, cycles of mclk */ + unsigned int tpc; /* RAS Precharge time, cycles of mclk */ + unsigned int trwl; /* Write Precharge Time, cycles of mclk */ + unsigned int trc; /* RAS Cycle Time, cycles of mclk */ + unsigned int rtcor; /* Refresh Time Constant */ + unsigned int sdram_initialized; + + /* LCD parameters */ + unsigned int lcd_clk; /* LCD clock, Hz */ + unsigned int lcdpix_clk; /* LCD Pixel clock, Hz */ + unsigned int lcd_clks_initialized; +} boot_config; + +struct jz4740_freq_percpu_info { + struct cpufreq_frequency_table table[7]; +}; + +static struct jz4740_freq_percpu_info jz4740_freq_table; + +/* + * This contains the registers value for an operating point. + * If only part of a register needs to change then there is + * a mask value for that register. + * When going to a new operating point the current register + * value is ANDed with the ~mask and ORed with the new value. + */ +struct dpm_regs { + u32 cpccr; /* Clock Freq Control Register */ + u32 cpccr_mask; /* Clock Freq Control Register mask */ + u32 cppcr; /* PLL1 Control Register */ + u32 cppcr_mask; /* PLL1 Control Register mask */ + u32 pll_up_flag; /* New PLL freq is higher than current or not */ +}; + +extern jz_clocks_t jz_clocks; + +static void jz_update_clocks(void) +{ + /* Next clocks must be updated if we have changed + * the PLL or divisors. + */ + jz_clocks.cclk = __cpm_get_cclk(); + jz_clocks.hclk = __cpm_get_hclk(); + jz_clocks.mclk = __cpm_get_mclk(); + jz_clocks.pclk = __cpm_get_pclk(); + jz_clocks.lcdclk = __cpm_get_lcdclk(); + jz_clocks.pixclk = __cpm_get_pixclk(); + jz_clocks.i2sclk = __cpm_get_i2sclk(); + jz_clocks.usbclk = __cpm_get_usbclk(); + jz_clocks.mscclk = __cpm_get_mscclk(); +} + +static void +jz_init_boot_config(void) +{ + if (!boot_config.lcd_clks_initialized) { + /* the first time to scale pll */ + boot_config.lcd_clk = __cpm_get_lcdclk(); + boot_config.lcdpix_clk = __cpm_get_pixclk(); + boot_config.lcd_clks_initialized = 1; + } + + if (!boot_config.sdram_initialized) { + /* the first time to scale frequencies */ + unsigned int dmcr, rtcor; + unsigned int tras, rcd, tpc, trwl, trc; + + dmcr = REG_EMC_DMCR; + rtcor = REG_EMC_RTCOR; + + tras = (dmcr >> 13) & 0x7; + rcd = (dmcr >> 11) & 0x3; + tpc = (dmcr >> 8) & 0x7; + trwl = (dmcr >> 5) & 0x3; + trc = (dmcr >> 2) & 0x7; + + boot_config.mclk = __cpm_get_mclk() / 1000; + boot_config.tras = tras + 4; + boot_config.rcd = rcd + 1; + boot_config.tpc = tpc + 1; + boot_config.trwl = trwl + 1; + boot_config.trc = trc * 2 + 1; + boot_config.rtcor = rtcor; + + boot_config.sdram_initialized = 1; + } +} + +static void jz_update_dram_rtcor(unsigned int new_mclk) +{ + unsigned int rtcor; + + new_mclk /= 1000; + rtcor = boot_config.rtcor * new_mclk / boot_config.mclk; + rtcor--; + + if (rtcor < 1) rtcor = 1; + if (rtcor > 255) rtcor = 255; + + REG_EMC_RTCOR = rtcor; + REG_EMC_RTCNT = rtcor; +} + +static void jz_update_dram_dmcr(unsigned int new_mclk) +{ + unsigned int dmcr; + unsigned int tras, rcd, tpc, trwl, trc; + unsigned int valid_time, new_time; /* ns */ + + new_mclk /= 1000; + tras = boot_config.tras * new_mclk / boot_config.mclk; + rcd = boot_config.rcd * new_mclk / boot_config.mclk; + tpc = boot_config.tpc * new_mclk / boot_config.mclk; + trwl = boot_config.trwl * new_mclk / boot_config.mclk; + trc = boot_config.trc * new_mclk / boot_config.mclk; + + /* Validation checking */ + valid_time = (boot_config.tras * 1000000) / boot_config.mclk; + new_time = (tras * 1000000) / new_mclk; + if (new_time < valid_time) tras += 1; + + valid_time = (boot_config.rcd * 1000000) / boot_config.mclk; + new_time = (rcd * 1000000) / new_mclk; + if (new_time < valid_time) rcd += 1; + + valid_time = (boot_config.tpc * 1000000) / boot_config.mclk; + new_time = (tpc * 1000000) / new_mclk; + if (new_time < valid_time) tpc += 1; + + valid_time = (boot_config.trwl * 1000000) / boot_config.mclk; + new_time = (trwl * 1000000) / new_mclk; + if (new_time < valid_time) trwl += 1; + + valid_time = (boot_config.trc * 1000000) / boot_config.mclk; + new_time = (trc * 1000000) / new_mclk; + if (new_time < valid_time) trc += 2; + + tras = (tras < 4) ? 4: tras; + tras = (tras > 11) ? 11: tras; + tras -= 4; + + rcd = (rcd < 1) ? 1: rcd; + rcd = (rcd > 4) ? 4: rcd; + rcd -= 1; + + tpc = (tpc < 1) ? 1: tpc; + tpc = (tpc > 8) ? 8: tpc; + tpc -= 1; + + trwl = (trwl < 1) ? 1: trwl; + trwl = (trwl > 4) ? 4: trwl; + trwl -= 1; + + trc = (trc < 1) ? 1: trc; + trc = (trc > 15) ? 15: trc; + trc /= 2; + + dmcr = REG_EMC_DMCR; + + dmcr &= ~(EMC_DMCR_TRAS_MASK | EMC_DMCR_RCD_MASK | EMC_DMCR_TPC_MASK | EMC_DMCR_TRWL_MASK | EMC_DMCR_TRC_MASK); + dmcr |= ((tras << EMC_DMCR_TRAS_BIT) | (rcd << EMC_DMCR_RCD_BIT) | (tpc << EMC_DMCR_TPC_BIT) | (trwl << EMC_DMCR_TRWL_BIT) | (trc << EMC_DMCR_TRC_BIT)); + + REG_EMC_DMCR = dmcr; +} + +static void jz_update_dram_prev(unsigned int cur_mclk, unsigned int new_mclk) +{ + /* No risk, no fun: run with interrupts on! */ + if (new_mclk > cur_mclk) { + /* We're going FASTER, so first update TRAS, RCD, TPC, TRWL + * and TRC of DMCR before changing the frequency. + */ + jz_update_dram_dmcr(new_mclk); + } else { + /* We're going SLOWER: first update RTCOR value + * before changing the frequency. + */ + jz_update_dram_rtcor(new_mclk); + } +} + +static void jz_update_dram_post(unsigned int cur_mclk, unsigned int new_mclk) +{ + /* No risk, no fun: run with interrupts on! */ + if (new_mclk > cur_mclk) { + /* We're going FASTER, so update RTCOR + * after changing the frequency + */ + jz_update_dram_rtcor(new_mclk); + } else { + /* We're going SLOWER: so update TRAS, RCD, TPC, TRWL + * and TRC of DMCR after changing the frequency. + */ + jz_update_dram_dmcr(new_mclk); + } +} + +static void jz_scale_divisors(struct dpm_regs *regs) +{ + unsigned int cpccr; + unsigned int cur_mclk, new_mclk; + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + unsigned int tmp = 0, wait = PLL_WAIT_500NS; + + cpccr = REG_CPM_CPCCR; + cpccr &= ~((unsigned long)regs->cpccr_mask); + cpccr |= regs->cpccr; + cpccr |= CPM_CPCCR_CE; /* update immediately */ + + cur_mclk = __cpm_get_mclk(); + new_mclk = __cpm_get_pllout() / div[(cpccr & CPM_CPCCR_MDIV_MASK) >> CPM_CPCCR_MDIV_BIT]; + + /* Update some DRAM parameters before changing frequency */ + jz_update_dram_prev(cur_mclk, new_mclk); + + /* update register to change the clocks. + * align this code to a cache line. + */ + __asm__ __volatile__( + ".set noreorder\n\t" + ".align 5\n" + "sw %1,0(%0)\n\t" + "li %3,0\n\t" + "1:\n\t" + "bne %3,%2,1b\n\t" + "addi %3, 1\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + ".set reorder\n\t" + : + : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); + + /* Update some other DRAM parameters after changing frequency */ + jz_update_dram_post(cur_mclk, new_mclk); +} + +#ifdef CHANGE_PLL +/* Maintain the LCD clock and pixel clock */ +static void jz_scale_lcd_divisors(struct dpm_regs *regs) +{ + unsigned int new_pll, new_lcd_div, new_lcdpix_div; + unsigned int cpccr; + unsigned int tmp = 0, wait = PLL_WAIT_500NS; + + if (!boot_config.lcd_clks_initialized) return; + + new_pll = __cpm_get_pllout(); + new_lcd_div = new_pll / boot_config.lcd_clk; + new_lcdpix_div = new_pll / boot_config.lcdpix_clk; + + if (new_lcd_div < 1) + new_lcd_div = 1; + if (new_lcd_div > 16) + new_lcd_div = 16; + + if (new_lcdpix_div < 1) + new_lcdpix_div = 1; + if (new_lcdpix_div > 512) + new_lcdpix_div = 512; + +// REG_CPM_CPCCR2 = new_lcdpix_div - 1; + + cpccr = REG_CPM_CPCCR; + cpccr &= ~CPM_CPCCR_LDIV_MASK; + cpccr |= ((new_lcd_div - 1) << CPM_CPCCR_LDIV_BIT); + cpccr |= CPM_CPCCR_CE; /* update immediately */ + + /* update register to change the clocks. + * align this code to a cache line. + */ + __asm__ __volatile__( + ".set noreorder\n\t" + ".align 5\n" + "sw %1,0(%0)\n\t" + "li %3,0\n\t" + "1:\n\t" + "bne %3,%2,1b\n\t" + "addi %3, 1\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + ".set reorder\n\t" + : + : "r" (CPM_CPCCR), "r" (cpccr), "r" (wait), "r" (tmp)); +} + +static void jz_scale_pll(struct dpm_regs *regs) +{ + unsigned int cppcr; + unsigned int cur_mclk, new_mclk, new_pll; + int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + int od[] = {1, 2, 2, 4}; + + cppcr = REG_CPM_CPPCR; + cppcr &= ~(regs->cppcr_mask | CPM_CPPCR_PLLS | CPM_CPPCR_PLLEN | CPM_CPPCR_PLLST_MASK); + regs->cppcr &= ~CPM_CPPCR_PLLEN; + cppcr |= (regs->cppcr | 0xff); + + /* Update some DRAM parameters before changing frequency */ + new_pll = JZ_EXTAL * ((cppcr>>23)+2) / ((((cppcr>>18)&0x1f)+2) * od[(cppcr>>16)&0x03]); + cur_mclk = __cpm_get_mclk(); + new_mclk = new_pll / div[(REG_CPM_CPCCR>>CPM_CPCCR_MDIV_BIT) & 0xf]; + + /* + * Update some SDRAM parameters + */ + jz_update_dram_prev(cur_mclk, new_mclk); + + /* + * Update PLL, align code to cache line. + */ + cppcr |= CPM_CPPCR_PLLEN; + __asm__ __volatile__( + ".set noreorder\n\t" + ".align 5\n" + "sw %1,0(%0)\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + "nop\n\t" + ".set reorder\n\t" + : + : "r" (CPM_CPPCR), "r" (cppcr)); + + /* Update some other DRAM parameters after changing frequency */ + jz_update_dram_post(cur_mclk, new_mclk); +} +#endif + +static void jz4740_transition(struct dpm_regs *regs) +{ + /* + * Get and save some boot-time conditions. + */ + jz_init_boot_config(); + +#ifdef CHANGE_PLL + /* + * Disable LCD before scaling pll. + * LCD and LCD pixel clocks should not be changed even if the PLL + * output frequency has been changed. + */ + REG_LCD_CTRL &= ~LCD_CTRL_ENA; + + /* + * Stop module clocks before scaling PLL + */ + __cpm_stop_eth(); + __cpm_stop_aic(1); + __cpm_stop_aic(2); +#endif + + /* ... add more as necessary */ + + if (regs->pll_up_flag == PLL_GOES_UP) { + /* the pll frequency is going up, so change dividors first */ + jz_scale_divisors(regs); +#ifdef CHANGE_PLL + jz_scale_pll(regs); +#endif + } + else if (regs->pll_up_flag == PLL_GOES_DOWN) { + /* the pll frequency is going down, so change pll first */ +#ifdef CHANGE_PLL + jz_scale_pll(regs); +#endif + jz_scale_divisors(regs); + } + else { + /* the pll frequency is unchanged, so change divisors only */ + jz_scale_divisors(regs); + } + +#ifdef CHANGE_PLL + /* + * Restart module clocks before scaling PLL + */ + __cpm_start_eth(); + __cpm_start_aic(1); + __cpm_start_aic(2); + + /* ... add more as necessary */ + + /* Scale the LCD divisors after scaling pll */ + if (regs->pll_up_flag != PLL_UNCHANGED) { + jz_scale_lcd_divisors(regs); + } + + /* Enable LCD controller */ + REG_LCD_CTRL &= ~LCD_CTRL_DIS; + REG_LCD_CTRL |= LCD_CTRL_ENA; +#endif + + /* Update system clocks */ + jz_update_clocks(); +} + +extern unsigned int idle_times; +static unsigned int jz4740_freq_get(unsigned int cpu) +{ + return (__cpm_get_cclk() / 1000); +} + +static unsigned int index_to_divisor(unsigned int index, struct dpm_regs *regs) +{ + int n2FR[33] = { + 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, + 9 + }; + int div[4] = {1, 2, 2, 2}; /* divisors of I:S:P:M */ + unsigned int div_of_cclk, new_freq, i; + + regs->pll_up_flag = PLL_UNCHANGED; + regs->cpccr_mask = CPM_CPCCR_CDIV_MASK | CPM_CPCCR_HDIV_MASK | CPM_CPCCR_PDIV_MASK | CPM_CPCCR_MDIV_MASK; + + new_freq = jz4740_freq_table.table[index].frequency; + + do { + div_of_cclk = __cpm_get_pllout() / (1000 * new_freq); + } while (div_of_cclk==0); + + if(div_of_cclk == 1 || div_of_cclk == 2 || div_of_cclk == 4) { + for(i = 1; i<4; i++) { + div[i] = 3; + } + } else { + for(i = 1; i<4; i++) { + div[i] = 2; + } + } + + for(i = 0; i<4; i++) { + div[i] *= div_of_cclk; + } + + dprintk("divisors of I:S:P:M = %d:%d:%d:%d\n", div[0], div[1], div[2], div[3]); + + regs->cpccr = + (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) | + (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) | + (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) | + (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT); + + return div_of_cclk; +} + +static void jz4740_set_cpu_divider_index(unsigned int cpu, unsigned int index) +{ + unsigned long divisor, old_divisor; + struct cpufreq_freqs freqs; + struct dpm_regs regs; + + old_divisor = __cpm_get_pllout() / __cpm_get_cclk(); + divisor = index_to_divisor(index, ®s); + + freqs.old = __cpm_get_cclk() / 1000; + freqs.new = __cpm_get_pllout() / (1000 * divisor); + freqs.cpu = cpu; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + if (old_divisor != divisor) + jz4740_transition(®s); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +} + +static int jz4740_freq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int new_index = 0; + + if (cpufreq_frequency_table_target(policy, + &jz4740_freq_table.table[0], + target_freq, relation, &new_index)) + return -EINVAL; + + jz4740_set_cpu_divider_index(policy->cpu, new_index); + + dprintk("new frequency is %d KHz (REG_CPM_CPCCR:0x%x)\n", __cpm_get_cclk() / 1000, REG_CPM_CPCCR); + + return 0; +} + +static int jz4740_freq_verify(struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, + &jz4740_freq_table.table[0]); +} + +static int __init jz4740_cpufreq_driver_init(struct cpufreq_policy *policy) +{ + + struct cpufreq_frequency_table *table = &jz4740_freq_table.table[0]; + unsigned int MAX_FREQ; + + dprintk(KERN_INFO "Jz4740 cpufreq driver\n"); + + if (policy->cpu != 0) + return -EINVAL; + + policy->cur = MAX_FREQ = __cpm_get_cclk() / 1000; /* in kHz. Current and max frequency is determined by u-boot */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + + policy->cpuinfo.min_freq = MAX_FREQ/8; + policy->cpuinfo.max_freq = MAX_FREQ; + policy->cpuinfo.transition_latency = 100000; /* in 10^(-9) s = nanoseconds */ + + table[0].index = 0; + table[0].frequency = MAX_FREQ/8; + table[1].index = 1; + table[1].frequency = MAX_FREQ/6; + table[2].index = 2; + table[2].frequency = MAX_FREQ/4; + table[3].index = 3; + table[3].frequency = MAX_FREQ/3; + table[4].index = 4; + table[4].frequency = MAX_FREQ/2; + table[5].index = 5; + table[5].frequency = MAX_FREQ; + table[6].index = 6; + table[6].frequency = CPUFREQ_TABLE_END; + +#ifdef CONFIG_CPU_FREQ_STAT_DETAILS + cpufreq_frequency_table_get_attr(table, policy->cpu); /* for showing /sys/devices/system/cpu/cpuX/cpufreq/stats/ */ +#endif + + return cpufreq_frequency_table_cpuinfo(policy, table); +} + +static struct cpufreq_driver cpufreq_jz4740_driver = { +// .flags = CPUFREQ_STICKY, + .init = jz4740_cpufreq_driver_init, + .verify = jz4740_freq_verify, + .target = jz4740_freq_target, + .get = jz4740_freq_get, + .name = "jz4740", +}; + +static int __init jz4740_cpufreq_init(void) +{ + return cpufreq_register_driver(&cpufreq_jz4740_driver); +} + +static void __exit jz4740_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&cpufreq_jz4740_driver); +} + +module_init(jz4740_cpufreq_init); +module_exit(jz4740_cpufreq_exit); + +MODULE_AUTHOR("Regen "); +MODULE_DESCRIPTION("cpufreq driver for Jz4740"); +MODULE_LICENSE("GPL"); + diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/dma.c linux-2.6.31/arch/mips/jz4740/dma.c --- linux-2.6.31-vanilla/arch/mips/jz4740/dma.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/dma.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,922 @@ +/* + * linux/arch/mips/jz4740/dma.c + * + * Support functions for the JZ4740 internal DMA channels. + * No-descriptor transfer only. + * Descriptor transfer should also call jz_request_dma() to get a free + * channel and call jz_free_dma() to free the channel. And driver should + * build the DMA descriptor and setup the DMA channel by itself. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define JZ_REG_DMA_SRC_ADDR(x) ((x) * 0x20 + 0x00) +#define JZ_REG_DMA_DEST_ADDR(x) ((x) * 0x20 + 0x04) +#define JZ_REG_DMA_COUNT(x) ((x) * 0x20 + 0x08) +#define JZ_REG_DMA_TYPE(x) ((x) * 0x20 + 0x0c) +#define JZ_REG_DMA_STATUS(x) ((x) * 0x20 + 0x10) +#define JZ_REG_DMA_CMD(x) ((x) * 0x20 + 0x14) +#define JZ_REG_DMA_DESC_ADDR(x) ((x) * 0x20 + 0x18) +#define JZ_REG_DMA_CTRL 0x300 +#define JZ_REG_DMA_IRQ 0x304 +#define JZ_REG_DMA_DOORBELL 0x308 +#define JZ_REG_DMA_DOORBELL_SET 0x30C + +#define JZ_DMA_STATUS_NO_DESC BIT(31) +#define JZ_DMA_STATUS_CDOA_MASK (0xff << 16) +#define JZ_DMA_STATUS_INV_DESC BIT(6) +#define JZ_DMA_STATUS_ADDR_ERROR BIT(4) +#define JZ_DMA_STATUS_TERMINATE_TRANSFER BIT(3) +#define JZ_DMA_STATUS_HALT BIT(2) +#define JZ_DMA_STATUS_CT BIT(1) +#define JZ_DMA_STATUS_ENABLE BIT(0) + +#define JZ_DMA_CMD_SAI BIT(23) +#define JZ_DMA_CMD_DAI BIT(22) +#define JZ_DMA_CMD_RDIL_MASK (0xf << 16) +#define JZ_DMA_CMD_SRC_WIDTH_MASK (0x3 << 14) +#define JZ_DMA_CMD_DEST_WIDTH_MASK (0x3 << 12) +#define JZ_DMA_CMD_TRANSFER_SIZE_MASK (0x7 << 8) +#define JZ_DMA_CMD_BLOCK_MODE BIT(7) +#define JZ_DMA_CMD_VALID BIT(4) +#define JZ_DMA_CMD_VALID_MODE BIT(3) +#define JZ_DMA_CMD_VALID_IRQ_ENABLE BIT(2) +#define JZ_DMA_CMD_TRANSFER_IRQ_ENABLE BIT(1) +#define JZ_DMA_CMD_LINK BIT(0) + + +static void __iomem *jz_dma_base; +static spinlock_t jz_dma_lock; + +static inline uint32_t jz_dma_read(size_t reg) +{ + return readl(jz_dma_base + reg); +} + +static inline void jz_dma_write(size_t reg, uint32_t val) +{ + writel(val, jz_dma_base + reg); +} + + + +/* + * A note on resource allocation: + * + * All drivers needing DMA channels, should allocate and release them + * through the public routines `jz_request_dma()' and `jz_free_dma()'. + * + * In order to avoid problems, all processes should allocate resources in + * the same sequence and release them in the reverse order. + * + * So, when allocating DMAs and IRQs, first allocate the DMA, then the IRQ. + * When releasing them, first release the IRQ, then release the DMA. The + * main reason for this order is that, if you are requesting the DMA buffer + * done interrupt, you won't know the irq number until the DMA channel is + * returned from jz_request_dma(). + */ + +struct jz_dma_chan jz_dma_table[MAX_DMA_NUM] = { + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, + {dev_id:-1,}, +}; + +// Device FIFO addresses and default DMA modes +static const struct { + unsigned int fifo_addr; + unsigned int dma_mode; + unsigned int dma_source; +} dma_dev_table[DMA_ID_MAX] = { + {CPHYSADDR(UART0_TDR), DMA_8BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_UART0OUT}, + {CPHYSADDR(UART0_RDR), DMA_8BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_UART0IN}, + {CPHYSADDR(SSI_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_SSIOUT}, + {CPHYSADDR(SSI_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_SSIIN}, + {CPHYSADDR(AIC_DR), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_AICOUT}, + {CPHYSADDR(AIC_DR), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_AICIN}, + {CPHYSADDR(MSC_TXFIFO), DMA_32BIT_TX_CMD | DMA_MODE_WRITE, DMAC_DRSR_RS_MSCOUT}, + {CPHYSADDR(MSC_RXFIFO), DMA_32BIT_RX_CMD | DMA_MODE_READ, DMAC_DRSR_RS_MSCIN}, + {0, DMA_AUTOINIT, DMAC_DRSR_RS_TCU}, + {0, DMA_AUTOINIT, DMAC_DRSR_RS_AUTO}, + {}, +}; + + +int jz_dma_read_proc(char *buf, char **start, off_t fpos, + int length, int *eof, void *data) +{ + int i, len = 0; + struct jz_dma_chan *chan; + + for (i = 0; i < MAX_DMA_NUM; i++) { + if ((chan = get_dma_chan(i)) != NULL) { + len += sprintf(buf + len, "%2d: %s\n", + i, chan->dev_str); + } + } + + if (fpos >= len) { + *start = buf; + *eof = 1; + return 0; + } + *start = buf + fpos; + if ((len -= fpos) > length) + return length; + *eof = 1; + return len; +} + + +void dump_jz_dma_channel(unsigned int dmanr) +{ + struct jz_dma_chan *chan; + + if (dmanr > MAX_DMA_NUM) + return; + chan = &jz_dma_table[dmanr]; + + printk("DMA%d Registers:\n", dmanr); + printk(" DMACR = 0x%08x\n", REG_DMAC_DMACR); + printk(" DSAR = 0x%08x\n", REG_DMAC_DSAR(dmanr)); + printk(" DTAR = 0x%08x\n", REG_DMAC_DTAR(dmanr)); + printk(" DTCR = 0x%08x\n", REG_DMAC_DTCR(dmanr)); + printk(" DRSR = 0x%08x\n", REG_DMAC_DRSR(dmanr)); + printk(" DCCSR = 0x%08x\n", REG_DMAC_DCCSR(dmanr)); + printk(" DCMD = 0x%08x\n", REG_DMAC_DCMD(dmanr)); + printk(" DDA = 0x%08x\n", REG_DMAC_DDA(dmanr)); + printk(" DMADBR = 0x%08x\n", REG_DMAC_DMADBR); +} + + +/** + * jz_request_dma - dynamically allcate an idle DMA channel to return + * @dev_id: the specified dma device id or DMA_ID_RAW_SET + * @dev_str: the specified dma device string name + * @irqhandler: the irq handler, or NULL + * @irqflags: the irq handler flags + * @irq_dev_id: the irq handler device id for shared irq + * + * Finds a free channel, and binds the requested device to it. + * Returns the allocated channel number, or negative on error. + * Requests the DMA done IRQ if irqhandler != NULL. + * +*/ +/*int jz_request_dma(int dev_id, const char *dev_str, + void (*irqhandler)(int, void *, struct pt_regs *), + unsigned long irqflags, + void *irq_dev_id) +*/ + +int jz_request_dma(int dev_id, const char *dev_str, + irqreturn_t (*irqhandler)(int, void *), + unsigned long irqflags, + void *irq_dev_id) +{ + struct jz_dma_chan *chan; + int i, ret; + + if (dev_id < 0 || dev_id >= DMA_ID_MAX) + return -EINVAL; + + for (i = 0; i < MAX_DMA_NUM; i++) { + if (jz_dma_table[i].dev_id < 0) + break; + } + if (i == MAX_DMA_NUM) /* no free channel */ + return -ENODEV; + + /* we got a free channel */ + chan = &jz_dma_table[i]; + + if (irqhandler) { + chan->irq = JZ_IRQ_DMA(i); // allocate irq number + chan->irq_dev = irq_dev_id; + if ((ret = request_irq(chan->irq, irqhandler, irqflags, + dev_str, chan->irq_dev))) { + chan->irq = -1; + chan->irq_dev = NULL; + return ret; + } + } else { + chan->irq = -1; + chan->irq_dev = NULL; + } + + // fill it in + chan->io = i; + chan->dev_id = dev_id; + chan->dev_str = dev_str; + chan->fifo_addr = dma_dev_table[dev_id].fifo_addr; + chan->mode = dma_dev_table[dev_id].dma_mode; + chan->source = dma_dev_table[dev_id].dma_source; + + return i; +} + +void jz_free_dma(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) { + printk("Trying to free DMA%d\n", dmanr); + return; + } + + disable_dma(dmanr); + if (chan->irq) + free_irq(chan->irq, chan->irq_dev); + + chan->irq = -1; + chan->irq_dev = NULL; + chan->dev_id = -1; +} + +void jz_set_dma_dest_width(int dmanr, int nbit) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + chan->mode &= ~DMAC_DCMD_DWDH_MASK; + switch (nbit) { + case 8: + chan->mode |= DMAC_DCMD_DWDH_8; + break; + case 16: + chan->mode |= DMAC_DCMD_DWDH_16; + break; + case 32: + chan->mode |= DMAC_DCMD_DWDH_32; + break; + } +} + +void jz_set_dma_src_width(int dmanr, int nbit) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + chan->mode &= ~DMAC_DCMD_SWDH_MASK; + switch (nbit) { + case 8: + chan->mode |= DMAC_DCMD_SWDH_8; + break; + case 16: + chan->mode |= DMAC_DCMD_SWDH_16; + break; + case 32: + chan->mode |= DMAC_DCMD_SWDH_32; + break; + } +} + +void jz_set_dma_block_size(int dmanr, int nbyte) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + chan->mode &= ~DMAC_DCMD_DS_MASK; + switch (nbyte) { + case 1: + chan->mode |= DMAC_DCMD_DS_8BIT; + break; + case 2: + chan->mode |= DMAC_DCMD_DS_16BIT; + break; + case 4: + chan->mode |= DMAC_DCMD_DS_32BIT; + break; + case 16: + chan->mode |= DMAC_DCMD_DS_16BYTE; + break; + case 32: + chan->mode |= DMAC_DCMD_DS_32BYTE; + break; + } +} + +unsigned int jz_get_dma_command(int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + return chan->mode; +} + +/** + * jz_set_dma_mode - do the raw settings for the specified DMA channel + * @dmanr: the specified DMA channel + * @mode: dma operate mode, DMA_MODE_READ or DMA_MODE_WRITE + * @dma_mode: dma raw mode + * @dma_source: dma raw request source + * @fifo_addr: dma raw device fifo address + * + * Ensure call jz_request_dma(DMA_ID_RAW_SET, ...) first, then call + * jz_set_dma_mode() rather than set_dma_mode() if you work with + * and external request dma device. + * + * NOTE: Don not dynamically allocate dma channel if one external request + * dma device will occupy this channel. +*/ +int jz_set_dma_mode(unsigned int dmanr, unsigned int mode, + unsigned int dma_mode, unsigned int dma_source, + unsigned int fifo_addr) +{ + int dev_id, i; + struct jz_dma_chan *chan; + + if (dmanr > MAX_DMA_NUM) + return -ENODEV; + + for (i = 0; i < MAX_DMA_NUM; i++) { + if (jz_dma_table[i].dev_id < 0) + break; + } + if (i == MAX_DMA_NUM) + return -ENODEV; + + chan = &jz_dma_table[dmanr]; + dev_id = chan->dev_id; + if (dev_id > 0) { + printk(KERN_DEBUG "%s sets the allocated DMA channel %d!\n", + __FUNCTION__, dmanr); + return -ENODEV; + } + + /* clone it from the dynamically allocated. */ + if (i != dmanr) { + chan->irq = jz_dma_table[i].irq; + chan->irq_dev = jz_dma_table[i].irq_dev; + chan->dev_str = jz_dma_table[i].dev_str; + jz_dma_table[i].irq = 0; + jz_dma_table[i].irq_dev = NULL; + jz_dma_table[i].dev_id = -1; + } + chan->dev_id = DMA_ID_RAW_SET; + chan->io = dmanr; + chan->fifo_addr = fifo_addr; + chan->mode = dma_mode; + chan->source = dma_source; + + set_dma_mode(dmanr, dma_mode); + + return dmanr; +} + +void enable_dma(unsigned int dmanr) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + REG_DMAC_DCCSR(dmanr) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR); + REG_DMAC_DCCSR(dmanr) |= DMAC_DCCSR_NDES; /* No-descriptor transfer */ + __dmac_enable_channel(dmanr); + if (chan->irq) + __dmac_channel_enable_irq(dmanr); +} + +#define DMA_DISABLE_POLL 0x10000 + +void disable_dma(unsigned int dmanr) +{ + int i; + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + if (!__dmac_channel_enabled(dmanr)) + return; + + for (i = 0; i < DMA_DISABLE_POLL; i++) + if (__dmac_channel_transmit_end_detected(dmanr)) + break; +#if 0 + if (i == DMA_DISABLE_POLL) + printk(KERN_INFO "disable_dma: poll expired!\n"); +#endif + + __dmac_disable_channel(dmanr); + if (chan->irq) + __dmac_channel_disable_irq(dmanr); +} + +/* Note: DMA_MODE_MASK is simulated by sw */ +void set_dma_mode(unsigned int dmanr, unsigned int mode) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); + mode &= DMA_MODE_MASK; + if (mode == DMA_MODE_READ) { + chan->mode |= DMAC_DCMD_DAI; + chan->mode &= ~DMAC_DCMD_SAI; + } else if (mode == DMA_MODE_WRITE) { + chan->mode |= DMAC_DCMD_SAI; + chan->mode &= ~DMAC_DCMD_DAI; + } else { + printk(KERN_DEBUG "set_dma_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); + } + jz_dma_write(JZ_REG_DMA_CMD(chan->io), chan->mode & ~DMA_MODE_MASK); + jz_dma_write(JZ_REG_DMA_TYPE(chan->io), chan->source); +} + +void set_dma_addr(unsigned int dmanr, unsigned int phyaddr) +{ + unsigned int mode; + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + mode = chan->mode & DMA_MODE_MASK; + if (mode == DMA_MODE_READ) { + jz_dma_write(JZ_REG_DMA_SRC_ADDR(chan->io), chan->fifo_addr); + jz_dma_write(JZ_REG_DMA_DEST_ADDR(chan->io), phyaddr); + } else if (mode == DMA_MODE_WRITE) { + jz_dma_write(JZ_REG_DMA_SRC_ADDR(chan->io), phyaddr); + jz_dma_write(JZ_REG_DMA_DEST_ADDR(chan->io), chan->fifo_addr); + } else + printk(KERN_DEBUG "Driver should call set_dma_mode() ahead set_dma_addr()!\n"); +} + +void set_dma_count(unsigned int dmanr, unsigned int bytecnt) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + int dma_ds[] = {4, 1, 2, 16, 32}; + unsigned int ds; + + if (!chan) + return; + + ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; + + jz_dma_write(JZ_REG_DMA_COUNT(chan->io), bytecnt / dma_ds[ds]); +} + +unsigned int get_dma_residue(unsigned int dmanr) +{ + unsigned int count, ds; + int dma_ds[] = {4, 1, 2, 16, 32}; + struct jz_dma_chan *chan = get_dma_chan(dmanr); + if (!chan) + return 0; + + ds = (chan->mode & DMAC_DCMD_DS_MASK) >> DMAC_DCMD_DS_BIT; + count = jz_dma_read(JZ_REG_DMA_COUNT(chan->io)); + count = count * dma_ds[ds]; + + return count; +} + +void jz_set_oss_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + switch (audio_fmt) { + case AFMT_U8: + /* burst mode : 32BIT */ + break; + case AFMT_S16_LE: + /* burst mode : 16BYTE */ + if (mode == DMA_MODE_READ) { + chan->mode = DMA_AIC_32_16BYTE_RX_CMD | DMA_MODE_READ; + chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); + mode &= DMA_MODE_MASK; + chan->mode |= DMAC_DCMD_DAI; + chan->mode &= ~DMAC_DCMD_SAI; + } else if (mode == DMA_MODE_WRITE) { + chan->mode = DMA_AIC_32_16BYTE_TX_CMD | DMA_MODE_WRITE; + chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); + mode &= DMA_MODE_MASK; + chan->mode |= DMAC_DCMD_SAI; + chan->mode &= ~DMAC_DCMD_DAI; + } else + printk("oss_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); + + jz_dma_write(JZ_REG_DMA_CMD(chan->io), chan->mode & ~DMA_MODE_MASK); + jz_dma_write(JZ_REG_DMA_TYPE(chan->io), chan->source); + break; + } +} + +void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt) +{ + struct jz_dma_chan *chan = get_dma_chan(dmanr); + + if (!chan) + return; + + switch (audio_fmt) { + case 8: + /* SNDRV_PCM_FORMAT_S8 burst mode : 32BIT */ + break; + case 16: + /* SNDRV_PCM_FORMAT_S16_LE burst mode : 16BYTE */ + if (mode == DMA_MODE_READ) { + chan->mode = DMA_AIC_16BYTE_RX_CMD | DMA_MODE_READ; + chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); + mode &= DMA_MODE_MASK; + chan->mode |= DMAC_DCMD_DAI; + chan->mode &= ~DMAC_DCMD_SAI; + } else if (mode == DMA_MODE_WRITE) { + chan->mode = DMA_AIC_16BYTE_TX_CMD | DMA_MODE_WRITE; + chan->mode |= mode & ~(DMAC_DCMD_SAI | DMAC_DCMD_DAI); + mode &= DMA_MODE_MASK; + chan->mode |= DMAC_DCMD_SAI; + chan->mode &= ~DMAC_DCMD_DAI; + } else { + printk("alsa_dma_burst_mode() just supports DMA_MODE_READ or DMA_MODE_WRITE!\n"); + } + + jz_dma_write(JZ_REG_DMA_CMD(chan->io), chan->mode & ~DMA_MODE_MASK); + jz_dma_write(JZ_REG_DMA_TYPE(chan->io), chan->source); + + break; + } +} + +#undef JZ4740_DMAC_TEST_ENABLE + +#ifdef JZ4740_DMAC_TEST_ENABLE + +/* + * DMA test: external address <--> external address + */ +#define TEST_DMA_SIZE 16*1024 + +static jz_dma_desc *dma_desc; + +static int dma_chan; +static dma_addr_t dma_desc_phys_addr; +static unsigned int dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr; + +static int dma_check_result(void *src, void *dst, int size) +{ + unsigned int addr1, addr2, i, err = 0; + + addr1 = (unsigned int)src; + addr2 = (unsigned int)dst; + + for (i = 0; i < size; i += 4) { + if (*(volatile unsigned int *)addr1 != *(volatile unsigned int *)addr2) { + err++; + printk("wrong data at 0x%08x: src 0x%08x dst 0x%08x\n", addr2, *(volatile unsigned int *)addr1, *(volatile unsigned int *)addr2); + } + addr1 += 4; + addr2 += 4; + } + printk("check DMA result err=%d\n", err); + return err; +} + +static void jz4740_dma_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + printk("jz4740_dma_irq %d\n", irq); + + REG_DMAC_DCCSR(dma_chan) &= ~DMAC_DCCSR_EN; /* disable DMA */ + + if (__dmac_channel_transmit_halt_detected(dma_chan)) { + printk("DMA HALT\n"); + __dmac_channel_clear_transmit_halt(dma_chan); + } + + if (__dmac_channel_address_error_detected(dma_chan)) { + printk("DMA ADDR ERROR\n"); + __dmac_channel_clear_address_error(dma_chan); + } + + if (__dmac_channel_descriptor_invalid_detected(dma_chan)) { + printk("DMA DESC INVALID\n"); + __dmac_channel_clear_descriptor_invalid(dma_chan); + } + + if (__dmac_channel_count_terminated_detected(dma_chan)) { + printk("DMA CT\n"); + __dmac_channel_clear_count_terminated(dma_chan); + } + + if (__dmac_channel_transmit_end_detected(dma_chan)) { + printk("DMA TT\n"); + __dmac_channel_clear_transmit_end(dma_chan); + dump_jz_dma_channel(dma_chan); + dma_check_result((void *)dma_src_addr, (void *)dma_dst_addr, TEST_DMA_SIZE); + } + + /* free buffers */ + printk("free DMA buffers\n"); + free_pages(dma_src_addr, 2); + free_pages(dma_dst_addr, 2); + + if (dma_desc) + free_pages((unsigned int)dma_desc, 0); + + /* free dma */ + jz_free_dma(dma_chan); +} + +void dma_nodesc_test(void) +{ + unsigned int addr, i; + + printk("dma_nodesc_test\n"); + + /* Request DMA channel and setup irq handler */ + dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, + SA_INTERRUPT, NULL); + if (dma_chan < 0) { + printk("Setup irq failed\n"); + return; + } + + printk("Requested DMA channel = %d\n", dma_chan); + + /* Allocate DMA buffers */ + dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ + dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ + + dma_src_phys_addr = CPHYSADDR(dma_src_addr); + dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); + + printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", + dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); + + /* Prepare data for source buffer */ + addr = (unsigned int)dma_src_addr; + for (i = 0; i < TEST_DMA_SIZE; i += 4) { + *(volatile unsigned int *)addr = addr; + addr += 4; + } + dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); + + /* Init target buffer */ + memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); + dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); + + /* Init DMA module */ + printk("Starting DMA\n"); + REG_DMAC_DMACR = 0; + REG_DMAC_DCCSR(dma_chan) = 0; + REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; + REG_DMAC_DSAR(dma_chan) = dma_src_phys_addr; + REG_DMAC_DTAR(dma_chan) = dma_dst_phys_addr; + REG_DMAC_DTCR(dma_chan) = 512; + REG_DMAC_DCMD(dma_chan) = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TIE; + REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_NDES | DMAC_DCCSR_EN; + REG_DMAC_DMACR = DMAC_DMACR_DMAE; /* global DMA enable bit */ + + printk("DMA started. IMR=%08x\n", REG_INTC_IMR); +} + +void dma_desc_test(void) +{ + unsigned int next, addr, i; + static jz_dma_desc *desc; + + printk("dma_desc_test\n"); + + /* Request DMA channel and setup irq handler */ + dma_chan = jz_request_dma(DMA_ID_AUTO, "auto", jz4740_dma_irq, + SA_INTERRUPT, NULL); + if (dma_chan < 0) { + printk("Setup irq failed\n"); + return; + } + + printk("Requested DMA channel = %d\n", dma_chan); + + /* Allocate DMA buffers */ + dma_src_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ + dma_dst_addr = __get_free_pages(GFP_KERNEL, 2); /* 16KB */ + + dma_src_phys_addr = CPHYSADDR(dma_src_addr); + dma_dst_phys_addr = CPHYSADDR(dma_dst_addr); + + printk("Buffer addresses: 0x%08x 0x%08x 0x%08x 0x%08x\n", + dma_src_addr, dma_src_phys_addr, dma_dst_addr, dma_dst_phys_addr); + + /* Prepare data for source buffer */ + addr = (unsigned int)dma_src_addr; + for (i = 0; i < TEST_DMA_SIZE; i += 4) { + *(volatile unsigned int *)addr = addr; + addr += 4; + } + dma_cache_wback((unsigned long)dma_src_addr, TEST_DMA_SIZE); + + /* Init target buffer */ + memset((void *)dma_dst_addr, 0, TEST_DMA_SIZE); + dma_cache_wback((unsigned long)dma_dst_addr, TEST_DMA_SIZE); + + /* Allocate DMA descriptors */ + dma_desc = (jz_dma_desc *)__get_free_pages(GFP_KERNEL, 0); + dma_desc_phys_addr = CPHYSADDR((unsigned long)dma_desc); + + printk("DMA descriptor address: 0x%08x 0x%08x\n", (u32)dma_desc, dma_desc_phys_addr); + + /* Setup DMA descriptors */ + desc = dma_desc; + next = (dma_desc_phys_addr + (sizeof(jz_dma_desc))) >> 4; + + desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BYTE | DMAC_DCMD_TM | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; + desc->dsadr = dma_src_phys_addr; /* DMA source address */ + desc->dtadr = dma_dst_phys_addr; /* DMA target address */ + desc->ddadr = (next << 24) + 128; /* size: 128*32 bytes = 4096 bytes */ + + desc++; + next = (dma_desc_phys_addr + 2*(sizeof(jz_dma_desc))) >> 4; + + desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; + desc->dsadr = dma_src_phys_addr + 4096; /* DMA source address */ + desc->dtadr = dma_dst_phys_addr + 4096; /* DMA target address */ + desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ + + desc++; + next = (dma_desc_phys_addr + 3*(sizeof(jz_dma_desc))) >> 4; + + desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_16BYTE | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE | DMAC_DCMD_LINK; + desc->dsadr = dma_src_phys_addr + 8192; /* DMA source address */ + desc->dtadr = dma_dst_phys_addr + 8192; /* DMA target address */ + desc->ddadr = (next << 24) + 256; /* size: 256*16 bytes = 4096 bytes */ + + desc++; + next = (dma_desc_phys_addr + 4*(sizeof(jz_dma_desc))) >> 4; + + desc->dcmd = DMAC_DCMD_SAI | DMAC_DCMD_DAI | DMAC_DCMD_RDIL_IGN | DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | DMAC_DCMD_DS_32BIT | DMAC_DCMD_DES_V | DMAC_DCMD_DES_VM | DMAC_DCMD_DES_VIE | DMAC_DCMD_TIE; + desc->dsadr = dma_src_phys_addr + 12*1024; /* DMA source address */ + desc->dtadr = dma_dst_phys_addr + 12*1024; /* DMA target address */ + desc->ddadr = (next << 24) + 1024; /* size: 1024*4 bytes = 4096 bytes */ + + dma_cache_wback((unsigned long)dma_desc, 4*(sizeof(jz_dma_desc))); + + /* Setup DMA descriptor address */ + REG_DMAC_DDA(dma_chan) = dma_desc_phys_addr; + + /* Setup request source */ + REG_DMAC_DRSR(dma_chan) = DMAC_DRSR_RS_AUTO; + + /* Setup DMA channel control/status register */ + REG_DMAC_DCCSR(dma_chan) = DMAC_DCCSR_EN; /* descriptor transfer, clear status, start channel */ + + /* Enable DMA */ + REG_DMAC_DMACR = DMAC_DMACR_DMAE; + + /* DMA doorbell set -- start DMA now ... */ + REG_DMAC_DMADBSR = 1 << dma_chan; + + printk("DMA started. IMR=%08x\n", REG_INTC_IMR); +} + +#endif + +static void jz_dma_irq_demux_handler(unsigned int irq, struct irq_desc *desc) +{ + int i; + uint32_t pending; + + pending = jz_dma_read(JZ_REG_DMA_IRQ); + + for (i = 0; i < 6; ++i) { + if (pending & BIT(i)) + generic_handle_irq(JZ_IRQ_DMA(i)); + } +} + +#define IRQ_TO_DMA(irq) ((irq) - JZ_IRQ_DMA(0)) + +static void dma_irq_unmask(unsigned int irq) +{ + unsigned long flags; + uint32_t mask; + unsigned int chan; + + chan = IRQ_TO_DMA(irq); + + spin_lock_irqsave(&jz_dma_lock, flags); + + mask = jz_dma_read(JZ_REG_DMA_CMD(chan)); + mask |= JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; + jz_dma_write(JZ_REG_DMA_CMD(chan), mask); + + spin_unlock_irqrestore(&jz_dma_lock, flags); +} + +static void dma_irq_mask(unsigned int irq) +{ + unsigned long flags; + uint32_t mask; + unsigned int chan; + + chan = IRQ_TO_DMA(irq); + + spin_lock_irqsave(&jz_dma_lock, flags); + + mask = jz_dma_read(JZ_REG_DMA_CMD(chan)); + mask &= ~JZ_DMA_CMD_TRANSFER_IRQ_ENABLE; + jz_dma_write(JZ_REG_DMA_CMD(chan), mask); + + spin_unlock_irqrestore(&jz_dma_lock, flags); +} + +static void dma_irq_ack(unsigned int irq) +{ + unsigned long flags; + uint32_t pending; + + spin_lock_irqsave(&jz_dma_lock, flags); + + pending = jz_dma_read(JZ_REG_DMA_IRQ); + pending &= ~BIT(irq); + jz_dma_write(JZ_REG_DMA_IRQ, pending); + + spin_unlock_irqrestore(&jz_dma_lock, flags); +} + +static void dma_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + dma_irq_unmask(irq); + } +} + +static struct irq_chip dma_irq_type = { + .name = "DMA", + .unmask = dma_irq_unmask, + .mask = dma_irq_mask, + .ack = dma_irq_ack, + .end = dma_irq_end, +}; + +static int jz_dma_init(void) +{ + int i; + + jz_dma_base = ioremap(CPHYSADDR(DMAC_BASE), 0x400); + + if (!jz_dma_base) + return -EBUSY; + + spin_lock_init(&jz_dma_lock); + + set_irq_chained_handler(JZ_IRQ_DMAC, jz_dma_irq_demux_handler); + + for (i = 0; i < NUM_DMA; i++) { + dma_irq_mask(JZ_IRQ_DMA(i)); + set_irq_chip_and_handler(JZ_IRQ_DMA(i), &dma_irq_type, handle_level_irq); + } + + return 0; +} +arch_initcall(jz_dma_init); + +//EXPORT_SYMBOL_NOVERS(jz_dma_table); +EXPORT_SYMBOL(jz_dma_table); +EXPORT_SYMBOL(jz_request_dma); +EXPORT_SYMBOL(jz_free_dma); +EXPORT_SYMBOL(jz_set_dma_src_width); +EXPORT_SYMBOL(jz_set_dma_dest_width); +EXPORT_SYMBOL(jz_set_dma_block_size); +EXPORT_SYMBOL(jz_set_dma_mode); +EXPORT_SYMBOL(set_dma_mode); +EXPORT_SYMBOL(jz_set_oss_dma); +EXPORT_SYMBOL(jz_set_alsa_dma); +EXPORT_SYMBOL(set_dma_addr); +EXPORT_SYMBOL(set_dma_count); +EXPORT_SYMBOL(get_dma_residue); +EXPORT_SYMBOL(enable_dma); +EXPORT_SYMBOL(disable_dma); +EXPORT_SYMBOL(dump_jz_dma_channel); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/gpio.c linux-2.6.31/arch/mips/jz4740/gpio.c --- linux-2.6.31-vanilla/arch/mips/jz4740/gpio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/gpio.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ74xx platform GPIO support + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#define JZ_GPIO_BASE_A (32*0) +#define JZ_GPIO_BASE_B (32*1) +#define JZ_GPIO_BASE_C (32*2) +#define JZ_GPIO_BASE_D (32*3) + +#define JZ_GPIO_NUM_A 32 +#define JZ_GPIO_NUM_B 32 +#define JZ_GPIO_NUM_C 31 +#define JZ_GPIO_NUM_D 32 + +#define JZ_IRQ_GPIO_BASE_A JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_A +#define JZ_IRQ_GPIO_BASE_B JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_B +#define JZ_IRQ_GPIO_BASE_C JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_C +#define JZ_IRQ_GPIO_BASE_D JZ_IRQ_GPIO(0) + JZ_GPIO_BASE_D + +#define JZ_IRQ_GPIO_A(num) (num < JZ_GPIO_NUM_A ? JZ_IRQ_GPIO_BASE_A + num : -EINVAL) +#define JZ_IRQ_GPIO_B(num) (num < JZ_GPIO_NUM_B ? JZ_IRQ_GPIO_BASE_B + num : -EINVAL) +#define JZ_IRQ_GPIO_C(num) (num < JZ_GPIO_NUM_C ? JZ_IRQ_GPIO_BASE_C + num : -EINVAL) +#define JZ_IRQ_GPIO_D(num) (num < JZ_GPIO_NUM_D ? JZ_IRQ_GPIO_BASE_D + num : -EINVAL) + + +#define CHIP_TO_REG(chip, reg) (jz_gpio_base + (((chip)->base) << 3) + reg) +#define CHIP_TO_PIN_REG(chip) CHIP_TO_REG(chip, 0x00) +#define CHIP_TO_DATA_REG(chip) CHIP_TO_REG(chip, 0x10) +#define CHIP_TO_DATA_SET_REG(chip) CHIP_TO_REG(chip, 0x14) +#define CHIP_TO_DATA_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x18) +#define CHIP_TO_PULL_REG(chip) CHIP_TO_REG(chip, 0x30) +#define CHIP_TO_PULL_SET_REG(chip) CHIP_TO_REG(chip, 0x34) +#define CHIP_TO_PULL_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x38) +#define CHIP_TO_DATA_SELECT_REG(chip) CHIP_TO_REG(chip, 0x50) +#define CHIP_TO_DATA_SELECT_SET_REG(chip) CHIP_TO_REG(chip, 0x54) +#define CHIP_TO_DATA_SELECT_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x58) +#define CHIP_TO_DIRECION_REG(chip) CHIP_TO_REG(chip, 0x60) +#define CHIP_TO_DIRECTION_SET_REG(chip) CHIP_TO_REG(chip, 0x64) +#define CHIP_TO_DIRECTION_CLEAR_REG(chip) CHIP_TO_REG(chip, 0x68) + +#define GPIO_TO_BIT(gpio) BIT(gpio & 0x1f) + +#define GPIO_TO_REG(gpio, reg) (jz_gpio_base + ((gpio >> 5) << 8) + reg) +#define GPIO_TO_MASK_REG(gpio) GPIO_TO_REG(gpio, 0x20) +#define GPIO_TO_MASK_SET_REG(gpio) GPIO_TO_REG(gpio, 0x24) +#define GPIO_TO_MASK_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x28) +#define GPIO_TO_PULL_REG(gpio) GPIO_TO_REG(gpio, 0x30) +#define GPIO_TO_PULL_SET_REG(gpio) GPIO_TO_REG(gpio, 0x34) +#define GPIO_TO_PULL_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x38) +#define GPIO_TO_FUNC_REG(gpio) GPIO_TO_REG(gpio, 0x40) +#define GPIO_TO_FUNC_SET_REG(gpio) GPIO_TO_REG(gpio, 0x44) +#define GPIO_TO_FUNC_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x48) +#define GPIO_TO_SEL_REG(gpio) GPIO_TO_REG(gpio, 0x50) +#define GPIO_TO_SEL_SET_REG(gpio) GPIO_TO_REG(gpio, 0x54) +#define GPIO_TO_SEL_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x58) +#define GPIO_TO_TRIGGER_REG(gpio) GPIO_TO_REG(gpio, 0x70) +#define GPIO_TO_TRIGGER_SET_REG(gpio) GPIO_TO_REG(gpio, 0x74) +#define GPIO_TO_TRIGGER_CLEAR_REG(gpio) GPIO_TO_REG(gpio, 0x78) + + + +static void __iomem *jz_gpio_base; +static spinlock_t jz_gpio_lock; + +struct jz_gpio_chip { + unsigned int irq; + unsigned int irq_base; + uint32_t wakeup; + uint32_t saved[4]; + struct gpio_chip gpio_chip; + struct irq_chip irq_chip; + uint32_t edge_trigger_both; +}; + +static struct jz_gpio_chip *jz_irq_to_chip(unsigned int irq) +{ + return get_irq_chip_data(irq); +} + +int jz_gpio_set_function(int gpio, enum jz_gpio_function function) +{ + if (function == JZ_GPIO_FUNC_NONE) { + writew(GPIO_TO_BIT(gpio), GPIO_TO_FUNC_CLEAR_REG(gpio)); + writew(GPIO_TO_BIT(gpio), GPIO_TO_SEL_CLEAR_REG(gpio)); + writew(GPIO_TO_BIT(gpio), GPIO_TO_TRIGGER_CLEAR_REG(gpio)); + } else { + writew(GPIO_TO_BIT(gpio), GPIO_TO_FUNC_SET_REG(gpio)); + switch (function) { + case JZ_GPIO_FUNC1: + writew(GPIO_TO_BIT(gpio), GPIO_TO_SEL_CLEAR_REG(gpio)); + break; + case JZ_GPIO_FUNC3: + writew(GPIO_TO_BIT(gpio), GPIO_TO_TRIGGER_SET_REG(gpio)); + case JZ_GPIO_FUNC2: /* Falltrough */ + writew(GPIO_TO_BIT(gpio), GPIO_TO_SEL_SET_REG(gpio)); + break; + default: + BUG(); + break; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(jz_gpio_set_function); + +int jz_gpio_bulk_request(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + int ret; + + for (i = 0; i < num; ++i, ++request) { + ret = gpio_request(request->gpio, request->name); + if (ret) + goto err; + jz_gpio_set_function(request->gpio, request->function); + } + + return 0; +err: + for (--request; i > 0; --i, --request) + gpio_free(request->gpio); + + return ret; +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_request); + +void jz_gpio_bulk_free(const struct jz_gpio_bulk_request *request, size_t num) +{ + size_t i; + + for (i = 0; i < num; ++i, ++request) { + gpio_free(request->gpio); + jz_gpio_set_function(request->gpio, JZ_GPIO_FUNC_NONE); + } + +} +EXPORT_SYMBOL_GPL(jz_gpio_bulk_free); + +void jz_gpio_enable_pullup(unsigned gpio) +{ + writel(GPIO_TO_BIT(gpio), GPIO_TO_PULL_CLEAR_REG(gpio)); +} +EXPORT_SYMBOL_GPL(jz_gpio_enable_pullup); + +void jz_gpio_disable_pullup(unsigned gpio) +{ + writel(GPIO_TO_BIT(gpio), GPIO_TO_PULL_SET_REG(gpio)); +} +EXPORT_SYMBOL_GPL(jz_gpio_disable_pullup); + +static int jz_gpio_get_value(struct gpio_chip *chip, unsigned gpio) +{ + return !!(readl(CHIP_TO_PIN_REG(chip)) & BIT(gpio)); +} + +static void jz_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value) +{ + uint32_t __iomem *reg = CHIP_TO_DATA_SET_REG(chip) + ((!value) << 2); + writel(BIT(gpio), reg); +} + +static int jz_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value) +{ + writel(BIT(gpio), CHIP_TO_DIRECTION_SET_REG(chip)); + jz_gpio_set_value(chip, gpio, value); + + return 0; +} + +static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + writel(BIT(gpio), CHIP_TO_DIRECTION_CLEAR_REG(chip)); + + return 0; +} + + +#define IRQ_TO_GPIO(irq) (irq - JZ_IRQ_GPIO(0)) +#define IRQ_TO_BIT(irq) BIT(IRQ_TO_GPIO(irq) & 0x1f) + + +#define IRQ_TO_REG(irq, reg) GPIO_TO_REG(IRQ_TO_GPIO(irq), reg) +#define IRQ_TO_PIN_REG(irq) IRQ_TO_REG(irq, 0x00) +#define IRQ_TO_MASK_REG(irq) IRQ_TO_REG(irq, 0x20) +#define IRQ_TO_MASK_SET_REG(irq) IRQ_TO_REG(irq, 0x24) +#define IRQ_TO_MASK_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x28) +#define IRQ_TO_SELECT_REG(irq) IRQ_TO_REG(irq, 0x50) +#define IRQ_TO_SELECT_SET_REG(irq) IRQ_TO_REG(irq, 0x54) +#define IRQ_TO_SELECT_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x58) +#define IRQ_TO_DIRECTION_REG(irq) IRQ_TO_REG(irq, 0x60) +#define IRQ_TO_DIRECTION_SET_REG(irq) IRQ_TO_REG(irq, 0x64) +#define IRQ_TO_DIRECTION_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x68) +#define IRQ_TO_TRIGGER_REG(irq) IRQ_TO_REG(irq, 0x70) +#define IRQ_TO_TRIGGER_SET_REG(irq) IRQ_TO_REG(irq, 0x74) +#define IRQ_TO_TRIGGER_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x78) +#define IRQ_TO_FLAG_REG(irq) IRQ_TO_REG(irq, 0x80) +#define IRQ_TO_FLAG_CLEAR_REG(irq) IRQ_TO_REG(irq, 0x14) + + +static void jz_gpio_irq_demux_handler(unsigned int irq, struct irq_desc *desc) +{ + uint32_t flag; + unsigned int gpio_irq; + unsigned int gpio_bank; + struct jz_gpio_chip *chip = get_irq_desc_data(desc); + + gpio_bank = JZ_IRQ_GPIO0 - irq; + + flag = readl(jz_gpio_base + (gpio_bank << 8) + 0x80); + + gpio_irq = ffs(flag) - 1; + + if (chip->edge_trigger_both & BIT(gpio_irq)) { + uint32_t value = readl(CHIP_TO_PIN_REG(&chip->gpio_chip)); + if (value & BIT(gpio_irq)) { + writel(BIT(gpio_irq), + CHIP_TO_DIRECTION_CLEAR_REG(&chip->gpio_chip)); + } else { + writel(BIT(gpio_irq), + CHIP_TO_DIRECTION_SET_REG(&chip->gpio_chip)); + } + } + + + gpio_irq += (gpio_bank << 5) + JZ_IRQ_GPIO(0); + + + generic_handle_irq(gpio_irq); +}; + +/* TODO: Check if function is gpio */ +static unsigned int jz_gpio_irq_startup(unsigned int irq) +{ + writel(IRQ_TO_BIT(irq), IRQ_TO_SELECT_SET_REG(irq)); + spin_lock(&jz_gpio_lock); + writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq)); + spin_unlock(&jz_gpio_lock); + return 0; +} + +static void jz_gpio_irq_shutdown(unsigned int irq) +{ + spin_lock(&jz_gpio_lock); + writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_SET_REG(irq)); + spin_unlock(&jz_gpio_lock); + /* Set direction to input */ + writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq)); + writel(IRQ_TO_BIT(irq), IRQ_TO_SELECT_CLEAR_REG(irq)); +} + +static void jz_gpio_irq_mask(unsigned int irq) +{ + writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_SET_REG(irq)); +}; + +static void jz_gpio_irq_unmask(unsigned int irq) +{ + writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq)); +}; + +static void jz_gpio_irq_ack(unsigned int irq) +{ + writel(IRQ_TO_BIT(irq), IRQ_TO_FLAG_CLEAR_REG(irq)); +}; + +static int jz_gpio_irq_set_type(unsigned int irq, unsigned int flow_type) +{ + uint32_t mask; + struct jz_gpio_chip *chip = jz_irq_to_chip(irq); + spin_lock(&jz_gpio_lock); + + mask = readl(IRQ_TO_MASK_REG(irq)); + + writel(IRQ_TO_BIT(irq), IRQ_TO_MASK_CLEAR_REG(irq)); + if (flow_type == IRQ_TYPE_EDGE_BOTH) { + uint32_t value = readl(IRQ_TO_PIN_REG(irq)); + if (value & IRQ_TO_BIT(irq)) + flow_type = IRQ_TYPE_EDGE_FALLING; + else + flow_type = IRQ_TYPE_EDGE_RISING; + chip->edge_trigger_both |= IRQ_TO_BIT(irq); + } else { + chip->edge_trigger_both &= ~IRQ_TO_BIT(irq); + } + + switch(flow_type) { + case IRQ_TYPE_EDGE_RISING: + writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_SET_REG(irq)); + writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq)); + break; + case IRQ_TYPE_EDGE_FALLING: + writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq)); + writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_SET_REG(irq)); + break; + case IRQ_TYPE_LEVEL_HIGH: + writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_SET_REG(irq)); + writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_CLEAR_REG(irq)); + break; + case IRQ_TYPE_LEVEL_LOW: + writel(IRQ_TO_BIT(irq), IRQ_TO_DIRECTION_CLEAR_REG(irq)); + writel(IRQ_TO_BIT(irq), IRQ_TO_TRIGGER_CLEAR_REG(irq)); + break; + default: + return -EINVAL; + } + + writel(mask, IRQ_TO_MASK_SET_REG(irq)); + + spin_unlock(&jz_gpio_lock); + + return 0; +} + +static int jz_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + struct jz_gpio_chip *chip = jz_irq_to_chip(irq); + if (on) { + chip->wakeup |= IRQ_TO_BIT(irq); + } else { + chip->wakeup &= ~IRQ_TO_BIT(irq); + } + set_irq_wake(chip->irq, on); + return 0; +} + +int gpio_to_irq(unsigned gpio) +{ + return JZ_IRQ_GPIO(0) + gpio; +} +EXPORT_SYMBOL_GPL(gpio_to_irq); + +int irq_to_gpio(unsigned gpio) +{ + return IRQ_TO_GPIO(gpio); +} +EXPORT_SYMBOL_GPL(irq_to_gpio); + +#define JZ_GPIO_CHIP(_bank) { \ + .irq_base = JZ_IRQ_GPIO_BASE_ ## _bank, \ + .gpio_chip = { \ + .label = "Bank " # _bank, \ + .owner = THIS_MODULE, \ + .set = jz_gpio_set_value, \ + .get = jz_gpio_get_value, \ + .direction_output = jz_gpio_direction_output, \ + .direction_input = jz_gpio_direction_input, \ + .base = JZ_GPIO_BASE_ ## _bank, \ + .ngpio = JZ_GPIO_NUM_ ## _bank, \ + }, \ + .irq_chip = { \ + .name = "GPIO Bank " # _bank, \ + .mask = jz_gpio_irq_mask, \ + .unmask = jz_gpio_irq_unmask, \ + .ack = jz_gpio_irq_ack, \ + .startup = jz_gpio_irq_startup, \ + .shutdown = jz_gpio_irq_shutdown, \ + .set_type = jz_gpio_irq_set_type, \ + .set_wake = jz_gpio_irq_set_wake, \ + }, \ +} + +static struct jz_gpio_chip jz_gpio_chips[] = { + JZ_GPIO_CHIP(A), + JZ_GPIO_CHIP(B), + JZ_GPIO_CHIP(C), + JZ_GPIO_CHIP(D), +}; + +int __init jz_gpiolib_init(void) +{ + struct jz_gpio_chip *chip = jz_gpio_chips; + int i, irq; + + jz_gpio_base = ioremap(0x10010000, 0x400); + + for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) { + gpiochip_add(&chip->gpio_chip); + chip->irq = JZ_IRQ_INTC_GPIO(i); + set_irq_data(chip->irq, chip); + set_irq_chained_handler(chip->irq, jz_gpio_irq_demux_handler); + for (irq = chip->irq_base; irq < chip->irq_base + chip->gpio_chip.ngpio; + ++irq) { + set_irq_chip_and_handler(irq, &chip->irq_chip, handle_level_irq); + set_irq_chip_data(irq, chip); + } + } + + printk("JZ GPIO initalized\n"); + + return 0; +} + +void jz_gpiolib_suspend(void) +{ + struct jz_gpio_chip *chip = jz_gpio_chips; + int i, gpio; + for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) { + gpio = chip->gpio_chip.base; + chip->saved[0] = readl(GPIO_TO_MASK_REG(gpio)); + writel(~(chip->wakeup), GPIO_TO_MASK_SET_REG(gpio)); + } +} + +/* TODO: Use sysdev */ +void jz_gpiolib_resume(void) +{ + struct jz_gpio_chip *chip = jz_gpio_chips; + int i, gpio; + for (i = 0; i < ARRAY_SIZE(jz_gpio_chips); ++i, ++chip) { + writel(~(chip->saved[0]), GPIO_TO_MASK_CLEAR_REG(chip->gpio_chip.base)); + } +} diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/irq.c linux-2.6.31/arch/mips/jz4740/irq.c --- linux-2.6.31-vanilla/arch/mips/jz4740/irq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/irq.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,148 @@ +/* + * linux/arch/mips/jz4740/irq.c + * + * JZ4740 interrupt routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static void __iomem *jz_intc_base; +static uint32_t jz_intc_wakeup; +static uint32_t jz_intc_saved; + +#define JZ_REG_BASE_INTC 0x10001000 + +#define JZ_REG_INTC_STATUS 0x00 +#define JZ_REG_INTC_MASK 0x04 +#define JZ_REG_INTC_SET_MASK 0x08 +#define JZ_REG_INTC_CLEAR_MASK 0x0c +#define JZ_REG_INTC_PENDING 0x10 + +#define IRQ_BIT(x) BIT((x) - JZ_IRQ_BASE) + +static void intc_irq_unmask(unsigned int irq) +{ + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_CLEAR_MASK); +} + +static void intc_irq_mask(unsigned int irq) +{ + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_SET_MASK); +} + +static void intc_irq_ack(unsigned int irq) +{ + writel(IRQ_BIT(irq), jz_intc_base + JZ_REG_INTC_PENDING); +} + +static void intc_irq_end(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) { + intc_irq_unmask(irq); + } +} + +static int intc_irq_set_wake(unsigned int irq, unsigned int on) +{ + if (on) + jz_intc_wakeup |= IRQ_BIT(irq); + else + jz_intc_wakeup &= ~IRQ_BIT(irq); + + return 0; +} + +static struct irq_chip intc_irq_type = { + .name = "INTC", + .mask = intc_irq_mask, + .unmask = intc_irq_unmask, + .ack = intc_irq_ack, + .end = intc_irq_end, + .set_wake = intc_irq_set_wake, +}; + +static irqreturn_t jz4740_cascade(int irq, void *data) +{ + uint32_t irq_reg; + irq_reg = readl(jz_intc_base + JZ_REG_INTC_PENDING); + + if (irq_reg) { + generic_handle_irq(ffs(irq_reg) - 1 + JZ_IRQ_BASE); + return IRQ_HANDLED; + } + + return 0; +} + +static struct irqaction jz4740_cascade_action = { + .handler = jz4740_cascade, + .name = "JZ4740 cascade interrupt" +}; + +void __init arch_init_irq(void) +{ + int i; + mips_cpu_irq_init(); + + jz_intc_base = ioremap(JZ_REG_BASE_INTC, 0x14); + + for (i = JZ_IRQ_BASE; i < JZ_IRQ_BASE + 32; i++) { + intc_irq_mask(i); + set_irq_chip_and_handler(i, &intc_irq_type, handle_level_irq); + } + + setup_irq(2, &jz4740_cascade_action); +} + +asmlinkage void plat_irq_dispatch(void) +{ + unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; + if (pending & STATUSF_IP2) + jz4740_cascade(2, NULL); + else if(pending & STATUSF_IP3) + do_IRQ(3); + else + spurious_interrupt(); +} + +/* TODO: Use sysdev */ +void jz4740_intc_suspend(void) +{ + jz_intc_saved = readl(jz_intc_base + JZ_REG_INTC_MASK); + printk("intc wakeup: %d\n", jz_intc_wakeup); + writel(~jz_intc_wakeup, jz_intc_base + JZ_REG_INTC_SET_MASK); +} + +void jz4740_intc_resume(void) +{ + writel(~jz_intc_saved, jz_intc_base + JZ_REG_INTC_CLEAR_MASK); +} diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/platform.c linux-2.6.31/arch/mips/jz4740/platform.c --- linux-2.6.31-vanilla/arch/mips/jz4740/platform.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/platform.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,240 @@ +/* + * Platform device support for Jz4740 SoC. + * + * Copyright 2007, + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* OHCI (USB full speed host controller) */ +static struct resource jz4740_usb_ohci_resources[] = { + [0] = { + .start = CPHYSADDR(UHC_BASE), + .end = CPHYSADDR(UHC_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_UHC, + .end = JZ_IRQ_UHC, + .flags = IORESOURCE_IRQ, + }, +}; + +/* The dmamask must be set for OHCI to work */ +static u64 ohci_dmamask = ~(u32)0; + +struct platform_device jz4740_usb_ohci_device = { + .name = "jz-ohci", + .id = 0, + .dev = { + .dma_mask = &ohci_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(jz4740_usb_ohci_resources), + .resource = jz4740_usb_ohci_resources, +}; + +/* UDC (USB gadget controller) */ +static struct resource jz4740_usb_gdt_resources[] = { + [0] = { + .start = CPHYSADDR(UDC_BASE), + .end = CPHYSADDR(UDC_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_UDC, + .end = JZ_IRQ_UDC, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 jz4740_udc_dmamask = ~(u32)0; + +struct platform_device jz4740_usb_gdt_device = { + .name = "jz-udc", + .id = -1, + .dev = { + .dma_mask = &jz4740_udc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(jz4740_usb_gdt_resources), + .resource = jz4740_usb_gdt_resources, +}; + +/** MMC/SD controller **/ +static struct resource jz4740_mmc_resources[] = { + [0] = { + .start = CPHYSADDR(MSC_BASE), + .end = CPHYSADDR(MSC_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_MSC, + .end = JZ_IRQ_MSC, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 jz4740_mmc_dmamask = ~(u32)0; + +struct platform_device jz4740_mmc_device = { + .name = "jz-mmc", + .id = 0, + .dev = { + .dma_mask = &jz4740_mmc_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(jz4740_mmc_resources), + .resource = jz4740_mmc_resources, +}; + +static struct resource jz4740_rtc_resources[] = { + [0] = { + .start = CPHYSADDR(RTC_BASE), + .end = CPHYSADDR(RTC_BASE) + 0x10, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_RTC, + .end = JZ_IRQ_RTC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_rtc_device = { + .name = "jz4740-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_rtc_resources), + .resource = jz4740_rtc_resources, +}; + +/** I2C controller **/ +static struct resource jz4740_i2c_resources[] = { + [0] = { + .start = CPHYSADDR(I2C_BASE), + .end = CPHYSADDR(I2C_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_I2C, + .end = JZ_IRQ_I2C, + .flags = IORESOURCE_IRQ, + } +}; + +static u64 jz4740_i2c_dmamask = ~(u32)0; + +struct platform_device jz4740_i2c_device = { + .name = "jz_i2c", + .id = 0, + .dev = { + .dma_mask = &jz4740_i2c_dmamask, + .coherent_dma_mask = 0xffffffff, + }, + .num_resources = ARRAY_SIZE(jz4740_i2c_resources), + .resource = jz4740_i2c_resources, +}; + +static struct resource jz4740_nand_resources[] = { + [0] = { + .start = CPHYSADDR(EMC_BASE), + .end = CPHYSADDR(EMC_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_nand_device = { + .name = "jz4740-nand", + .num_resources = ARRAY_SIZE(jz4740_nand_resources), + .resource = jz4740_nand_resources, +}; + +static struct resource jz4740_framebuffer_resources[] = { + [0] = { + .start = CPHYSADDR(LCD_BASE), + .end = CPHYSADDR(LCD_BASE) + 0x10000 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 jz4740_fb_dmamask = ~(u32)0; + +struct platform_device jz4740_framebuffer_device = { + .name = "jz4740-fb", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_framebuffer_resources), + .resource = jz4740_framebuffer_resources, + .dev = { + .dma_mask = &jz4740_fb_dmamask, + .coherent_dma_mask = 0xffffffff, + }, +}; + +static struct resource jz4740_i2s_resources[] = { + [0] = { + .start = CPHYSADDR(AIC_BASE), + .end = CPHYSADDR(AIC_BASE) + 0x38 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_i2s_device = { + .name = "jz4740-i2s", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_i2s_resources), + .resource = jz4740_i2s_resources, +}; + +static struct resource jz4740_codec_resources[] = { + [0] = { + .start = CPHYSADDR(AIC_BASE) + 0x80, + .end = CPHYSADDR(AIC_BASE) + 0x88 - 1, + .flags = IORESOURCE_MEM, + }, +}; + +struct platform_device jz4740_codec_device = { + .name = "jz4740-codec", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_codec_resources), + .resource = jz4740_codec_resources, +}; + +static struct resource jz4740_adc_resources[] = { + [0] = { + .start = CPHYSADDR(SADC_BASE), + .end = CPHYSADDR(SADC_BASE) + 0x30, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = JZ_IRQ_SADC, + .end = JZ_IRQ_SADC, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device jz4740_adc_device = { + .name = "jz4740-adc", + .id = -1, + .num_resources = ARRAY_SIZE(jz4740_adc_resources), + .resource = jz4740_adc_resources, +}; + +struct platform_device jz4740_battery_device = { + .name = "jz4740-battery", + .id = -1, + .dev = { + .parent = &jz4740_adc_device.dev + }, +}; diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/pm.c linux-2.6.31/arch/mips/jz4740/pm.c --- linux-2.6.31-vanilla/arch/mips/jz4740/pm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/pm.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,97 @@ +/* + * linux/arch/mips/jz4740/common/pm.c + * + * JZ4740 Power Management Routines + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include + +extern void jz4740_intc_suspend(void); +extern void jz4740_intc_resume(void); +extern void jz_gpiolib_suspend(void); +extern void jz_gpiolib_resume(void); + +static int jz_pm_enter(suspend_state_t state) +{ + unsigned long delta; + unsigned long nfcsr = REG_EMC_NFCSR; + uint32_t scr = REG_CPM_SCR; + uint32_t sleep_gpio_save[7*3]; + + /* Preserve current time */ + delta = xtime.tv_sec - REG_RTC_RSR; + + /* Disable nand flash */ + REG_EMC_NFCSR = ~0xff; + + udelay(100); + + /*stop udc and usb*/ + REG_CPM_SCR &= ~( 1<<6 | 1<<7); + REG_CPM_SCR |= 0<<6 | 1<<7; + + jz_gpiolib_suspend(); + jz4740_intc_suspend(); + + /* Enter SLEEP mode */ + REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; + REG_CPM_LCR |= CPM_LCR_LPM_SLEEP; + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); + + /* Restore to IDLE mode */ + REG_CPM_LCR &= ~CPM_LCR_LPM_MASK; + REG_CPM_LCR |= CPM_LCR_LPM_IDLE; + + /* Restore nand flash control register */ + REG_EMC_NFCSR = nfcsr; + + jz4740_intc_resume(); + jz_gpiolib_resume(); + + /* Restore sleep control register */ + REG_CPM_SCR = scr; + + /* Restore current time */ + xtime.tv_sec = REG_RTC_RSR + delta; + + return 0; +} + +static struct platform_suspend_ops jz_pm_ops = { + .valid = suspend_valid_only_mem, + .enter = jz_pm_enter, +}; + +/* + * Initialize power interface + */ +int __init jz_pm_init(void) +{ + suspend_set_ops(&jz_pm_ops); + return 0; + +} +late_initcall(jz_pm_init); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/proc.c linux-2.6.31/arch/mips/jz4740/proc.c --- linux-2.6.31-vanilla/arch/mips/jz4740/proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/proc.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,308 @@ +/* + * linux/arch/mips/jz4740/proc.c + * + * /proc/jz/ procfs for jz4740 on-chip modules. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define DEBUG 1 +#undef DEBUG + + +struct proc_dir_entry *proc_jz_root; + + +/* + * EMC Modules + */ +static int emc_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf (page+len, "SMCR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SMCR0, REG_EMC_SMCR1, REG_EMC_SMCR2, REG_EMC_SMCR3, REG_EMC_SMCR4); + len += sprintf (page+len, "SACR(0-5): 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", REG_EMC_SACR0, REG_EMC_SACR1, REG_EMC_SACR2, REG_EMC_SACR3, REG_EMC_SACR4); + len += sprintf (page+len, "DMCR: 0x%08x\n", REG_EMC_DMCR); + len += sprintf (page+len, "RTCSR: 0x%04x\n", REG_EMC_RTCSR); + len += sprintf (page+len, "RTCOR: 0x%04x\n", REG_EMC_RTCOR); + return len; +} + +/* + * Power Manager Module + */ +static int pmc_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + unsigned long lcr = REG_CPM_LCR; + unsigned long clkgr = REG_CPM_CLKGR; + + len += sprintf (page+len, "Low Power Mode : %s\n", + ((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_IDLE)) ? + "IDLE" : (((lcr & CPM_LCR_LPM_MASK) == (CPM_LCR_LPM_SLEEP)) ? + "SLEEP" : "HIBERNATE")); + len += sprintf (page+len, "Doze Mode : %s\n", + (lcr & CPM_LCR_DOZE_ON) ? "on" : "off"); + if (lcr & CPM_LCR_DOZE_ON) + len += sprintf (page+len, " duty : %d\n", (int)((lcr & CPM_LCR_DOZE_DUTY_MASK) >> CPM_LCR_DOZE_DUTY_BIT)); + len += sprintf (page+len, "IPU : %s\n", + (clkgr & CPM_CLKGR_IPU) ? "stopped" : "running"); + len += sprintf (page+len, "DMAC : %s\n", + (clkgr & CPM_CLKGR_DMAC) ? "stopped" : "running"); + len += sprintf (page+len, "UHC : %s\n", + (clkgr & CPM_CLKGR_UHC) ? "stopped" : "running"); + len += sprintf (page+len, "UDC : %s\n", + (clkgr & CPM_CLKGR_UDC) ? "stopped" : "running"); + len += sprintf (page+len, "LCD : %s\n", + (clkgr & CPM_CLKGR_LCD) ? "stopped" : "running"); + len += sprintf (page+len, "CIM : %s\n", + (clkgr & CPM_CLKGR_CIM) ? "stopped" : "running"); + len += sprintf (page+len, "SADC : %s\n", + (clkgr & CPM_CLKGR_SADC) ? "stopped" : "running"); + len += sprintf (page+len, "MSC : %s\n", + (clkgr & CPM_CLKGR_MSC) ? "stopped" : "running"); + len += sprintf (page+len, "AIC1 : %s\n", + (clkgr & CPM_CLKGR_AIC1) ? "stopped" : "running"); + len += sprintf (page+len, "AIC2 : %s\n", + (clkgr & CPM_CLKGR_AIC2) ? "stopped" : "running"); + len += sprintf (page+len, "SSI : %s\n", + (clkgr & CPM_CLKGR_SSI) ? "stopped" : "running"); + len += sprintf (page+len, "I2C : %s\n", + (clkgr & CPM_CLKGR_I2C) ? "stopped" : "running"); + len += sprintf (page+len, "RTC : %s\n", + (clkgr & CPM_CLKGR_RTC) ? "stopped" : "running"); + len += sprintf (page+len, "TCU : %s\n", + (clkgr & CPM_CLKGR_TCU) ? "stopped" : "running"); + len += sprintf (page+len, "UART1 : %s\n", + (clkgr & CPM_CLKGR_UART1) ? "stopped" : "running"); + len += sprintf (page+len, "UART0 : %s\n", + (clkgr & CPM_CLKGR_UART0) ? "stopped" : "running"); + return len; +} + +static int pmc_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + REG_CPM_CLKGR = simple_strtoul(buffer, 0, 16); + return count; +} + +/* + * Clock Generation Module + */ +#define TO_MHZ(x) (x/1000000),(x%1000000)/10000 +#define TO_KHZ(x) (x/1000),(x%1000)/10 + +static int cgm_read_proc (char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + unsigned int cppcr = REG_CPM_CPPCR; /* PLL Control Register */ + unsigned int cpccr = REG_CPM_CPCCR; /* Clock Control Register */ + unsigned int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; + unsigned int od[4] = {1, 2, 2, 4}; + + len += sprintf (page+len, "CPPCR : 0x%08x\n", cppcr); + len += sprintf (page+len, "CPCCR : 0x%08x\n", cpccr); + len += sprintf (page+len, "PLL : %s\n", + (cppcr & CPM_CPPCR_PLLEN) ? "ON" : "OFF"); + len += sprintf (page+len, "m:n:o : %d:%d:%d\n", + __cpm_get_pllm() + 2, + __cpm_get_plln() + 2, + od[__cpm_get_pllod()] + ); + len += sprintf (page+len, "C:H:M:P : %d:%d:%d:%d\n", + div[__cpm_get_cdiv()], + div[__cpm_get_hdiv()], + div[__cpm_get_mdiv()], + div[__cpm_get_pdiv()] + ); + len += sprintf (page+len, "PLL Freq : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pllout())); + len += sprintf (page+len, "CCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_cclk())); + len += sprintf (page+len, "HCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_hclk())); + len += sprintf (page+len, "MCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mclk())); + len += sprintf (page+len, "PCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_pclk())); + len += sprintf (page+len, "LCDCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_lcdclk())); + len += sprintf (page+len, "PIXCLK : %3d.%02d KHz\n", TO_KHZ(__cpm_get_pixclk())); + len += sprintf (page+len, "I2SCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_i2sclk())); + len += sprintf (page+len, "USBCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_usbclk())); + len += sprintf (page+len, "MSCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_mscclk())); + len += sprintf (page+len, "EXTALCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_extalclk())); + len += sprintf (page+len, "RTCCLK : %3d.%02d MHz\n", TO_MHZ(__cpm_get_rtcclk())); + + return len; +} + +static int cgm_write_proc(struct file *file, const char *buffer, unsigned long count, void *data) +{ + REG_CPM_CPCCR = simple_strtoul(buffer, 0, 16); + return count; +} + + +extern void local_flush_tlb_all(void); + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") +void show_tlb(void) +{ +#define ASID_MASK 0xFF + + unsigned long flags; + unsigned int old_ctx; + unsigned int entry; + unsigned int entrylo0, entrylo1, entryhi; + unsigned int pagemask; + + local_irq_save(flags); + + /* Save old context */ + old_ctx = (read_c0_entryhi() & 0xff); + + printk("TLB content:\n"); + entry = 0; + while(entry < 32) { + write_c0_index(entry); + BARRIER; + tlb_read(); + BARRIER; + entryhi = read_c0_entryhi(); + entrylo0 = read_c0_entrylo0(); + entrylo1 = read_c0_entrylo1(); + pagemask = read_c0_pagemask(); + printk("%02d: ASID=%02d%s VA=0x%08x ", entry, entryhi & ASID_MASK, (entrylo0 & entrylo1 & 1) ? "(G)" : " ", entryhi & ~ASID_MASK); + printk("PA0=0x%08x C0=%x %s%s%s\n", (entrylo0>>6)<<12, (entrylo0>>3) & 7, (entrylo0 & 4) ? "Dirty " : "", (entrylo0 & 2) ? "Valid " : "Invalid ", (entrylo0 & 1) ? "Global" : ""); + printk("\t\t\t PA1=0x%08x C1=%x %s%s%s\n", (entrylo1>>6)<<12, (entrylo1>>3) & 7, (entrylo1 & 4) ? "Dirty " : "", (entrylo1 & 2) ? "Valid " : "Invalid ", (entrylo1 & 1) ? "Global" : ""); + + printk("\t\tpagemask=0x%08x", pagemask); + printk("\tentryhi=0x%08x\n", entryhi); + printk("\t\tentrylo0=0x%08x", entrylo0); + printk("\tentrylo1=0x%08x\n", entrylo1); + + entry++; + } + BARRIER; + write_c0_entryhi(old_ctx); + + local_irq_restore(flags); +} + +/* + * UDC hotplug + */ +#ifdef CONFIG_JZ_UDC_HOTPLUG +extern int jz_udc_active; /* defined in drivers/char/jzchar/jz_udc_hotplug.c */ +#endif + +#ifndef GPIO_UDC_HOTPLUG +#define GPIO_UDC_HOTPLUG 86 +#endif + +static int udc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + if (__gpio_get_pin(GPIO_UDC_HOTPLUG)) { + +#ifdef CONFIG_JZ_UDC_HOTPLUG + + /* Cable has connected, wait for disconnection. */ + __gpio_as_irq_fall_edge(GPIO_UDC_HOTPLUG); + + if (jz_udc_active) + len += sprintf (page+len, "CONNECT_CABLE\n"); + else + len += sprintf (page+len, "CONNECT_POWER\n"); +#else + len += sprintf (page+len, "CONNECT\n"); +#endif + } + else { + +#ifdef CONFIG_JZ_UDC_HOTPLUG + /* Cable has disconnected, wait for connection. */ + __gpio_as_irq_rise_edge(GPIO_UDC_HOTPLUG); +#endif + + len += sprintf (page+len, "REMOVE\n"); + } + + return len; +} + +/* + * /proc/jz/xxx entry + * + */ +static int __init jz_proc_init(void) +{ + struct proc_dir_entry *res; + unsigned int virt_addr, i; + + proc_jz_root = proc_mkdir("jz", 0); + + /* External Memory Controller */ + res = create_proc_entry("emc", 0644, proc_jz_root); + if (res) { + res->read_proc = emc_read_proc; + res->write_proc = NULL; + res->data = NULL; + } + + /* Power Management Controller */ + res = create_proc_entry("pmc", 0644, proc_jz_root); + if (res) { + res->read_proc = pmc_read_proc; + res->write_proc = pmc_write_proc; + res->data = NULL; + } + + /* Clock Generation Module */ + res = create_proc_entry("cgm", 0644, proc_jz_root); + if (res) { + res->read_proc = cgm_read_proc; + res->write_proc = cgm_write_proc; + res->data = NULL; + } + + /* udc hotplug */ + res = create_proc_entry("udc", 0644, proc_jz_root); + if (res) { + res->read_proc = udc_read_proc; + res->write_proc = NULL; + res->data = NULL; + } + + return 0; +} + +__initcall(jz_proc_init); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/prom.c linux-2.6.31/arch/mips/jz4740/prom.c --- linux-2.6.31-vanilla/arch/mips/jz4740/prom.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/prom.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,198 @@ +/* + * + * BRIEF MODULE DESCRIPTION + * PROM library initialisation code, supports YAMON and U-Boot. + * + * Copyright 2000, 2001, 2006 MontaVista Software Inc. + * Author: MontaVista Software, Inc. + * ppopov@mvista.com or source@mvista.com + * + * This file was derived from Carsten Langgaard's + * arch/mips/mips-boards/xx files. + * + * Carsten Langgaard, carstenl@mips.com + * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include + +#include +#include + +/* #define DEBUG_CMDLINE */ + +int prom_argc; +char **prom_argv, **prom_envp; + +char * prom_getcmdline(void) +{ + return &(arcs_cmdline[0]); +} + +void prom_init_cmdline(void) +{ + char *cp; + int actr; + + actr = 1; /* Always ignore argv[0] */ + + cp = &(arcs_cmdline[0]); + while(actr < prom_argc) { + strcpy(cp, prom_argv[actr]); + cp += strlen(prom_argv[actr]); + *cp++ = ' '; + actr++; + } + if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */ + --cp; + if (prom_argc > 1) + *cp = '\0'; + +} + + +char *prom_getenv(char *envname) +{ +#if 0 + /* + * Return a pointer to the given environment variable. + * YAMON uses "name", "value" pairs, while U-Boot uses "name=value". + */ + + char **env = prom_envp; + int i = strlen(envname); + int yamon = (*env && strchr(*env, '=') == NULL); + + while (*env) { + if (yamon) { + if (strcmp(envname, *env++) == 0) + return *env; + } else { + if (strncmp(envname, *env, i) == 0 && (*env)[i] == '=') + return *env + i + 1; + } + env++; + } +#endif + return NULL; +} + +inline unsigned char str2hexnum(unsigned char c) +{ + if(c >= '0' && c <= '9') + return c - '0'; + if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + if(c >= 'A' && c <= 'F') + return c - 'A' + 10; + return 0; /* foo */ +} + +inline void str2eaddr(unsigned char *ea, unsigned char *str) +{ + int i; + + for(i = 0; i < 6; i++) { + unsigned char num; + + if((*str == '.') || (*str == ':')) + str++; + num = str2hexnum(*str++) << 4; + num |= (str2hexnum(*str++)); + ea[i] = num; + } +} + +int get_ethernet_addr(char *ethernet_addr) +{ + char *ethaddr_str; + + ethaddr_str = prom_getenv("ethaddr"); + if (!ethaddr_str) { + printk("ethaddr not set in boot prom\n"); + return -1; + } + str2eaddr(ethernet_addr, ethaddr_str); + +#if 0 + { + int i; + + printk("get_ethernet_addr: "); + for (i=0; i<5; i++) + printk("%02x:", (unsigned char)*(ethernet_addr+i)); + printk("%02x\n", *(ethernet_addr+i)); + } +#endif + + return 0; +} + +void __init prom_free_prom_memory(void) +{ +} + +void __init prom_init(void) +{ + unsigned char *memsize_str; + unsigned long memsize; + + prom_argc = (int) fw_arg0; + prom_argv = (char **) fw_arg1; + prom_envp = (char **) fw_arg2; + + mips_machtype = MACH_INGENIC_JZ4740; + + prom_init_cmdline(); + memsize_str = prom_getenv("memsize"); + if (!memsize_str) { + memsize = 0x04000000; + } else { + memsize = simple_strtol(memsize_str, NULL, 0); + } + add_memory_region(0, memsize, BOOT_MEM_RAM); +} + +/* used by early printk */ +void prom_putchar(char c) +{ + volatile u8 *uart_lsr = (volatile u8 *)(UART0_BASE + OFF_LSR); + volatile u8 *uart_tdr = (volatile u8 *)(UART0_BASE + OFF_TDR); + + /* Wait for fifo to shift out some bytes */ + while ( !((*uart_lsr & (UARTLSR_TDRQ | UARTLSR_TEMT)) == 0x60) ); + + *uart_tdr = (u8)c; +} + +const char *get_system_type(void) +{ + return "JZ4740"; +} + +EXPORT_SYMBOL(prom_getcmdline); +EXPORT_SYMBOL(get_ethernet_addr); +EXPORT_SYMBOL(str2eaddr); diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/reset.c linux-2.6.31/arch/mips/jz4740/reset.c --- linux-2.6.31-vanilla/arch/mips/jz4740/reset.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/reset.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,48 @@ +/* + * linux/arch/mips/jz4740/reset.c + * + * JZ4740 reset routines. + * + * Copyright (c) 2006-2007 Ingenic Semiconductor Inc. + * Author: + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +void jz_restart(char *command) +{ + printk(KERN_NOTICE "Restarting after 4 ms\n"); + REG_WDT_TCSR = WDT_TCSR_PRESCALE4 | WDT_TCSR_EXT_EN; + REG_WDT_TCNT = 0; + REG_WDT_TDR = JZ_EXTAL/1000; /* reset after 4ms */ + REG_TCU_TSCR = TCU_TSSR_WDTSC; /* enable wdt clock */ + REG_WDT_TCER = WDT_TCER_TCEN; /* wdt start */ + while (1); +} + +void jz_halt(void) +{ + /* Put CPU to power down mode */ + while (!(REG_RTC_RCR & RTC_RCR_WRDY)); + REG_RTC_HCR = RTC_HCR_PD; + + while (1) + __asm__(".set\tmips3\n\t" + "wait\n\t" + ".set\tmips0"); +} + +void jz_power_off(void) +{ + jz_halt(); +} diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/setup.c linux-2.6.31/arch/mips/jz4740/setup.c --- linux-2.6.31-vanilla/arch/mips/jz4740/setup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/setup.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,180 @@ +/* + * linux/arch/mips/jz4740/common/setup.c + * + * JZ4740 common setup routines. + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +#ifdef CONFIG_PC_KEYB +#include +#endif + +jz_clocks_t jz_clocks; + +extern char * __init prom_getcmdline(void); +extern void __init jz_board_setup(void); +extern void jz_restart(char *); +extern void jz_halt(void); +extern void jz_power_off(void); +extern void jz_time_init(void); + +static void __init sysclocks_setup(void) +{ +#ifndef CONFIG_MIPS_JZ_EMURUS /* FPGA */ + jz_clocks.cclk = __cpm_get_cclk(); + jz_clocks.hclk = __cpm_get_hclk(); + jz_clocks.pclk = __cpm_get_pclk(); + jz_clocks.mclk = __cpm_get_mclk(); + jz_clocks.lcdclk = __cpm_get_lcdclk(); + jz_clocks.pixclk = __cpm_get_pixclk(); + jz_clocks.i2sclk = __cpm_get_i2sclk(); + jz_clocks.usbclk = __cpm_get_usbclk(); + jz_clocks.mscclk = __cpm_get_mscclk(); + jz_clocks.extalclk = __cpm_get_extalclk(); + jz_clocks.rtcclk = __cpm_get_rtcclk(); +#else + +#define FPGACLK 8000000 + + jz_clocks.cclk = FPGACLK; + jz_clocks.hclk = FPGACLK; + jz_clocks.pclk = FPGACLK; + jz_clocks.mclk = FPGACLK; + jz_clocks.lcdclk = FPGACLK; + jz_clocks.pixclk = FPGACLK; + jz_clocks.i2sclk = FPGACLK; + jz_clocks.usbclk = FPGACLK; + jz_clocks.mscclk = FPGACLK; + jz_clocks.extalclk = FPGACLK; + jz_clocks.rtcclk = FPGACLK; +#endif + + printk("CPU clock: %dMHz, System clock: %dMHz, Peripheral clock: %dMHz, Memory clock: %dMHz\n", + (jz_clocks.cclk + 500000) / 1000000, + (jz_clocks.hclk + 500000) / 1000000, + (jz_clocks.pclk + 500000) / 1000000, + (jz_clocks.mclk + 500000) / 1000000); +} + +static void __init soc_cpm_setup(void) +{ + /* Enable CKO to external memory */ + __cpm_enable_cko(); + + /* CPU enters IDLE mode when executing 'wait' instruction */ + __cpm_idle_mode(); + + /* Setup system clocks */ + sysclocks_setup(); +} + +static void __init soc_harb_setup(void) +{ +// __harb_set_priority(0x00); /* CIM>LCD>DMA>ETH>PCI>USB>CBB */ +// __harb_set_priority(0x03); /* LCD>CIM>DMA>ETH>PCI>USB>CBB */ +// __harb_set_priority(0x0a); /* ETH>LCD>CIM>DMA>PCI>USB>CBB */ +} + +static void __init soc_emc_setup(void) +{ +} + +static void __init soc_dmac_setup(void) +{ + __dmac_enable_module(); +} + +static void __init jz_soc_setup(void) +{ + soc_cpm_setup(); + soc_harb_setup(); + soc_emc_setup(); + soc_dmac_setup(); +} + +static void __init jz_serial_setup(void) +{ +#ifdef CONFIG_SERIAL_8250 + struct uart_port s; + REG8(UART0_FCR) |= UARTFCR_UUE; /* enable UART module */ + memset(&s, 0, sizeof(s)); + s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST; + s.iotype = SERIAL_IO_MEM; + s.regshift = 2; + s.uartclk = jz_clocks.extalclk ; + + s.line = 0; + s.membase = (u8 *)UART0_BASE; + s.irq = JZ_IRQ_UART0; + if (early_serial_setup(&s) != 0) { + printk(KERN_ERR "Serial ttyS0 setup failed!\n"); + } + + s.line = 1; + s.membase = (u8 *)UART1_BASE; + s.irq = JZ_IRQ_UART1; + if (early_serial_setup(&s) != 0) { + printk(KERN_ERR "Serial ttyS1 setup failed!\n"); + } +#endif +} + +void __init plat_mem_setup(void) +{ + char *argptr; + + argptr = prom_getcmdline(); + + /* IO/MEM resources. Which will be the addtion value in `inX' and + * `outX' macros defined in asm/io.h */ + set_io_port_base(0); + ioport_resource.start = 0x00000000; + ioport_resource.end = 0xffffffff; + iomem_resource.start = 0x00000000; + iomem_resource.end = 0xffffffff; + + _machine_restart = jz_restart; + _machine_halt = jz_halt; + pm_power_off = jz_power_off; + jz_soc_setup(); + jz_serial_setup(); +} + diff -ruN linux-2.6.31-vanilla/arch/mips/jz4740/time.c linux-2.6.31/arch/mips/jz4740/time.c --- linux-2.6.31-vanilla/arch/mips/jz4740/time.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/arch/mips/jz4740/time.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,159 @@ +/* + * linux/arch/mips/jz4740/time.c + * + * Setting up the clock on the JZ4740 boards. + * + * Copyright (C) 2008 Ingenic Semiconductor Inc. + * Author: + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include + +#include +#include + +/* This is for machines which generate the exact clock. */ + +#define JZ_TIMER_CHAN 0 +#define JZ_TIMER_IRQ JZ_IRQ_TCU0 + +#define JZ_TIMER_CLOCK (JZ_EXTAL>>4) /* Jz timer clock frequency */ + +static struct clocksource clocksource_jz; /* Jz clock source */ +static struct clock_event_device jz_clockevent_device; /* Jz clock event */ + +void (*jz_timer_callback)(void); + +static irqreturn_t jz_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *cd = dev_id; + + REG_TCU_TFCR = 1 << JZ_TIMER_CHAN; /* ACK timer */ + + if (jz_timer_callback) + jz_timer_callback(); + + cd->event_handler(cd); + + return IRQ_HANDLED; +} + +static struct irqaction jz_irqaction = { + .handler = jz_timer_interrupt, + .flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER, + .name = "jz-timerirq", +}; + + +cycle_t jz_get_cycles(void) +{ + /* convert jiffes to jz timer cycles */ + return (cycle_t)( jiffies*((JZ_TIMER_CLOCK)/HZ) + REG_TCU_TCNT(JZ_TIMER_CHAN)); +} + +static struct clocksource clocksource_jz = { + .name = "jz_clocksource", + .rating = 300, + .read = jz_get_cycles, + .mask = 0xFFFF, + .shift = 10, + .flags = CLOCK_SOURCE_WATCHDOG, +}; + +static int __init jz_clocksource_init(void) +{ + clocksource_jz.mult = clocksource_hz2mult(JZ_TIMER_CLOCK, clocksource_jz.shift); + clocksource_register(&clocksource_jz); + return 0; +} + +static int jz_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + return 0; +} + +static void jz_set_mode(enum clock_event_mode mode, + struct clock_event_device *evt) +{ + switch (mode) { + case CLOCK_EVT_MODE_PERIODIC: + break; + case CLOCK_EVT_MODE_ONESHOT: + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + break; + case CLOCK_EVT_MODE_RESUME: + break; + } +} + +static struct clock_event_device jz_clockevent_device = { + .name = "jz-clockenvent", + .features = CLOCK_EVT_FEAT_PERIODIC, +// .features = CLOCK_EVT_FEAT_ONESHOT, /* Jz4740 not support dynamic clock now */ + + /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ + .mult = 1, + .rating = 300, + .irq = JZ_TIMER_IRQ, + .set_mode = jz_set_mode, + .set_next_event = jz_set_next_event, +}; + +static void __init jz_clockevent_init(void) +{ + struct clock_event_device *cd = &jz_clockevent_device; + unsigned int cpu = smp_processor_id(); + + cd->cpumask = cpumask_of(cpu); + clockevents_register_device(cd); +} + +static void __init jz_timer_setup(void) +{ + jz_clocksource_init(); /* init jz clock source */ + jz_clockevent_init(); /* init jz clock event */ + + /* + * Make irqs happen for the system timer + */ + jz_irqaction.dev_id = &jz_clockevent_device; + setup_irq(JZ_TIMER_IRQ, &jz_irqaction); +} + + +void __init plat_time_init(void) +{ + unsigned int latch; + /* Init timer */ + latch = ( JZ_TIMER_CLOCK + (HZ>>1)) / HZ; + + REG_TCU_TCSR(JZ_TIMER_CHAN) = TCU_TCSR_PRESCALE16 | TCU_TCSR_EXT_EN; + REG_TCU_TCNT(JZ_TIMER_CHAN) = 0; + REG_TCU_TDHR(JZ_TIMER_CHAN) = 0; + REG_TCU_TDFR(JZ_TIMER_CHAN) = latch; + + REG_TCU_TMSR = (1 << (JZ_TIMER_CHAN + 16)); /* mask half irq */ + REG_TCU_TMCR = (1 << JZ_TIMER_CHAN); /* unmask full irq */ + REG_TCU_TSCR = (1 << JZ_TIMER_CHAN); /* enable timer clock */ + REG_TCU_TESR = (1 << JZ_TIMER_CHAN); /* start counting up */ + + jz_timer_setup(); +} diff -ruN linux-2.6.31-vanilla/drivers/char/defkeymap.c linux-2.6.31/drivers/char/defkeymap.c --- linux-2.6.31-vanilla/drivers/char/defkeymap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/char/defkeymap.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,438 @@ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf07f, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf701, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf209, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03c, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short shift_map[NR_KEYS] = { + 0xf200, 0xf01b, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, + 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf07f, 0xf009, + 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, + 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf201, 0xf702, 0xfb41, 0xfb53, + 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, + 0xf022, 0xf07e, 0xf700, 0xf07c, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03b, 0xf03a, 0xf03f, 0xf701, 0xf30c, + 0xf703, 0xf020, 0xf207, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, + 0xf10f, 0xf110, 0xf111, 0xf112, 0xf113, 0xf213, 0xf203, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf03e, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf20b, 0xf601, 0xf602, 0xf117, 0xf600, 0xf20a, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, + 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf07e, 0xf200, 0xf200, + 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, + 0xf028, 0xf029, 0xf200, 0xf07e, 0xf201, 0xf702, 0xf0b0, 0xf0a8, + 0xf0a4, 0xf02d, 0xf05f, 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf039, 0xf030, 0xf916, 0xfb76, + 0xf915, 0xf03c, 0xf03e, 0xf027, 0xf022, 0xf200, 0xf701, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, + 0xf036, 0xf037, 0xf038, 0xf514, 0xf515, 0xf208, 0xf202, 0xf911, + 0xf912, 0xf913, 0xf30b, 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf90b, + 0xf90c, 0xf90d, 0xf90a, 0xf310, 0xf206, 0xf200, 0xf07c, 0xf516, + 0xf517, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, + 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf007, 0xf000, 0xf700, 0xf01c, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf701, 0xf30c, + 0xf703, 0xf000, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf208, 0xf204, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf10a, + 0xf10b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, + 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, + 0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013, + 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf701, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short alt_map[NR_KEYS] = { + 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, + 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf87f, 0xf809, + 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, + 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf80d, 0xf702, 0xf861, 0xf873, + 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, + 0xf827, 0xf860, 0xf700, 0xf85c, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf200, 0xf200, 0xf82f, 0xf701, 0xf30c, + 0xf703, 0xf820, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf209, 0xf907, + 0xf908, 0xf909, 0xf30b, 0xf904, 0xf905, 0xf906, 0xf30a, 0xf901, + 0xf902, 0xf903, 0xf900, 0xf310, 0xf206, 0xf200, 0xf83c, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf210, 0xf211, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, + 0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813, + 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf701, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, + 0xf505, 0xf506, 0xf507, 0xf508, 0xf509, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf20c, 0xf206, 0xf200, 0xf200, 0xf50a, + 0xf50b, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf20c, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +static u_short ctr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf033, 0xf200, 0xf200, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xf037, 0xf038, + 0xf039, 0xfb70, 0xf200, 0xf200, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xf034, 0xf035, 0xf036, 0xf200, + 0xf200, 0xf200, 0xf700, 0xf200, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xf031, 0xf032, 0xf200, 0xf200, 0xf030, 0xf701, 0xf30c, + 0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf208, 0xf200, 0xf307, + 0xf308, 0xf309, 0xf30b, 0xf304, 0xf305, 0xf306, 0xf30a, 0xf301, + 0xf302, 0xf303, 0xf300, 0xf310, 0xf206, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf30e, 0xf707, 0xf30d, 0xf01c, 0xf701, 0xf205, 0xf114, 0xf603, + 0xf118, 0xf601, 0xf602, 0xf117, 0xf600, 0xf119, 0xf115, 0xf116, + 0xf11a, 0xf10c, 0xf10d, 0xf11b, 0xf11c, 0xf110, 0xf311, 0xf11d, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + ctr_map, 0 +}; + +unsigned int keymap_count = 8; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + 0, + 0, + func_buf + 149, + 0, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', 'a', '\344'}, + {'O', 'A', '\305'}, {'o', 'a', '\345'}, + {'0', 'A', '\305'}, {'0', 'a', '\345'}, + {'A', 'A', '\305'}, {'a', 'a', '\345'}, + {'A', 'E', '\306'}, {'a', 'e', '\346'}, + {',', 'C', '\307'}, {',', 'c', '\347'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; diff -ruN linux-2.6.31-vanilla/drivers/misc/jz4740-adc.c linux-2.6.31/drivers/misc/jz4740-adc.c --- linux-2.6.31-vanilla/drivers/misc/jz4740-adc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/misc/jz4740-adc.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC ADC driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * This driver is meant to synchronize access to the adc core for the battery + * and touchscreen driver. Thus these drivers should use the adc driver as a + * parent. + */ + +#include +#include +#include +#include +#include +#include + +#define JZ_REG_ADC_ENABLE 0x00 +#define JZ_REG_ADC_CFG 0x04 +#define JZ_REG_ADC_CTRL 0x08 +#define JZ_REG_ADC_STATUS 0x0C +#define JZ_REG_ADC_SAME 0x10 +#define JZ_REG_ADC_WAIT 0x14 +#define JZ_REG_ADC_TOUCH 0x18 +#define JZ_REG_ADC_BATTERY 0x1C +#define JZ_REG_ADC_ADCIN 0x20 + +#define JZ_ADC_ENABLE_TOUCH BIT(2) +#define JZ_ADC_ENABLE_BATTERY BIT(1) +#define JZ_ADC_ENABLE_ADCIN BIT(0) + +#define JZ_ADC_CFG_SPZZ BIT(31) +#define JZ_ADC_CFG_EX_IN BIT(30) +#define JZ_ADC_CFG_DNUM_MASK (0x7 << 16) +#define JZ_ADC_CFG_DMA_ENABLE BIT(15) +#define JZ_ADC_CFG_XYZ_MASK (0x2 << 13) +#define JZ_ADC_CFG_SAMPLE_NUM_MASK (0x7 << 10) +#define JZ_ADC_CFG_CLKDIV (0xf << 5) +#define JZ_ADC_CFG_BAT_MB BIT(4) + +#define JZ_ADC_CFG_DNUM_OFFSET 16 +#define JZ_ADC_CFG_XYZ_OFFSET 13 +#define JZ_ADC_CFG_SAMPLE_NUM_OFFSET 10 +#define JZ_ADC_CFG_CLKDIV_OFFSET 5 + +#define JZ_ADC_IRQ_PENDOWN BIT(4) +#define JZ_ADC_IRQ_PENUP BIT(3) +#define JZ_ADC_IRQ_TOUCH BIT(2) +#define JZ_ADC_IRQ_BATTERY BIT(1) +#define JZ_ADC_IRQ_ADCIN BIT(0) + +#define JZ_ADC_TOUCH_TYPE1 BIT(31) +#define JZ_ADC_TOUCH_DATA1_MASK 0xfff +#define JZ_ADC_TOUCH_TYPE0 BIT(15) +#define JZ_ADC_TOUCH_DATA0_MASK 0xfff + +#define JZ_ADC_BATTERY_MASK 0xfff + +#define JZ_ADC_ADCIN_MASK 0xfff + +struct jz4740_adc { + struct resource *mem; + void __iomem *base; + + int irq; + + struct completion bat_completion; + struct completion adc_completion; + + spinlock_t lock; +}; + +static irqreturn_t jz4740_adc_irq(int irq, void *data) +{ + struct jz4740_adc *adc = data; + uint8_t status; + + status = readb(adc->base + JZ_REG_ADC_STATUS); + + if (status & JZ_ADC_IRQ_BATTERY) + complete(&adc->bat_completion); + if (status & JZ_ADC_IRQ_ADCIN) + complete(&adc->adc_completion); + + writeb(0xff, adc->base + JZ_REG_ADC_STATUS); + + return IRQ_HANDLED; +} + +static void jz4740_adc_enable_irq(struct jz4740_adc *adc, int irq) +{ + unsigned long flags; + uint8_t val; + + spin_lock_irqsave(&adc->lock, flags); + + val = readb(adc->base + JZ_REG_ADC_CTRL); + val &= ~irq; + writeb(val, adc->base + JZ_REG_ADC_CTRL); + + spin_unlock_irqrestore(&adc->lock, flags); +} + +static void jz4740_adc_disable_irq(struct jz4740_adc *adc, int irq) +{ + unsigned long flags; + uint8_t val; + + spin_lock_irqsave(&adc->lock, flags); + + val = readb(adc->base + JZ_REG_ADC_CTRL); + val |= irq; + writeb(val, adc->base + JZ_REG_ADC_CTRL); + + spin_unlock_irqrestore(&adc->lock, flags); +} + +static void jz4740_adc_enable_adc(struct jz4740_adc *adc, int engine) +{ + unsigned long flags; + uint8_t val; + + spin_lock_irqsave(&adc->lock, flags); + + val = readb(adc->base + JZ_REG_ADC_ENABLE); + val |= engine; + writeb(val, adc->base + JZ_REG_ADC_ENABLE); + + spin_unlock_irqrestore(&adc->lock, flags); +} + +static void jz4740_adc_disable_adc(struct jz4740_adc *adc, int engine) +{ + unsigned long flags; + uint8_t val; + + spin_lock_irqsave(&adc->lock, flags); + + val = readb(adc->base + JZ_REG_ADC_ENABLE); + val &= ~engine; + writeb(val, adc->base + JZ_REG_ADC_ENABLE); + + spin_unlock_irqrestore(&adc->lock, flags); +} + +static inline void jz4740_adc_set_cfg(struct jz4740_adc *adc, uint32_t mask, +uint32_t val) +{ + unsigned long flags; + uint32_t cfg; + + spin_lock_irqsave(&adc->lock, flags); + + cfg = readl(adc->base + JZ_REG_ADC_CFG); + + cfg &= ~mask; + cfg |= val; + + writel(cfg, adc->base + JZ_REG_ADC_CFG); + + spin_unlock_irqrestore(&adc->lock, flags); +} + +long jz4740_adc_read_battery_voltage(struct device *dev, + enum jz_adc_battery_scale scale) +{ + struct jz4740_adc *adc = dev_get_drvdata(dev); + unsigned long t; + long long voltage; + uint16_t val; + + if (!adc) + return -ENODEV; + + if (scale == JZ_ADC_BATTERY_SCALE_2V5) + jz4740_adc_set_cfg(adc, JZ_ADC_CFG_BAT_MB, JZ_ADC_CFG_BAT_MB); + else + jz4740_adc_set_cfg(adc, JZ_ADC_CFG_BAT_MB, 0); + + jz4740_adc_enable_irq(adc, JZ_ADC_IRQ_BATTERY); + jz4740_adc_enable_adc(adc, JZ_ADC_ENABLE_BATTERY); + + t = wait_for_completion_interruptible_timeout(&adc->bat_completion, + HZ); + + jz4740_adc_disable_irq(adc, JZ_ADC_IRQ_BATTERY); + + if (t <= 0) { + jz4740_adc_disable_adc(adc, JZ_ADC_ENABLE_BATTERY); + return t ? t : -ETIMEDOUT; + } + + val = readw(adc->base + JZ_REG_ADC_BATTERY); + + if (scale == JZ_ADC_BATTERY_SCALE_2V5) + voltage = (((long long)val) * 2500000LL) >> 12LL; + else + voltage = ((((long long)val) * 7395000LL) >> 12LL) + 33000LL; + + return voltage; +} +EXPORT_SYMBOL_GPL(jz4740_adc_read_battery_voltage); + +static ssize_t jz4740_adc_read_adcin(struct device *dev, + struct device_attribute *dev_attr, + char *buf) +{ + struct jz4740_adc *adc = dev_get_drvdata(dev); + unsigned long t; + uint16_t val; + + jz4740_adc_enable_irq(adc, JZ_ADC_IRQ_ADCIN); + jz4740_adc_enable_adc(adc, JZ_ADC_ENABLE_ADCIN); + + t = wait_for_completion_interruptible_timeout(&adc->adc_completion, + HZ); + + jz4740_adc_disable_irq(adc, JZ_ADC_IRQ_ADCIN); + + if (t <= 0) { + jz4740_adc_disable_adc(adc, JZ_ADC_ENABLE_ADCIN); + return t ? t : -ETIMEDOUT; + } + + val = readw(adc->base + JZ_REG_ADC_ADCIN); + + return sprintf(buf, "%d\n", val); +} + +static DEVICE_ATTR(adcin, S_IRUGO, jz4740_adc_read_adcin, NULL); + +static int __devinit jz4740_adc_probe(struct platform_device *pdev) +{ + int ret; + struct jz4740_adc *adc; + + adc = kmalloc(sizeof(*adc), GFP_KERNEL); + + adc->irq = platform_get_irq(pdev, 0); + + if (adc->irq < 0) { + ret = adc->irq; + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret); + goto err_free; + } + + adc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!adc->mem) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get platform mmio resource\n"); + goto err_free; + } + + adc->mem = request_mem_region(adc->mem->start, resource_size(adc->mem), + pdev->name); + + if (!adc->mem) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to request mmio memory region\n"); + goto err_free; + } + + adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem)); + + if (!adc->base) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); + goto err_release_mem_region; + } + + + init_completion(&adc->bat_completion); + init_completion(&adc->adc_completion); + + spin_lock_init(&adc->lock); + + platform_set_drvdata(pdev, adc); + + ret = request_irq(adc->irq, jz4740_adc_irq, 0, pdev->name, adc); + + if (ret) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_iounmap; + } + + ret = device_create_file(&pdev->dev, &dev_attr_adcin); + if (ret) { + dev_err(&pdev->dev, "Failed to create sysfs file: %d\n", ret); + goto err_free_irq; + } + + writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); + writeb(0xff, adc->base + JZ_REG_ADC_CTRL); + + return 0; + +err_free_irq: + free_irq(adc->irq, adc); +err_iounmap: + platform_set_drvdata(pdev, NULL); + iounmap(adc->base); +err_release_mem_region: + release_mem_region(adc->mem->start, resource_size(adc->mem)); +err_free: + kfree(adc); + + return ret; +} + +static int __devexit jz4740_adc_remove(struct platform_device *pdev) +{ + struct jz4740_adc *adc = platform_get_drvdata(pdev); + + device_remove_file(&pdev->dev, &dev_attr_adcin); + + free_irq(adc->irq, adc); + + iounmap(adc->base); + release_mem_region(adc->mem->start, resource_size(adc->mem)); + + platform_set_drvdata(pdev, NULL); + + kfree(adc); + + return 0; +} + +struct platform_driver jz4740_adc_driver = { + .probe = jz4740_adc_probe, + .remove = jz4740_adc_remove, + .driver = { + .name = "jz4740-adc", + .owner = THIS_MODULE, + }, +}; + +static int __init jz4740_adc_init(void) +{ + return platform_driver_register(&jz4740_adc_driver); +} +module_init(jz4740_adc_init); + +static void __exit jz4740_adc_exit(void) +{ + platform_driver_unregister(&jz4740_adc_driver); +} +module_exit(jz4740_adc_exit); + +MODULE_DESCRIPTION("JZ4720/JZ4740 SoC ADC driver"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:jz4740-adc"); +MODULE_ALIAS("platform:jz4720-adc"); diff -ruN linux-2.6.31-vanilla/drivers/mmc/host/jz_mmc.c linux-2.6.31/drivers/mmc/host/jz_mmc.c --- linux-2.6.31-vanilla/drivers/mmc/host/jz_mmc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/mmc/host/jz_mmc.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,994 @@ +/* + * linux/drivers/mmc/jz_mmc.c - JZ SD/MMC driver + * + * Copyright (C) 2005 - 2008 Ingenic Semiconductor Inc. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "jz_mmc.h" + +#define DRIVER_NAME "jz-mmc" + +#define NR_SG 1 + +#if defined(CONFIG_SOC_JZ4725) || defined(CONFIG_SOC_JZ4720) +#undef USE_DMA +#else +#define USE_DMA +#endif + +struct jz_mmc_host { + struct mmc_host *mmc; + spinlock_t lock; + struct { + int len; + int dir; + } dma; + struct { + int index; + int offset; + int len; + } pio; + int irq; + unsigned int clkrt; + unsigned int cmdat; + unsigned int imask; + unsigned int power_mode; + struct jz_mmc_platform_data *pdata; + struct mmc_request *mrq; + struct mmc_command *cmd; + struct mmc_data *data; + dma_addr_t sg_dma; + struct jzsoc_dma_desc *sg_cpu; + unsigned int dma_len; + unsigned int dma_dir; + struct pm_dev *pmdev; +}; + +static int r_type = 0; + +#define MMC_IRQ_MASK() \ +do { \ + REG_MSC_IMASK = 0xff; \ + REG_MSC_IREG = 0xff; \ +} while (0) + +static int rxdmachan = 0; +static int txdmachan = 0; +static int mmc_slot_enable = 0; + +/* Stop the MMC clock and wait while it happens */ +static inline int jz_mmc_stop_clock(void) +{ + int timeout = 1000; + + REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP; + while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) { + timeout--; + if (timeout == 0) + return 0; + udelay(1); + } + return MMC_NO_ERROR; +} + +/* Start the MMC clock and operation */ +static inline int jz_mmc_start_clock(void) +{ + REG_MSC_STRPCL = + MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP; + return MMC_NO_ERROR; +} + +static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate) +{ + u32 clkrt; + u32 clk_src = is_sd ? 24000000 : 20000000; + + clkrt = 0; + while (rate < clk_src) { + clkrt++; + clk_src >>= 1; + } + return clkrt; +} + +/* Select the MMC clock frequency */ +static int jz_mmc_set_clock(u32 rate) +{ + int clkrt; + + jz_mmc_stop_clock(); + __cpm_select_msc_clk(1); /* select clock source from CPM */ + clkrt = jz_mmc_calc_clkrt(1, rate); + REG_MSC_CLKRT = clkrt; + return MMC_NO_ERROR; +} + +static void jz_mmc_enable_irq(struct jz_mmc_host *host, unsigned int mask) +{ + unsigned long flags; + spin_lock_irqsave(&host->lock, flags); + host->imask &= ~mask; + REG_MSC_IMASK = host->imask; + spin_unlock_irqrestore(&host->lock, flags); +} + +static void jz_mmc_disable_irq(struct jz_mmc_host *host, unsigned int mask) +{ + unsigned long flags; + + spin_lock_irqsave(&host->lock, flags); + host->imask |= mask; + REG_MSC_IMASK = host->imask; + spin_unlock_irqrestore(&host->lock, flags); +} + +void jz_set_dma_block_size(int dmanr, int nbyte); + +#ifdef USE_DMA +static inline void +jz_mmc_start_dma(int chan, unsigned long phyaddr, int count, int mode) +{ + unsigned long flags; + + flags = claim_dma_lock(); + disable_dma(chan); + clear_dma_ff(chan); + jz_set_dma_block_size(chan, 32); + set_dma_mode(chan, mode); + set_dma_addr(chan, phyaddr); + set_dma_count(chan, count + 31); + enable_dma(chan); + release_dma_lock(flags); +} + +static irqreturn_t jz_mmc_dma_rx_callback(int irq, void *devid) +{ + int chan = rxdmachan; + + disable_dma(chan); + if (__dmac_channel_address_error_detected(chan)) { + printk(KERN_DEBUG "%s: DMAC address error.\n", + __FUNCTION__); + __dmac_channel_clear_address_error(chan); + } + if (__dmac_channel_transmit_end_detected(chan)) { + __dmac_channel_clear_transmit_end(chan); + } + return IRQ_HANDLED; +} +static irqreturn_t jz_mmc_dma_tx_callback(int irq, void *devid) +{ + int chan = txdmachan; + + disable_dma(chan); + if (__dmac_channel_address_error_detected(chan)) { + printk(KERN_DEBUG "%s: DMAC address error.\n", + __FUNCTION__); + __dmac_channel_clear_address_error(chan); + } + if (__dmac_channel_transmit_end_detected(chan)) { + __dmac_channel_clear_transmit_end(chan); + } + return IRQ_HANDLED; +} + +/* Prepare DMA to start data transfer from the MMC card */ +static void jz_mmc_rx_setup_data(struct jz_mmc_host *host, + struct mmc_data *data) +{ + unsigned int nob = data->blocks; + int channelrx = rxdmachan; + int i; + u32 size; + + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + REG_MSC_NOB = nob; + REG_MSC_BLKLEN = data->blksz; + size = nob * data->blksz; + + if (data->flags & MMC_DATA_READ) { + host->dma.dir = DMA_FROM_DEVICE; + } else { + host->dma.dir = DMA_TO_DEVICE; + } + + host->dma.len = + dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + host->dma.dir); + + for (i = 0; i < host->dma.len; i++) { + host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); + host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); + dma_cache_wback_inv((unsigned long) + CKSEG0ADDR(sg_dma_address(data->sg)) + + data->sg->offset, + host->sg_cpu[i].dcmd); + jz_mmc_start_dma(channelrx, host->sg_cpu[i].dtadr, + host->sg_cpu[i].dcmd, DMA_MODE_READ); + } +} + +/* Prepare DMA to start data transfer from the MMC card */ +static void jz_mmc_tx_setup_data(struct jz_mmc_host *host, + struct mmc_data *data) +{ + unsigned int nob = data->blocks; + int channeltx = txdmachan; + int i; + u32 size; + + if (data->flags & MMC_DATA_STREAM) + nob = 0xffff; + + REG_MSC_NOB = nob; + REG_MSC_BLKLEN = data->blksz; + size = nob * data->blksz; + + if (data->flags & MMC_DATA_READ) { + host->dma.dir = DMA_FROM_DEVICE; + } else { + host->dma.dir = DMA_TO_DEVICE; + } + + host->dma.len = + dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + host->dma.dir); + + for (i = 0; i < host->dma.len; i++) { + host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]); + host->sg_cpu[i].dcmd = sg_dma_len(&data->sg[i]); + dma_cache_wback_inv((unsigned long) + CKSEG0ADDR(sg_dma_address(data->sg)) + + data->sg->offset, + host->sg_cpu[i].dcmd); + jz_mmc_start_dma(channeltx, host->sg_cpu[i].dtadr, + host->sg_cpu[i].dcmd, DMA_MODE_WRITE); + } +} +#else +static void jz_mmc_receive_pio(struct jz_mmc_host *host) +{ + + struct mmc_data *data = 0; + int sg_len = 0, max = 0, count = 0; + u32 *buf = 0; + struct scatterlist *sg; + unsigned int nob; + + data = host->mrq->data; + nob = data->blocks; + REG_MSC_NOB = nob; + REG_MSC_BLKLEN = data->blksz; + + max = host->pio.len; + if (host->pio.index < host->dma.len) { + sg = &data->sg[host->pio.index]; + buf = sg_virt(sg) + host->pio.offset; + + /* This is the space left inside the buffer */ + sg_len = sg_dma_len(&data->sg[host->pio.index]) - host->pio.offset; + /* Check to if we need less then the size of the sg_buffer */ + if (sg_len < max) max = sg_len; + } + max = max / 4; + for(count = 0; count < max; count++) { + while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY) + ; + *buf++ = REG_MSC_RXFIFO; + } + host->pio.len -= count; + host->pio.offset += count; + + if (sg_len && count == sg_len) { + host->pio.index++; + host->pio.offset = 0; + } +} + +static void jz_mmc_send_pio(struct jz_mmc_host *host) +{ + + struct mmc_data *data = 0; + int sg_len, max, count = 0; + u32 *wbuf = 0; + struct scatterlist *sg; + unsigned int nob; + + data = host->mrq->data; + nob = data->blocks; + + REG_MSC_NOB = nob; + REG_MSC_BLKLEN = data->blksz; + + /* This is the pointer to the data buffer */ + sg = &data->sg[host->pio.index]; + wbuf = sg_virt(sg) + host->pio.offset; + + /* This is the space left inside the buffer */ + sg_len = data->sg[host->pio.index].length - host->pio.offset; + + /* Check to if we need less then the size of the sg_buffer */ + max = (sg_len > host->pio.len) ? host->pio.len : sg_len; + max = max / 4; + for(count = 0; count < max; count++ ) { + while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL) + ; + REG_MSC_TXFIFO = *wbuf++; + } + + host->pio.len -= count; + host->pio.offset += count; + + if (count == sg_len) { + host->pio.index++; + host->pio.offset = 0; + } +} + +static int +jz_mmc_prepare_data(struct jz_mmc_host *host, struct mmc_data *data) +{ + int datalen = data->blocks * data->blksz; + + host->dma.dir = DMA_BIDIRECTIONAL; + host->dma.len = dma_map_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, host->dma.dir); + if (host->dma.len == 0) + return -ETIMEDOUT; + + host->pio.index = 0; + host->pio.offset = 0; + host->pio.len = datalen; + return 0; +} +#endif + +static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat); + +static void jz_mmc_finish_request(struct jz_mmc_host *host, struct mmc_request *mrq) +{ + jz_mmc_stop_clock(); + host->mrq = NULL; + host->cmd = NULL; + host->data = NULL; + mmc_request_done(host->mmc, mrq); +} + +static void jz_mmc_start_cmd(struct jz_mmc_host *host, + struct mmc_command *cmd, unsigned int cmdat) +{ + u32 timeout = 0x3fffff; + unsigned int stat; + struct jz_mmc_host *hst = host; + WARN_ON(host->cmd != NULL); + host->cmd = cmd; + + /* stop MMC clock */ + jz_mmc_stop_clock(); + + /* mask interrupts */ + REG_MSC_IMASK = 0xff; + + /* clear status */ + REG_MSC_IREG = 0xff; + + if (cmd->flags & MMC_RSP_BUSY) + cmdat |= MSC_CMDAT_BUSY; + +#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE)) + switch (RSP_TYPE(mmc_resp_type(cmd))) { + case RSP_TYPE(MMC_RSP_R1): /* r1,r1b, r6, r7 */ + cmdat |= MSC_CMDAT_RESPONSE_R1; + r_type = 1; + break; + case RSP_TYPE(MMC_RSP_R3): + cmdat |= MSC_CMDAT_RESPONSE_R3; + r_type = 1; + break; + case RSP_TYPE(MMC_RSP_R2): + cmdat |= MSC_CMDAT_RESPONSE_R2; + r_type = 2; + break; + default: + break; + } + REG_MSC_CMD = cmd->opcode; + + /* Set argument */ +#ifdef CONFIG_JZ_MMC_BUS_1 + if (cmd->opcode == 6) { + /* set 1 bit sd card bus*/ + if (cmd->arg ==2) + REG_MSC_ARG = 0; + + /* set 1 bit mmc card bus*/ + if (cmd->arg == 0x3b70101) + REG_MSC_ARG = 0x3b70001; + } else + REG_MSC_ARG = cmd->arg; +#else + REG_MSC_ARG = cmd->arg; +#endif + + /* Set command */ + REG_MSC_CMDAT = cmdat; + + /* Send command */ + jz_mmc_start_clock(); + + while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES)) + ; + + REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear irq flag */ + if (cmd->opcode == 12) { + while (timeout-- && !(REG_MSC_IREG & MSC_IREG_PRG_DONE)) + ; + REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */ + } + if (!mmc_slot_enable) { + /* It seems that MSC can't report the MSC_STAT_TIME_OUT_RES when + * card was removed. We force to return here. + */ + cmd->error = -ETIMEDOUT; + jz_mmc_finish_request(hst, hst->mrq); + return; + } + + if (SD_IO_SEND_OP_COND == cmd->opcode) { + /* + * Don't support SDIO card currently. + */ + cmd->error = -ETIMEDOUT; + jz_mmc_finish_request(hst, hst->mrq); + return; + } + + /* Check for status */ + stat = REG_MSC_STAT; + jz_mmc_cmd_done(hst, stat); + if (host->data) { + if (cmd->opcode == MMC_WRITE_BLOCK || cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) +#ifdef USE_DMA + jz_mmc_tx_setup_data(host, host->data); +#else + jz_mmc_send_pio(host); + else + jz_mmc_receive_pio(host); +#endif + } +} + +static int jz_mmc_cmd_done(struct jz_mmc_host *host, unsigned int stat) +{ + struct mmc_command *cmd = host->cmd; + int i, temp[16]; + u8 *buf; + u32 data, v, w1, w2; + + if (!cmd) + return 0; + + host->cmd = NULL; + buf = (u8 *) temp; + switch (r_type) { + case 1: + { + data = REG_MSC_RES; + buf[0] = (data >> 8) & 0xff; + buf[1] = data & 0xff; + data = REG_MSC_RES; + buf[2] = (data >> 8) & 0xff; + buf[3] = data & 0xff; + data = REG_MSC_RES; + buf[4] = data & 0xff; + cmd->resp[0] = + buf[1] << 24 | buf[2] << 16 | buf[3] << 8 | + buf[4]; + break; + } + case 2: + { + data = REG_MSC_RES; + v = data & 0xffff; + for (i = 0; i < 4; i++) { + data = REG_MSC_RES; + w1 = data & 0xffff; + data = REG_MSC_RES; + w2 = data & 0xffff; + cmd->resp[i] = v << 24 | w1 << 8 | w2 >> 8; + v = w2; + } + break; + } + case 0: + break; + } + if (stat & MSC_STAT_TIME_OUT_RES) { + printk("MSC_STAT_TIME_OUT_RES\n"); + cmd->error = -ETIMEDOUT; + } else if (stat & MSC_STAT_CRC_RES_ERR && cmd->flags & MMC_RSP_CRC) { + printk("MSC_STAT_CRC\n"); + if (cmd->opcode == MMC_ALL_SEND_CID || + cmd->opcode == MMC_SEND_CSD || + cmd->opcode == MMC_SEND_CID) { + /* a bogus CRC error can appear if the msb of + the 15 byte response is a one */ + if ((cmd->resp[0] & 0x80000000) == 0) + cmd->error = -EILSEQ; + } + } + /* + * Did I mention this is Sick. We always need to + * discard the upper 8 bits of the first 16-bit word. + */ + if (host->data && cmd->error == 0) + jz_mmc_enable_irq(host, MSC_IMASK_DATA_TRAN_DONE); + else + jz_mmc_finish_request(host, host->mrq); + + return 1; +} + +static int jz_mmc_data_done(struct jz_mmc_host *host, unsigned int stat) +{ + struct mmc_data *data = host->data; + + if (!data) + return 0; + REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */ + jz_mmc_stop_clock(); + dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len, + host->dma_dir); + if (stat & MSC_STAT_TIME_OUT_READ) { + printk("MMC/SD timeout, MMC_STAT 0x%x\n", stat); + data->error = -ETIMEDOUT; + } else if (REG_MSC_STAT & + (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR)) { + printk("MMC/SD CRC error, MMC_STAT 0x%x\n", stat); + data->error = -EILSEQ; + } + /* + * There appears to be a hardware design bug here. There seems to + * be no way to find out how much data was transferred to the card. + * This means that if there was an error on any block, we mark all + * data blocks as being in error. + */ + if (data->error == 0) + data->bytes_xfered = data->blocks * data->blksz; + else + data->bytes_xfered = 0; + + jz_mmc_disable_irq(host, MSC_IMASK_DATA_TRAN_DONE); + host->data = NULL; + if (host->mrq->stop) { + jz_mmc_stop_clock(); + jz_mmc_start_cmd(host, host->mrq->stop, 0); + } else { + jz_mmc_finish_request(host, host->mrq); + } + return 1; +} + +static void jz_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) +{ + struct jz_mmc_host *host = mmc_priv(mmc); + unsigned int cmdat; + + /* stop MMC clock */ + jz_mmc_stop_clock(); + + /* Save current request for the future processing */ + host->mrq = mrq; + host->data = mrq->data; + cmdat = host->cmdat; + host->cmdat &= ~MSC_CMDAT_INIT; + + if (mrq->data) { + cmdat &= ~MSC_CMDAT_BUSY; +#ifdef USE_DMA + if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) + + cmdat |= + MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; + else { +#ifdef CONFIG_JZ_MMC_BUS_1 + cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN | + MSC_CMDAT_DMA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_DMA_EN; +#endif + } + if (mrq->data->flags & MMC_DATA_WRITE) + cmdat |= MSC_CMDAT_WRITE; + + if (mrq->data->flags & MMC_DATA_STREAM) + cmdat |= MSC_CMDAT_STREAM_BLOCK; + if (mrq->cmd->opcode != MMC_WRITE_BLOCK + && mrq->cmd->opcode != MMC_WRITE_MULTIPLE_BLOCK) + jz_mmc_rx_setup_data(host, mrq->data); +#else /*USE_DMA*/ + + if ((mrq->cmd->opcode == 51) | (mrq->cmd->opcode == 8) | (mrq->cmd->opcode == 6)) + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; + else { +#ifdef CONFIG_JZ_MMC_BUS_1 + cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; + cmdat |= MSC_CMDAT_BUS_WIDTH_1BIT | MSC_CMDAT_DATA_EN; +#else + cmdat |= MSC_CMDAT_DATA_EN; +#endif + } + if (mrq->data->flags & MMC_DATA_WRITE) + cmdat |= MSC_CMDAT_WRITE; + + if (mrq->data->flags & MMC_DATA_STREAM) + cmdat |= MSC_CMDAT_STREAM_BLOCK; + jz_mmc_prepare_data(host, host->data); +#endif /*USE_DMA*/ + } + jz_mmc_start_cmd(host, mrq->cmd, cmdat); +} + +static irqreturn_t jz_mmc_irq(int irq, void *devid) +{ + struct jz_mmc_host *host = devid; + unsigned int ireg; + int handled = 0; + + ireg = REG_MSC_IREG; + + if (ireg) { + unsigned stat = REG_MSC_STAT; + if (ireg & MSC_IREG_DATA_TRAN_DONE) + handled |= jz_mmc_data_done(host, stat); + } + return IRQ_RETVAL(handled); +} + +/* Returns true if MMC slot is empty */ +static int jz_mmc_slot_is_empty(int slot) +{ + int empty; + + empty = (__msc_card_detected(slot) == 0) ? 1 : 0; + + if (empty) { + /* wait for card insertion */ +#ifdef CONFIG_MIPS_JZ4740_LYRA + __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); +#else + __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); +#endif + } else { + /* wait for card removal */ +#ifdef CONFIG_MIPS_JZ4740_LYRA + __gpio_as_irq_fall_edge(MSC_HOTPLUG_PIN); +#else + __gpio_as_irq_rise_edge(MSC_HOTPLUG_PIN); +#endif + } + + return empty; +} + +static irqreturn_t jz_mmc_detect_irq(int irq, void *devid) +{ + struct jz_mmc_host *host = (struct jz_mmc_host *) devid; + + if (jz_mmc_slot_is_empty(0)) { + mmc_slot_enable = 0; + mmc_detect_change(host->mmc, 50); + } else { + mmc_slot_enable = 1; + mmc_detect_change(host->mmc, 50); + } + return IRQ_HANDLED; +} + +static int jz_mmc_get_ro(struct mmc_host *mmc) +{ + struct jz_mmc_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->get_ro) + return host->pdata->get_ro(mmc_dev(mmc)); + /* Host doesn't support read only detection so assume writeable */ + return 0; +} + +/* set clock and power */ +static void jz_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) +{ + struct jz_mmc_host *host = mmc_priv(mmc); + + if (ios->clock) + jz_mmc_set_clock(ios->clock); + else + jz_mmc_stop_clock(); + + if (host->power_mode != ios->power_mode) { + host->power_mode = ios->power_mode; + + if (ios->power_mode == MMC_POWER_ON) + host->cmdat |= CMDAT_INIT; + } + + if ((ios->bus_width == MMC_BUS_WIDTH_4) || (ios->bus_width == MMC_BUS_WIDTH_8)) + host->cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT; + else + host->cmdat &= ~MSC_CMDAT_BUS_WIDTH_4BIT; +} + +static const struct mmc_host_ops jz_mmc_ops = { + .request = jz_mmc_request, + .get_ro = jz_mmc_get_ro, + .set_ios = jz_mmc_set_ios, +}; + +static int jz_mmc_probe(struct platform_device *pdev) +{ + int retval; + struct mmc_host *mmc; + struct jz_mmc_host *host = NULL; + int irq; + struct resource *r; + + __gpio_as_msc(); + __msc_init_io(); + __msc_enable_power(); + + __msc_reset(); + + /* On reset, stop MMC clock */ + jz_mmc_stop_clock(); + + MMC_IRQ_MASK(); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + irq = platform_get_irq(pdev, 0); + if (!r || irq < 0) + return -ENXIO; + + r = request_mem_region(r->start, SZ_4K, DRIVER_NAME); + if (!r) + return -EBUSY; + + mmc = mmc_alloc_host(sizeof(struct jz_mmc_host), &pdev->dev); + if (!mmc) { + retval = -ENOMEM; + goto out; + } + mmc->ops = &jz_mmc_ops; + mmc->f_min = MMC_CLOCK_SLOW; + mmc->f_max = SD_CLOCK_FAST; + /* + * We can do SG-DMA, but we don't because we never know how much + * data we successfully wrote to the card. + */ + mmc->max_phys_segs = NR_SG; + /* + * Our hardware DMA can handle a maximum of one page per SG entry. + */ + mmc->max_seg_size = PAGE_SIZE; + /* + * Block length register is 10 bits. + */ + mmc->max_blk_size = 1023; + /* + * Block count register is 16 bits. + */ + mmc->max_blk_count = 65535; + host = mmc_priv(mmc); + host->mmc = mmc; + host->pdata = pdev->dev.platform_data; + mmc->ocr_avail = host->pdata ? + host->pdata->ocr_mask : MMC_VDD_32_33 | MMC_VDD_33_34; + host->mmc->caps = + MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED + | MMC_CAP_MMC_HIGHSPEED; + /* + *MMC_CAP_4_BIT_DATA (1 << 0) The host can do 4 bit transfers + * + */ + host->sg_cpu = + dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, + GFP_KERNEL); + if (!host->sg_cpu) { + retval = -ENOMEM; + goto out; + } + spin_lock_init(&host->lock); + host->irq = JZ_IRQ_MSC; + host->imask = 0xff; + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + retval = request_irq(JZ_IRQ_MSC, jz_mmc_irq, 0, "MMC/SD", host); + if (retval) { + printk(KERN_ERR "MMC/SD: can't request MMC/SD IRQ\n"); + return retval; + } + jz_mmc_slot_is_empty(0); + /* Request card detect interrupt */ + + retval = request_irq(MSC_HOTPLUG_IRQ, jz_mmc_detect_irq, 0, //SA_INTERRUPT, + "MMC card detect", host); + if (retval) { + printk(KERN_ERR "MMC/SD: can't request card detect IRQ\n"); + goto err1; + } +#ifdef USE_DMA + /* Request MMC Rx DMA channel */ + rxdmachan = + jz_request_dma(DMA_ID_MSC_RX, "MMC Rx", jz_mmc_dma_rx_callback, + 0, host); + if (rxdmachan < 0) { + printk(KERN_ERR "jz_request_dma failed for MMC Rx\n"); + goto err2; + } + + /* Request MMC Tx DMA channel */ + txdmachan = + jz_request_dma(DMA_ID_MSC_TX, "MMC Tx", jz_mmc_dma_tx_callback, + 0, host); + if (txdmachan < 0) { + printk(KERN_ERR "jz_request_dma failed for MMC Tx\n"); + goto err3; + } +#endif + platform_set_drvdata(pdev, mmc); + mmc_add_host(mmc); + printk("JZ SD/MMC card driver registered\n"); + + /* Detect card during initialization */ +#ifdef CONFIG_SOC_JZ4740 + if (!jz_mmc_slot_is_empty(0)) { + mmc_slot_enable = 1; + mmc_detect_change(host->mmc, 0); + } +#endif + return 0; + +err1:free_irq(JZ_IRQ_MSC, &host); +#ifdef USE_DMA + err2:jz_free_dma(rxdmachan); + err3:jz_free_dma(txdmachan); +#endif +out: + if (host) { + if (host->sg_cpu) + dma_free_coherent(&pdev->dev, PAGE_SIZE, + host->sg_cpu, host->sg_dma); + } + if (mmc) + mmc_free_host(mmc); + return -1; +} + +static int jz_mmc_remove(struct platform_device *pdev) +{ + struct mmc_host *mmc = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + if (mmc) { + struct jz_mmc_host *host = mmc_priv(mmc); + + if (host->pdata && host->pdata->exit) + host->pdata->exit(&pdev->dev, mmc); + + mmc_remove_host(mmc); + + jz_mmc_stop_clock(); + __msc_disable_power(); + jz_free_dma(rxdmachan); + jz_free_dma(txdmachan); + free_irq(JZ_IRQ_MSC, host); + mmc_free_host(mmc); + } + return 0; +} + +#ifdef CONFIG_PM +pm_message_t state; +static int jz_mmc_suspend(struct platform_device *dev, pm_message_t state) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret = 0; + + __msc_disable_power(); + if (mmc) + ret = mmc_suspend_host(mmc, state); + + return ret; +} + +static int jz_mmc_resume(struct platform_device *dev) +{ + struct mmc_host *mmc = platform_get_drvdata(dev); + int ret = 0; +#if 0 + /*for sandisk BB0807011816D and other strange cards*/ + int i; + + for(i = 104; i < 110; i++) + __gpio_as_input(i); + + /* perhaps you should mdelay more */ + mdelay(1000); + __gpio_as_msc(); +#endif + __msc_init_io(); + __msc_enable_power(); + __msc_reset(); + + if (!jz_mmc_slot_is_empty(0)) { + mmc_slot_enable = 1; + mmc_detect_change(mmc, 10); + } + + if (mmc) + ret = mmc_resume_host(mmc); + + return ret; +} +#else +#define jz_mmc_suspend NULL +#define jz_mmc_resume NULL +#endif + +static struct platform_driver jz_mmc_driver = { + .probe = jz_mmc_probe, + .remove = jz_mmc_remove, + .suspend = jz_mmc_suspend, + .resume = jz_mmc_resume, + .driver = { + .name = DRIVER_NAME, + }, +}; + +static int __init jz_mmc_init(void) +{ + return platform_driver_register(&jz_mmc_driver); +} + +static void __exit jz_mmc_exit(void) +{ + platform_driver_unregister(&jz_mmc_driver); +} + +module_init(jz_mmc_init); +module_exit(jz_mmc_exit); + +MODULE_DESCRIPTION("JZ47XX SD/Multimedia Card Interface Driver"); +MODULE_LICENSE("GPL"); diff -ruN linux-2.6.31-vanilla/drivers/mmc/host/jz_mmc.h linux-2.6.31/drivers/mmc/host/jz_mmc.h --- linux-2.6.31-vanilla/drivers/mmc/host/jz_mmc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/mmc/host/jz_mmc.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,65 @@ +#ifndef __JZ_MMC_H__ +#define __JZ_MMC_H__ + +#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ +#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ +#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */ +#define MMC_NO_ERROR 0 +/* Extra MMC commands for state control */ +/* Use negative numbers to disambiguate */ +#define MMC_CIM_RESET -1 +#define MMC_SET_CLOCK 100 + +typedef struct jzsoc_dma_desc { + volatile u32 ddadr; /* Points to the next descriptor + flags */ + volatile u32 dsadr; /* DSADR value for the current transfer */ + volatile u32 dtadr; /* DTADR value for the current transfer */ + volatile u32 dcmd; /* DCMD value for the current transfer */ +} jzsoc_dma_desc; + + + + +#include + +struct device; +struct mmc_host; + +struct jz_mmc_platform_data { + unsigned int ocr_mask; /* available voltages */ + unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */ + int (*init)(struct device *, irq_handler_t , void *); + int (*get_ro)(struct device *); + void (*setpower)(struct device *, unsigned int); + void (*exit)(struct device *, void *); +}; + +//extern void pxa_set_mci_info(struct pxamci_platform_data *info); + + + +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + + +#endif /* __JZ_MMC_H__ */ diff -ruN linux-2.6.31-vanilla/drivers/mtd/nand/jz4740_nand.c linux-2.6.31/drivers/mtd/nand/jz4740_nand.c --- linux-2.6.31-vanilla/drivers/mtd/nand/jz4740_nand.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/mtd/nand/jz4740_nand.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC NAND controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#define JZ_REG_NAND_CTRL 0x50 +#define JZ_REG_NAND_ECC_CTRL 0x100 +#define JZ_REG_NAND_DATA 0x104 +#define JZ_REG_NAND_PAR0 0x108 +#define JZ_REG_NAND_PAR1 0x10C +#define JZ_REG_NAND_PAR2 0x110 +#define JZ_REG_NAND_IRQ_STAT 0x114 +#define JZ_REG_NAND_IRQ_CTRL 0x118 +#define JZ_REG_NAND_ERR(x) (0x11C + (x << 2)) + +#define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) +#define JZ_NAND_ECC_CTRL_ENCODING BIT(3) +#define JZ_NAND_ECC_CTRL_RS BIT(2) +#define JZ_NAND_ECC_CTRL_RESET BIT(1) +#define JZ_NAND_ECC_CTRL_ENABLE BIT(0) + +#define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) +#define JZ_NAND_STATUS_PAD_FINISH BIT(4) +#define JZ_NAND_STATUS_DEC_FINISH BIT(3) +#define JZ_NAND_STATUS_ENC_FINISH BIT(2) +#define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) +#define JZ_NAND_STATUS_ERROR BIT(0) + +#define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT(x << 1) +#define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT((x << 1) + 1) + +#define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000) +#define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000) +#define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000) + +struct jz_nand { + struct mtd_info mtd; + struct nand_chip chip; + void __iomem *base; + struct resource *mem; + + struct jz_nand_platform_data *pdata; +}; + +static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) +{ + return container_of(mtd, struct jz_nand, mtd); +} + +static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + struct nand_chip *chip = mtd->priv; + uint32_t reg; + + if (ctrl & NAND_CTRL_CHANGE) { + BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); + if (ctrl & NAND_ALE) + chip->IO_ADDR_W = JZ_NAND_ADDR_ADDR; + else if (ctrl & NAND_CLE) + chip->IO_ADDR_W = JZ_NAND_CMD_ADDR; + else + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR; + + reg = readl(nand->base + JZ_REG_NAND_CTRL); + if ( ctrl & NAND_NCE ) + reg |= JZ_NAND_CTRL_ASSERT_CHIP(0); + else + reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(0); + writel(reg, nand->base + JZ_REG_NAND_CTRL); + } + if (dat != NAND_CMD_NONE) + writeb(dat, chip->IO_ADDR_W); +} + +static int jz_nand_dev_ready(struct mtd_info *mtd) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + return gpio_get_value_cansleep(nand->pdata->busy_gpio); +} + +static void jz_nand_hwctl(struct mtd_info *mtd, int mode) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + uint32_t reg; + + + writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + + reg |= JZ_NAND_ECC_CTRL_RESET; + reg |= JZ_NAND_ECC_CTRL_ENABLE; + reg |= JZ_NAND_ECC_CTRL_RS; + + switch(mode) { + case NAND_ECC_READ: + reg &= ~JZ_NAND_ECC_CTRL_ENCODING; + break; + case NAND_ECC_WRITE: + reg |= JZ_NAND_ECC_CTRL_ENCODING; + break; + default: + break; + } + + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); +} + +static int jz_nand_calculate_ecc_rs(struct mtd_info* mtd, const uint8_t* dat, + uint8_t *ecc_code) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + uint32_t reg, status; + int i; + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while(!(status & JZ_NAND_STATUS_ENC_FINISH)); + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + for (i = 0; i < 9; ++i) { + ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); + } + + return 0; +} + +static void correct_data(uint8_t *dat, int index, int mask) +{ + int offset = index & 0x7; + uint16_t data; + printk("correct: "); + + index += (index >> 3); + + data = dat[index]; + data |= dat[index+1] << 8; + + printk("0x%x -> ", data); + + mask ^= (data >> offset) & 0x1ff; + data &= ~(0x1ff << offset); + data |= (mask << offset); + + printk("0x%x\n", data); + + dat[index] = data & 0xff; + dat[index+1] = (data >> 8) & 0xff; +} + +static int jz_nand_correct_ecc_rs(struct mtd_info* mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + struct jz_nand *nand = mtd_to_jz_nand(mtd); + int i, error_count, index; + uint32_t reg, status, error; + + for(i = 0; i < 9; ++i) { + if (read_ecc[i] != 0xff) + break; + } + if (i == 9) { + for (i = 0; i < nand->chip.ecc.size; ++i) { + if (dat[i] != 0xff) + break; + } + if (i == nand->chip.ecc.size) + return 0; + } + + for(i = 0; i < 9; ++i) + writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg |= JZ_NAND_ECC_CTRL_PAR_READY; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + do { + status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); + } while (!(status & JZ_NAND_STATUS_DEC_FINISH)); + + reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); + reg &= ~JZ_NAND_ECC_CTRL_ENABLE; + writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); + + if (status & JZ_NAND_STATUS_ERROR) { + if (status & JZ_NAND_STATUS_UNCOR_ERROR) { + printk("uncorrectable ecc:"); + for(i = 0; i < 9; ++i) + printk(" 0x%x", read_ecc[i]); + printk("\n"); + printk("uncorrectable data:"); + for(i = 0; i < 32; ++i) + printk(" 0x%x", dat[i]); + printk("\n"); + return -1; + } + + error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; + + printk("error_count: %d %x\n", error_count, status); + + for(i = 0; i < error_count; ++i) { + error = readl(nand->base + JZ_REG_NAND_ERR(i)); + index = ((error >> 16) & 0x1ff) - 1; + if (index >= 0 && index < 512) { + correct_data(dat, index, error & 0x1ff); + } + } + + return error_count; + } + + return 0; +} + + + +#ifdef CONFIG_MTD_CMDLINE_PARTS +static const char *part_probes[] = {"cmdline", NULL}; +#endif + +static int __devinit jz_nand_probe(struct platform_device *pdev) +{ + int ret; + struct jz_nand *nand; + struct nand_chip *chip; + struct mtd_info *mtd; + struct jz_nand_platform_data *pdata = pdev->dev.platform_data; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *partition_info; + int num_partitions = 0; +#endif + + nand = kzalloc(sizeof(*nand), GFP_KERNEL); + if (!nand) { + dev_err(&pdev->dev, "Failed to allocate device structure.\n"); + return -ENOMEM; + } + + nand->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!nand->mem) { + dev_err(&pdev->dev, "Failed to get platform mmio memory\n"); + ret = -ENOENT; + goto err_free; + } + + nand->mem = request_mem_region(nand->mem->start, resource_size(nand->mem), + pdev->name); + + if (!nand->mem) { + dev_err(&pdev->dev, "Failed to request mmio memory region\n"); + ret = -EBUSY; + goto err_free; + } + + nand->base = ioremap(nand->mem->start, resource_size(nand->mem)); + + if (!nand->base) { + dev_err(&pdev->dev, "Faild to ioremap mmio memory region\n"); + ret = -EBUSY; + goto err_release_mem; + } + + if (pdata && gpio_is_valid(pdata->busy_gpio)) { + ret = gpio_request(pdata->busy_gpio, "jz nand busy line"); + if (ret) { + dev_err(&pdev->dev, "Failed to request busy gpio %d: %d\n", + pdata->busy_gpio, ret); + goto err_iounmap; + } + } + + mtd = &nand->mtd; + chip = &nand->chip; + mtd->priv = chip; + mtd->owner = THIS_MODULE; + mtd->name = "jz4740-nand"; + + chip->ecc.hwctl = jz_nand_hwctl; + + chip->ecc.calculate = jz_nand_calculate_ecc_rs; + chip->ecc.correct = jz_nand_correct_ecc_rs; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 512; + chip->ecc.bytes = 9; + if (pdata) + chip->ecc.layout = pdata->ecc_layout; + + chip->chip_delay = 50; + chip->cmd_ctrl = jz_nand_cmd_ctrl; + + if (pdata && gpio_is_valid(pdata->busy_gpio)) + chip->dev_ready = jz_nand_dev_ready; + + chip->IO_ADDR_R = JZ_NAND_DATA_ADDR; + chip->IO_ADDR_W = JZ_NAND_DATA_ADDR; + + nand->pdata = pdata; + platform_set_drvdata(pdev, nand); + + ret = nand_scan_ident(mtd, 1); + if (ret) { + dev_err(&pdev->dev, "Failed to scan nand\n"); + goto err_gpio_free; + } + + if (pdata && pdata->ident_callback) { + pdata->ident_callback(pdev, chip, &pdata->partitions, &pdata->num_partitions); + } + + ret = nand_scan_tail(mtd); + if (ret) { + dev_err(&pdev->dev, "Failed to scan nand\n"); + goto err_gpio_free; + } + +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + num_partitions = parse_mtd_partitions(mtd, part_probes, + &partition_info, 0); +#endif + if (num_partitions <= 0 && pdata) { + num_partitions = pdata->num_partitions; + partition_info = pdata->partitions; + } + + if (num_partitions > 0) + ret = add_mtd_partitions(mtd, partition_info, num_partitions); + else +#endif + ret = add_mtd_device(mtd); + + if (ret) { + dev_err(&pdev->dev, "Failed to add mtd device\n"); + goto err_nand_release; + } + + dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); + + return 0; +err_nand_release: + nand_release(&nand->mtd); +err_gpio_free: + platform_set_drvdata(pdev, NULL); + gpio_free(pdata->busy_gpio); +err_iounmap: + iounmap(nand->base); +err_release_mem: + release_mem_region(nand->mem->start, resource_size(nand->mem)); +err_free: + kfree(nand); + return ret; +} + +static void __devexit jz_nand_remove(struct platform_device *pdev) +{ + struct jz_nand *nand = platform_get_drvdata(pdev); + + nand_release(&nand->mtd); + + iounmap(nand->base); + + release_mem_region(nand->mem->start, resource_size(nand->mem)); + + platform_set_drvdata(pdev, NULL); + kfree(nand); +} + +struct platform_driver jz_nand_driver = { + .probe = jz_nand_probe, + .remove = __devexit_p(jz_nand_probe), + .driver = { + .name = "jz4740-nand", + .owner = THIS_MODULE, + }, +}; + +static int __init jz_nand_init(void) +{ + return platform_driver_register(&jz_nand_driver); +} +module_init(jz_nand_init); + +static void __exit jz_nand_exit(void) +{ + platform_driver_unregister(&jz_nand_driver); +} +module_exit(jz_nand_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("NAND controller driver for JZ4720/JZ4740 SoC"); +MODULE_ALIAS("platform:jz4740-nand"); +MODULE_ALIAS("platform:jz4720-nand"); diff -ruN linux-2.6.31-vanilla/drivers/power/jz4740-battery.c linux-2.6.31/drivers/power/jz4740-battery.c --- linux-2.6.31-vanilla/drivers/power/jz4740-battery.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/power/jz4740-battery.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,471 @@ +/* + * Battery measurement code for Ingenic JZ SOC. + * + * based on tosa_battery.c + * + * Copyright (C) 2008 Marek Vasut + * Copyright (C) 2009 Jiejing Zhang + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct jz_battery_info { + struct power_supply usb; + struct power_supply bat; + struct power_supply ac; + int bat_status; + struct jz_batt_info *pdata; + struct mutex work_lock; + struct workqueue_struct *monitor_wqueue; + struct delayed_work bat_work; +}; + +#define ps_to_jz_battery(x) container_of((x), struct jz_battery_info, bat); + +/********************************************************************* + * Power + *********************************************************************/ + + +static int jz_get_power_prop(struct jz_battery_info *bat_info, + struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int gpio; + + if (bat_info == 0 || bat_info->pdata == 0) + return -EINVAL; + gpio = (psy->type == POWER_SUPPLY_TYPE_MAINS) ? + bat_info->pdata->dc_dect_gpio : + bat_info->pdata->usb_dect_gpio; + if (!gpio_is_valid(gpio)) + return -EINVAL; + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !gpio_get_value(gpio); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int jz_usb_get_power_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct jz_battery_info *bat_info = container_of(psy, struct jz_battery_info, usb); + return jz_get_power_prop(bat_info, psy, psp, val); +} + +static int jz_ac_get_power_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct jz_battery_info *bat_info = container_of(psy, struct jz_battery_info, ac); + return jz_get_power_prop(bat_info, psy, psp, val); +} + + +static enum power_supply_property jz_power_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static struct power_supply jz_ac = { + .name = "ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = jz_power_props, + .num_properties = ARRAY_SIZE(jz_power_props), + .get_property = jz_ac_get_power_prop, +}; + +static struct power_supply jz_usb = { + .name = "usb", + .type = POWER_SUPPLY_TYPE_USB, + .properties = jz_power_props, + .num_properties = ARRAY_SIZE(jz_power_props), + .get_property = jz_usb_get_power_prop, +}; + + +/********************************************************************* + * Battery properties + *********************************************************************/ + +static long jz_read_bat(struct power_supply *psy) +{ + struct jz_battery_info *bat_info = ps_to_jz_battery(psy); + enum jz_adc_battery_scale scale; + + if (bat_info->pdata->max_voltag > 2500000) + scale = JZ_ADC_BATTERY_SCALE_7V5; + else + scale = JZ_ADC_BATTERY_SCALE_2V5; + + return jz4740_adc_read_battery_voltage(psy->dev->parent->parent, scale); +} + +static int jz_bat_get_capacity(struct power_supply *psy) +{ + int ret; + struct jz_battery_info *bat_info = ps_to_jz_battery(psy); + + ret = jz_read_bat(psy); + + if (ret < 0) + return ret; + + ret = (ret - bat_info->pdata->min_voltag) * 100 + / (bat_info->pdata->max_voltag - bat_info->pdata->min_voltag); + + if (ret > 100) + ret = 100; + else if (ret < 0) + ret = 0; + + return ret; +} + +static int jz_bat_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct jz_battery_info *bat_info = ps_to_jz_battery(psy) + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = bat_info->bat_status; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = bat_info->pdata->batt_tech; + break; + case POWER_SUPPLY_PROP_HEALTH: + if(jz_read_bat(psy) < bat_info->pdata->min_voltag) { + dev_dbg(psy->dev, "%s: battery is dead," + "voltage too low!\n", __func__); + val->intval = POWER_SUPPLY_HEALTH_DEAD; + } else { + dev_dbg(psy->dev, "%s: battery is good," + "voltage normal.\n", __func__); + val->intval = POWER_SUPPLY_HEALTH_GOOD; + } + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = jz_bat_get_capacity(psy); + dev_dbg(psy->dev, "%s: battery_capacity = %d\n", + __func__, val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = jz_read_bat(psy); + if (val->intval < 0) + return val->intval; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX: + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = bat_info->pdata->max_voltag; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = bat_info->pdata->min_voltag; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = 1; + break; + default: + return -EINVAL; + } + return 0; +} + +static void jz_bat_external_power_changed(struct power_supply *psy) +{ + struct jz_battery_info *bat_info = ps_to_jz_battery(psy); + + cancel_delayed_work(&bat_info->bat_work); + queue_delayed_work(bat_info->monitor_wqueue, &bat_info->bat_work, HZ / 8); +} + +static char *status_text[] = { + [POWER_SUPPLY_STATUS_UNKNOWN] = "Unknown", + [POWER_SUPPLY_STATUS_CHARGING] = "Charging", + [POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging", + [POWER_SUPPLY_STATUS_NOT_CHARGING] = "Not charging", +}; + +static void jz_bat_update(struct power_supply *psy) +{ + struct jz_battery_info *bat_info = ps_to_jz_battery(psy); + + int old_status = bat_info->bat_status; + static unsigned long old_batt_vol = 0; + unsigned long batt_vol = jz_read_bat(psy); + + mutex_lock(&bat_info->work_lock); + + if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) { + if(!gpio_get_value(bat_info->pdata->charg_stat_gpio)) + bat_info->bat_status = POWER_SUPPLY_STATUS_CHARGING; + else + bat_info->bat_status = POWER_SUPPLY_STATUS_NOT_CHARGING; + dev_dbg(psy->dev, "%s: battery status=%s\n", + __func__, status_text[bat_info->bat_status]); + + if (old_status != bat_info->bat_status) { + dev_dbg(psy->dev, "%s %s -> %s\n", + psy->name, + status_text[old_status], + status_text[bat_info->bat_status]); + + power_supply_changed(psy); + } + } + + if (old_batt_vol - batt_vol > 50000) { + dev_dbg(psy->dev, "voltage change : %ld -> %ld\n", + old_batt_vol, batt_vol); + power_supply_changed(psy); + old_batt_vol = batt_vol; + } + + mutex_unlock(&bat_info->work_lock); +} + +static enum power_supply_property jz_bat_main_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_MAX, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_PRESENT, +}; + +struct power_supply bat_ps = { + .name = "battery", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = jz_bat_main_props, + .num_properties = ARRAY_SIZE(jz_bat_main_props), + .get_property = jz_bat_get_property, + .external_power_changed = jz_bat_external_power_changed, + .use_for_apm = 1, +}; + +static void jz_bat_work(struct work_struct *work) +{ + /* query interval too small will increase system workload*/ + const int interval = HZ * 30; + struct jz_battery_info *bat_info = container_of(work,struct jz_battery_info, bat_work.work); + + jz_bat_update(&bat_info->bat); + queue_delayed_work(bat_info->monitor_wqueue, + &bat_info->bat_work, interval); +} + +#ifdef CONFIG_PM +static int jz_bat_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct jz_battery_info *bat_info = platform_get_drvdata(pdev); + + bat_info->bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + + return 0; +} + +static int jz_bat_resume(struct platform_device *pdev) +{ + struct jz_battery_info *bat_info = platform_get_drvdata(pdev); + + bat_info->bat_status = POWER_SUPPLY_STATUS_UNKNOWN; + + cancel_delayed_work(&bat_info->bat_work); + queue_delayed_work(bat_info->monitor_wqueue, &bat_info->bat_work, HZ/10); + + return 0; +} +#else +#define jz_bat_suspend NULL +#define jz_bat_resume NULL +#endif + +static int jz_bat_probe(struct platform_device *pdev) +{ + int ret = 0; + struct jz_battery_info *bat_info; + + bat_info = kzalloc(sizeof(struct jz_battery_info), GFP_KERNEL); + + if (!bat_info) { + return -ENOMEM; + } + + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "Please set battery info\n"); + ret = -EINVAL; + goto err_platform_data; + } + platform_set_drvdata(pdev, bat_info); + bat_info->pdata = pdev->dev.platform_data; + bat_info->bat = bat_ps; + bat_info->usb = jz_usb; + bat_info->ac = jz_ac; + mutex_init(&bat_info->work_lock); + INIT_DELAYED_WORK(&bat_info->bat_work, jz_bat_work); + + if (gpio_is_valid(bat_info->pdata->dc_dect_gpio)) { + ret = gpio_request(bat_info->pdata->dc_dect_gpio, "AC/DC DECT"); + if (ret) { + dev_err(&pdev->dev, "ac/dc dect gpio request failed.\n"); + + goto err_dc_gpio_request; + } + ret = gpio_direction_input(bat_info->pdata->dc_dect_gpio); + if (ret) { + dev_err(&pdev->dev, "ac/dc dect gpio direction failed.\n"); + + goto err_dc_gpio_direction; + } + } + + if (gpio_is_valid(bat_info->pdata->usb_dect_gpio)) { + ret = gpio_request(bat_info->pdata->usb_dect_gpio, "USB DECT"); + if (ret) { + dev_err(&pdev->dev, "usb dect gpio request failed.\n"); + + goto err_usb_gpio_request; + } + ret = gpio_direction_input(bat_info->pdata->usb_dect_gpio); + if (ret) { + dev_err(&pdev->dev, "usb dect gpio set direction failed.\n"); + goto err_usb_gpio_direction; + } + + jz_gpio_disable_pullup(bat_info->pdata->usb_dect_gpio); + /* TODO: Use generic gpio is better */ + } + + if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) { + ret = gpio_request(bat_info->pdata->charg_stat_gpio, "CHARG STAT"); + if (ret) { + dev_err(&pdev->dev, "charger state gpio request failed.\n"); + goto err_charg_gpio_request; + } + ret = gpio_direction_input(bat_info->pdata->charg_stat_gpio); + if (ret) { + dev_err(&pdev->dev, "charger state gpio set direction failed.\n"); + goto err_charg_gpio_direction; + } + } + + if (gpio_is_valid(bat_info->pdata->dc_dect_gpio)) { + ret = power_supply_register(&pdev->dev, &bat_info->ac); + if (ret) { + dev_err(&pdev->dev, "power supply ac/dc register failed.\n"); + goto err_power_register_ac; + } + } + + if (gpio_is_valid(bat_info->pdata->usb_dect_gpio)) { + ret = power_supply_register(&pdev->dev, &bat_info->usb); + if (ret) { + dev_err(&pdev->dev, "power supply usb register failed.\n"); + goto err_power_register_usb; + } + } + + if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) { + ret = power_supply_register(&pdev->dev, &bat_info->bat); + if (ret) { + dev_err(&pdev->dev, "power supply battery register failed.\n"); + goto err_power_register_bat; + } else { + bat_info->monitor_wqueue = create_singlethread_workqueue("jz_battery"); + if (!bat_info->monitor_wqueue) { + return -ESRCH; + } + queue_delayed_work(bat_info->monitor_wqueue, &bat_info->bat_work, HZ * 1); + } + } + printk(KERN_INFO "jz_bat init success.\n"); + return ret; + +err_power_register_bat: + power_supply_unregister(&bat_info->usb); +err_power_register_usb: + power_supply_unregister(&bat_info->ac); +err_power_register_ac: +err_charg_gpio_direction: + gpio_free(bat_info->pdata->charg_stat_gpio); +err_charg_gpio_request: +err_usb_gpio_direction: + gpio_free(bat_info->pdata->usb_dect_gpio); +err_usb_gpio_request: +err_dc_gpio_direction: + gpio_free(bat_info->pdata->dc_dect_gpio); +err_dc_gpio_request: +err_platform_data: + kfree(bat_info); + return ret; +} + +static int jz_bat_remove(struct platform_device *pdev) +{ + struct jz_battery_info *bat_info = platform_get_drvdata(pdev); + + if (bat_info->pdata) { + if (gpio_is_valid(bat_info->pdata->dc_dect_gpio)) + gpio_free(bat_info->pdata->dc_dect_gpio); + if (gpio_is_valid(bat_info->pdata->usb_dect_gpio)) + gpio_free(bat_info->pdata->usb_dect_gpio); + if (gpio_is_valid(bat_info->pdata->charg_stat_gpio)) + gpio_free(bat_info->pdata->charg_stat_gpio); + } + + power_supply_unregister(&bat_ps); + power_supply_unregister(&jz_ac); + power_supply_unregister(&jz_usb); + + return 0; +} + +static struct platform_driver jz_bat_driver = { + .probe = jz_bat_probe, + .remove = __devexit_p(jz_bat_remove), + .suspend = jz_bat_suspend, + .resume = jz_bat_resume, + .driver = { + .name = "jz4740-battery", + .owner = THIS_MODULE, + }, +}; + +static int __init jz_bat_init(void) +{ + return platform_driver_register(&jz_bat_driver); +} +module_init(jz_bat_init); + +static void __exit jz_bat_exit(void) +{ + platform_driver_unregister(&jz_bat_driver); +} +module_exit(jz_bat_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jiejing Zhang "); +MODULE_DESCRIPTION("JZ4720/JZ4740 SoC battery driver"); diff -ruN linux-2.6.31-vanilla/drivers/rtc/rtc-jz4740.c linux-2.6.31/drivers/rtc/rtc-jz4740.c --- linux-2.6.31-vanilla/drivers/rtc/rtc-jz4740.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/rtc/rtc-jz4740.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC RTC driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +#define JZ_REG_RTC_CTRL 0x00 +#define JZ_REG_RTC_SEC 0x04 +#define JZ_REG_RTC_SEC_ALARM 0x08 +#define JZ_REG_REGULATOR 0x0C + +#define JZ_RTC_CTRL_WRDY BIT(7) +#define JZ_RTC_CTRL_1HZ BIT(6) +#define JZ_RTC_CTRL_1HZ_IRQ BIT(5) +#define JZ_RTC_CTRL_AF BIT(4) +#define JZ_RTC_CTRL_AF_IRQ BIT(3) +#define JZ_RTC_CTRL_AE BIT(2) +#define JZ_RTC_CTRL_ENABLE BIT(0) + +struct jz4740_rtc { + struct resource *mem; + void __iomem *base; + + struct rtc_device *rtc; + + unsigned int irq; + + spinlock_t lock; +}; + +static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg) +{ + return readl(rtc->base + reg); +} + +static inline void jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc) +{ + uint32_t ctrl; + do { + ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); + } while (!(ctrl & JZ_RTC_CTRL_WRDY)); +} + + +static inline void jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, + uint32_t val) +{ + jz4740_rtc_wait_write_ready(rtc); + writel(val, rtc->base + reg); +} + +static void jz4740_rtc_ctrl_set_bits(struct jz4740_rtc *rtc, uint32_t mask, + uint32_t val) +{ + unsigned long flags; + uint32_t ctrl; + + spin_lock_irqsave(&rtc->lock, flags); + + ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); + + /* Don't clear interrupt flags by accident */ + ctrl |= JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF; + + ctrl &= ~mask; + ctrl |= val; + + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CTRL, ctrl); + + spin_unlock_irqrestore(&rtc->lock, flags); +} + +static inline struct jz4740_rtc *dev_to_rtc(struct device *dev) +{ + return dev_get_drvdata(dev); +} + +static int jz4740_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + uint32_t secs, secs2; + + secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC); + secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC); + + while (secs != secs2) { + secs = secs2; + secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC); + } + + rtc_time_to_tm(secs, time); + + return rtc_valid_tm(time); +} + +static int jz4740_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + + if ((uint32_t)secs != secs) + return -EINVAL; + + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, secs); + + return 0; +} + +static int jz4740_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + uint32_t secs, secs2; + uint32_t ctrl; + + secs = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM); + secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM); + + while (secs != secs2){ + secs = secs2; + secs2 = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_SEC_ALARM); + } + + ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); + + alrm->enabled = !!(ctrl & JZ_RTC_CTRL_AE); + alrm->pending = !!(ctrl & JZ_RTC_CTRL_AF); + + rtc_time_to_tm(secs, &alrm->time); + + return rtc_valid_tm(&alrm->time); +} + +static int jz4740_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + unsigned long secs; + + rtc_tm_to_time(&alrm->time, &secs); + + if ((uint32_t)secs != secs) + return -EINVAL; + + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC_ALARM, (uint32_t)secs); + jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AE, + alrm->enabled ? JZ_RTC_CTRL_AE : 0); + + return 0; +} + +static int jz4740_rtc_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ_IRQ, + enabled ? JZ_RTC_CTRL_1HZ_IRQ : 0); + return 0; +} + + +static int jz4740_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct jz4740_rtc *rtc = dev_to_rtc(dev); + jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_AF_IRQ, + enabled ? JZ_RTC_CTRL_AF_IRQ : 0); + return 0; +} + +static struct rtc_class_ops jz4740_rtc_ops = { + .read_time = jz4740_rtc_read_time, + .set_mmss = jz4740_rtc_set_mmss, + .read_alarm = jz4740_rtc_read_alarm, + .set_alarm = jz4740_rtc_set_alarm, + .update_irq_enable = jz4740_rtc_update_irq_enable, + .alarm_irq_enable = jz4740_rtc_alarm_irq_enable, +}; + +static irqreturn_t jz4740_rtc_irq(int irq, void *data) +{ + struct jz4740_rtc *rtc = data; + uint32_t ctrl; + unsigned long events = 0; + ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); + + if (ctrl & JZ_RTC_CTRL_1HZ) + events |= (RTC_UF | RTC_IRQF); + + if (ctrl & JZ_RTC_CTRL_AF) + events |= (RTC_AF | RTC_IRQF); + + rtc_update_irq(rtc->rtc, 1, events); + + jz4740_rtc_ctrl_set_bits(rtc, JZ_RTC_CTRL_1HZ | JZ_RTC_CTRL_AF, 0); + + return IRQ_HANDLED; +} + +static int __devinit jz4740_rtc_probe(struct platform_device *pdev) +{ + int ret; + struct jz4740_rtc *rtc; + + rtc = kmalloc(sizeof(*rtc), GFP_KERNEL); + + rtc->irq = platform_get_irq(pdev, 0); + + if (rtc->irq < 0) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get platform irq\n"); + goto err_free; + } + + rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!rtc->mem) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get platform mmio memory\n"); + goto err_free; + } + + rtc->mem = request_mem_region(rtc->mem->start, resource_size(rtc->mem), + pdev->name); + + if (!rtc->mem) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to request mmio memory region\n"); + goto err_free; + } + + rtc->base = ioremap_nocache(rtc->mem->start, resource_size(rtc->mem)); + + if (!rtc->base) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); + goto err_release_mem_region; + } + + platform_set_drvdata(pdev, rtc); + + rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &jz4740_rtc_ops, + THIS_MODULE); + + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + dev_err(&pdev->dev, "Failed to register rtc device: %d\n", ret); + goto err_iounmap; + } + + ret = request_irq(rtc->irq, jz4740_rtc_irq, 0, + pdev->name, rtc); + + if (ret) { + dev_err(&pdev->dev, "Failed to request rtc irq: %d\n", ret); + goto err_unregister_rtc; + } + printk("rtc-ctrl: %d\n", jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL)); + + return 0; + +err_unregister_rtc: + rtc_device_unregister(rtc->rtc); +err_iounmap: + platform_set_drvdata(pdev, NULL); + iounmap(rtc->base); +err_release_mem_region: + release_mem_region(rtc->mem->start, resource_size(rtc->mem)); +err_free: + kfree(rtc); + + return ret; +} + +static int __devexit jz4740_rtc_remove(struct platform_device *pdev) +{ + struct jz4740_rtc *rtc = platform_get_drvdata(pdev); + + rtc_device_unregister(rtc->rtc); + + iounmap(rtc->base); + release_mem_region(rtc->mem->start, resource_size(rtc->mem)); + + kfree(rtc); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +struct platform_driver jz4740_rtc_driver = { + .probe = jz4740_rtc_probe, + .remove = __devexit_p(jz4740_rtc_remove), + .driver = { + .name = "jz4740-rtc", + .owner = THIS_MODULE, + }, +}; + +static int __init jz4740_rtc_init(void) +{ + return platform_driver_register(&jz4740_rtc_driver); +} +module_init(jz4740_rtc_init); + +static void __exit jz4740_rtc_exit(void) +{ + platform_driver_unregister(&jz4740_rtc_driver); +} +module_exit(jz4740_rtc_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RTC driver for the JZ4720/JZ4740 SoC\n"); +MODULE_ALIAS("platform:jz4740-rtc"); +MODULE_ALIAS("platform:jz4720-rtc"); diff -ruN linux-2.6.31-vanilla/drivers/usb/gadget/jz4740_udc.c linux-2.6.31/drivers/usb/gadget/jz4740_udc.c --- linux-2.6.31-vanilla/drivers/usb/gadget/jz4740_udc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/usb/gadget/jz4740_udc.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,2337 @@ +/* + * linux/drivers/usb/gadget/jz4740_udc.c + * + * Ingenic JZ4740 on-chip high speed USB device controller + * + * Copyright (C) 2006 - 2008 Ingenic Semiconductor Inc. + * Author: + * + * 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 device has ep0, two bulk-in/interrupt-in endpoints, and one bulk-out endpoint. + * + * - Endpoint numbering is fixed: ep0, ep1in-int, ep2in-bulk, ep1out-bulk. + * - DMA works with bulk-in (channel 1) and bulk-out (channel 2) endpoints. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "jz4740_udc.h" + +#define JZ_REG_UDC_FADDR 0x00 /* Function Address 8-bit */ +#define JZ_REG_UDC_POWER 0x01 /* Power Managemetn 8-bit */ +#define JZ_REG_UDC_INTRIN 0x02 /* Interrupt IN 16-bit */ +#define JZ_REG_UDC_INTROUT 0x04 /* Interrupt OUT 16-bit */ +#define JZ_REG_UDC_INTRINE 0x06 /* Intr IN enable 16-bit */ +#define JZ_REG_UDC_INTROUTE 0x08 /* Intr OUT enable 16-bit */ +#define JZ_REG_UDC_INTRUSB 0x0a /* Interrupt USB 8-bit */ +#define JZ_REG_UDC_INTRUSBE 0x0b /* Interrupt USB Enable 8-bit */ +#define JZ_REG_UDC_FRAME 0x0c /* Frame number 16-bit */ +#define JZ_REG_UDC_INDEX 0x0e /* Index register 8-bit */ +#define JZ_REG_UDC_TESTMODE 0x0f /* USB test mode 8-bit */ + +#define JZ_REG_UDC_CSR0 0x12 /* EP0 CSR 8-bit */ +#define JZ_REG_UDC_INMAXP 0x10 /* EP1-2 IN Max Pkt Size 16-bit */ +#define JZ_REG_UDC_INCSR 0x12 /* EP1-2 IN CSR LSB 8/16bit */ +#define JZ_REG_UDC_INCSRH 0x13 /* EP1-2 IN CSR MSB 8-bit */ +#define JZ_REG_UDC_OUTMAXP 0x14 /* EP1 OUT Max Pkt Size 16-bit */ +#define JZ_REG_UDC_OUTCSR 0x16 /* EP1 OUT CSR LSB 8/16bit */ +#define JZ_REG_UDC_OUTCSRH 0x17 /* EP1 OUT CSR MSB 8-bit */ +#define JZ_REG_UDC_OUTCOUNT 0x18 /* bytes in EP0/1 OUT FIFO 16-bit */ + +#define JZ_REG_UDC_EP_FIFO(x) (4 * (x) + 0x20) + +#define JZ_REG_UDC_EPINFO 0x78 /* Endpoint information */ +#define JZ_REG_UDC_RAMINFO 0x79 /* RAM information */ + +#define JZ_REG_UDC_INTR 0x200 /* DMA pending interrupts */ +#define JZ_REG_UDC_CNTL1 0x204 /* DMA channel 1 control */ +#define JZ_REG_UDC_ADDR1 0x208 /* DMA channel 1 AHB memory addr */ +#define JZ_REG_UDC_COUNT1 0x20c /* DMA channel 1 byte count */ +#define JZ_REG_UDC_CNTL2 0x214 /* DMA channel 2 control */ +#define JZ_REG_UDC_ADDR2 0x218 /* DMA channel 2 AHB memory addr */ +#define JZ_REG_UDC_COUNT2 0x21c /* DMA channel 2 byte count */ + +#ifndef DEBUG +# define DEBUG(fmt,args...) do {} while(0) +#endif +#ifndef DEBUG_EP0 +# define NO_STATES +# define DEBUG_EP0(fmt,args...) do {} while(0) +#endif +#ifndef DEBUG_SETUP +# define DEBUG_SETUP(fmt,args...) do {} while(0) +#endif + +static unsigned int udc_debug = 0; /* 0: normal mode, 1: test udc cable type mode */ + +module_param(udc_debug, int, 0); +MODULE_PARM_DESC(udc_debug, "test udc cable or power type"); + +static unsigned int use_dma = 0; /* 1: use DMA, 0: use PIO */ + +module_param(use_dma, int, 0); +MODULE_PARM_DESC(use_dma, "DMA mode enable flag"); + +struct jz4740_udc *the_controller; + +/* + * Local declarations. + */ +static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep); +static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr); + +static void done(struct jz4740_ep *ep, struct jz4740_request *req, + int status); +static void pio_irq_enable(struct jz4740_ep *ep); +static void pio_irq_disable(struct jz4740_ep *ep); +static void stop_activity(struct jz4740_udc *dev, + struct usb_gadget_driver *driver); +static void nuke(struct jz4740_ep *ep, int status); +static void flush(struct jz4740_ep *ep); +static void udc_set_address(struct jz4740_udc *dev, unsigned char address); + +/*-------------------------------------------------------------------------*/ + +/* inline functions of register read/write/set/clear */ + +static inline uint8_t usb_readb(struct jz4740_udc *udc, size_t reg) +{ + return readb(udc->base + reg); +} + +static inline uint16_t usb_readw(struct jz4740_udc *udc, size_t reg) +{ + return readw(udc->base + reg); +} + +static inline uint32_t usb_readl(struct jz4740_udc *udc, size_t reg) +{ + return readl(udc->base + reg); +} + +static inline void usb_writeb(struct jz4740_udc *udc, size_t reg, uint8_t val) +{ + writeb(val, udc->base + reg); +} + +static inline void usb_writew(struct jz4740_udc *udc, size_t reg, uint16_t val) +{ + writew(val, udc->base + reg); +} + +static inline void usb_writel(struct jz4740_udc *udc, size_t reg, uint32_t val) +{ + writel(val, udc->base + reg); +} + +static inline void usb_setb(struct jz4740_udc *udc, size_t reg, uint8_t mask) +{ + usb_writeb(udc, reg, usb_readb(udc, reg) | mask); +} + +static inline void usb_setw(struct jz4740_udc *udc, size_t reg, uint8_t mask) +{ + usb_writew(udc, reg, usb_readw(udc, reg) | mask); +} + +static inline void usb_setl(struct jz4740_udc *udc, size_t reg, uint32_t mask) +{ + usb_writel(udc, reg, usb_readl(udc, reg) | mask); +} + +static inline void usb_clearb(struct jz4740_udc *udc, size_t reg, uint8_t mask) +{ + usb_writeb(udc, reg, usb_readb(udc, reg) & ~mask); +} + +static inline void usb_clearw(struct jz4740_udc *udc, size_t reg, uint16_t mask) +{ + usb_writew(udc, reg, usb_readw(udc, reg) & ~mask); +} + +static inline void usb_clearl(struct jz4740_udc *udc, size_t reg, uint32_t mask) +{ + usb_writel(udc, reg, usb_readl(udc, reg) & ~mask); +} + +/*-------------------------------------------------------------------------*/ + +static inline void jz_udc_set_index(struct jz4740_udc *udc, uint8_t index) +{ + usb_writeb(udc, JZ_REG_UDC_INDEX, index); +} + +static inline void jz_udc_select_ep(struct jz4740_ep *ep) +{ + jz_udc_set_index(ep->dev, ep_index(ep)); +} + +static inline int write_packet(struct jz4740_ep *ep, + struct jz4740_request *req, int max) +{ + uint8_t *buf; + int length, nlong, nbyte; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + buf = req->req.buf + req->req.actual; + prefetch(buf); + + length = req->req.length - req->req.actual; + length = min(length, max); + req->req.actual += length; + + DEBUG("Write %d (max %d), fifo %x\n", length, max, ep->fifo); + + nlong = length >> 2; + nbyte = length & 0x3; + while (nlong--) { + usb_writel(ep->dev, ep->fifo, *((uint32_t *)buf)); + buf += 4; + } + while (nbyte--) { + usb_writeb(ep->dev, ep->fifo, *buf++); + } + + return length; +} + +static inline int read_packet(struct jz4740_ep *ep, + struct jz4740_request *req, int count) +{ + uint8_t *buf; + int length, nlong, nbyte; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + + length = req->req.length - req->req.actual; + length = min(length, count); + req->req.actual += length; + + DEBUG("Read %d, fifo %x\n", length, ep->fifo); + + nlong = length >> 2; + nbyte = length & 0x3; + while (nlong--) { + *((uint32_t *)buf) = usb_readl(ep->dev, ep->fifo); + buf += 4; + } + while (nbyte--) { + *buf++ = usb_readb(ep->dev, ep->fifo); + } + + return length; +} + +/*-------------------------------------------------------------------------*/ + +/* + * udc_disable - disable USB device controller + */ +static void udc_disable(struct jz4740_udc *dev) +{ + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + udc_set_address(dev, 0); + + /* Disable interrupts */ + usb_writew(dev, JZ_REG_UDC_INTRINE, 0); + usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); + usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0); + + /* Disable DMA */ + usb_writel(dev, JZ_REG_UDC_CNTL1, 0); + usb_writel(dev, JZ_REG_UDC_CNTL2, 0); + + /* Disconnect from usb */ + usb_clearb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); + + /* Disable the USB PHY */ +#ifdef CONFIG_SOC_JZ4740 + REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; +#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; +#endif + + dev->ep0state = WAIT_FOR_SETUP; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + return; +} + +/* + * udc_reinit - initialize software state + */ +static void udc_reinit(struct jz4740_udc *dev) +{ + int i; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + /* device/ep0 records init */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + dev->ep0state = WAIT_FOR_SETUP; + + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct jz4740_ep *ep = &dev->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); + + INIT_LIST_HEAD(&ep->queue); + ep->desc = 0; + ep->stopped = 0; + ep->pio_irqs = 0; + } +} + +/* until it's enabled, this UDC should be completely invisible + * to any USB host. + */ +static void udc_enable(struct jz4740_udc *dev) +{ + int i; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + /* UDC state is incorrect - Added by River */ + if (dev->state != UDC_STATE_ENABLE) { + return; + } + + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* Flush FIFO for each */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct jz4740_ep *ep = &dev->ep[i]; + + jz_udc_set_index(dev, ep_index(ep)); + flush(ep); + } + + /* Set this bit to allow the UDC entering low-power mode when + * there are no actions on the USB bus. + * UDC still works during this bit was set. + */ + __cpm_stop_udc(); + + /* Enable the USB PHY */ +#ifdef CONFIG_SOC_JZ4740 + REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; +#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; +#endif + + /* Disable interrupts */ +/* usb_writew(dev, JZ_REG_UDC_INTRINE, 0); + usb_writew(dev, JZ_REG_UDC_INTROUTE, 0); + usb_writeb(dev, JZ_REG_UDC_INTRUSBE, 0);*/ + + /* Enable interrupts */ + usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_EP0); + usb_setb(dev, JZ_REG_UDC_INTRUSBE, USB_INTR_RESET); + /* Don't enable rest of the interrupts */ + /* usb_setw(dev, JZ_REG_UDC_INTRINE, USB_INTR_INEP1 | USB_INTR_INEP2); + usb_setw(dev, JZ_REG_UDC_INTROUTE, USB_INTR_OUTEP1); */ + + /* Enable SUSPEND */ + /* usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SUSPENDM); */ + + /* Enable HS Mode */ + usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_HSENAB); + + /* Let host detect UDC: + * Software must write a 1 to the PMR:USB_POWER_SOFTCONN bit to turn this + * transistor on and pull the USBDP pin HIGH. + */ + usb_setb(dev, JZ_REG_UDC_POWER, USB_POWER_SOFTCONN); + + return; +} + +/*-------------------------------------------------------------------------*/ + +/* keeping it simple: + * - one bus driver, initted first; + * - one function driver, initted second + */ + +/* + * Register entry point for the peripheral controller driver. + */ + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct jz4740_udc *dev = the_controller; + int retval; + + if (!driver || !driver->bind) { + return -EINVAL; + } + + if (!dev) { + return -ENODEV; + } + + if (dev->driver) { + return -EBUSY; + } + + /* hook up the driver */ + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + retval = driver->bind(&dev->gadget); + if (retval) { + DEBUG("%s: bind to driver %s --> error %d\n", dev->gadget.name, + driver->driver.name, retval); + dev->driver = 0; + return retval; + } + + /* then enable host detection and ep0; and we're ready + * for set_configuration as well as eventual disconnect. + */ + udc_enable(dev); + + DEBUG("%s: registered gadget driver '%s'\n", dev->gadget.name, + driver->driver.name); + + return 0; +} + +EXPORT_SYMBOL(usb_gadget_register_driver); + +static void stop_activity(struct jz4740_udc *dev, + struct usb_gadget_driver *driver) +{ + int i; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + /* don't disconnect drivers more than once */ + if (dev->gadget.speed == USB_SPEED_UNKNOWN) + driver = 0; + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* prevent new request submissions, kill any outstanding requests */ + for (i = 0; i < UDC_MAX_ENDPOINTS; i++) { + struct jz4740_ep *ep = &dev->ep[i]; + + ep->stopped = 1; + + jz_udc_set_index(dev, ep_index(ep)); + nuke(ep, -ESHUTDOWN); + } + + /* report disconnect; the driver is already quiesced */ + if (driver) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + + /* re-init driver-visible data structures */ + udc_reinit(dev); +} + + +/* + * Unregister entry point for the peripheral controller driver. + */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct jz4740_udc *dev = the_controller; + unsigned long flags; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver) + return -EINVAL; + if (!driver->unbind) + return -EBUSY; + + spin_lock_irqsave(&dev->lock, flags); + dev->driver = 0; + stop_activity(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + driver->unbind(&dev->gadget); + + udc_disable(dev); + + DEBUG("unregistered driver '%s'\n", driver->driver.name); + + return 0; +} + +EXPORT_SYMBOL(usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ + +/* + * Starting DMA using mode 1 + */ +static void kick_dma(struct jz4740_ep *ep, struct jz4740_request *req) +{ + struct jz4740_udc *dev = ep->dev; + uint32_t count = req->req.length; + uint32_t physaddr = virt_to_phys((void *)req->req.buf); + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + jz_udc_select_ep(ep); + + if (ep_is_in(ep)) { /* Bulk-IN transfer using DMA channel 1 */ + ep->reg_addr = JZ_REG_UDC_ADDR1; + + dma_cache_wback_inv((unsigned long)req->req.buf, count); + + pio_irq_enable(ep); + + usb_writeb(dev, JZ_REG_UDC_INCSRH, + USB_INCSRH_DMAREQENAB | USB_INCSRH_AUTOSET | USB_INCSRH_DMAREQMODE); + + usb_writel(dev, JZ_REG_UDC_ADDR1, physaddr); + usb_writel(dev, JZ_REG_UDC_COUNT1, count); + usb_writel(dev, JZ_REG_UDC_CNTL1, USB_CNTL_ENA | USB_CNTL_DIR_IN | USB_CNTL_MODE_1 | + USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); + } + else { /* Bulk-OUT transfer using DMA channel 2 */ + ep->reg_addr = JZ_REG_UDC_ADDR2; + + dma_cache_wback_inv((unsigned long)req->req.buf, count); + + pio_irq_enable(ep); + + usb_setb(dev, JZ_REG_UDC_OUTCSRH, + USB_OUTCSRH_DMAREQENAB | USB_OUTCSRH_AUTOCLR | USB_OUTCSRH_DMAREQMODE); + + usb_writel(dev, JZ_REG_UDC_ADDR2, physaddr); + usb_writel(dev, JZ_REG_UDC_COUNT2, count); + usb_writel(dev, JZ_REG_UDC_CNTL2, USB_CNTL_ENA | USB_CNTL_MODE_1 | + USB_CNTL_INTR_EN | USB_CNTL_BURST_16 | USB_CNTL_EP(ep_index(ep))); + } +} + +/*-------------------------------------------------------------------------*/ + +/** Write request to FIFO (max write == maxp size) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int write_fifo(struct jz4740_ep *ep, struct jz4740_request *req) +{ + struct jz4740_udc *dev = ep->dev; + uint32_t max, csr; + uint32_t physaddr = virt_to_phys((void *)req->req.buf); + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + max = le16_to_cpu(ep->desc->wMaxPacketSize); + + if (use_dma) { + uint32_t dma_count; + + /* DMA interrupt generated due to the last packet loaded into the FIFO */ + + dma_count = usb_readl(dev, ep->reg_addr) - physaddr; + req->req.actual += dma_count; + + if (dma_count % max) { + /* If the last packet is less than MAXP, set INPKTRDY manually */ + usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); + } + + done(ep, req, 0); + if (list_empty(&ep->queue)) { + pio_irq_disable(ep); + return 1; + } + else { + /* advance the request queue */ + req = list_entry(ep->queue.next, struct jz4740_request, queue); + kick_dma(ep, req); + return 0; + } + } + + /* + * PIO mode handling starts here ... + */ + + csr = usb_readb(dev, ep->csr); + + if (!(csr & USB_INCSR_FFNOTEMPT)) { + unsigned count; + int is_last, is_short; + + count = write_packet(ep, req, max); + usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = is_short = 1; + else { + if (likely(req->req.length != req->req.actual) + || req->req.zero) + is_last = 0; + else + is_last = 1; + /* interrupt/iso maxpacket may not fill the fifo */ + is_short = unlikely(max < ep_maxpacket(ep)); + } + + DEBUG("%s: wrote %s %d bytes%s%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", is_short ? "/S" : "", + req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + if (list_empty(&ep->queue)) { + pio_irq_disable(ep); + } + return 1; + } + } else { + DEBUG("Hmm.. %d ep FIFO is not empty!\n", ep_index(ep)); + } + + return 0; +} + +/** Read to request from FIFO (max read == bytes in fifo) + * Return: 0 = still running, 1 = completed, negative = errno + * NOTE: INDEX register must be set for EP + */ +static int read_fifo(struct jz4740_ep *ep, struct jz4740_request *req) +{ + struct jz4740_udc *dev = ep->dev; + uint32_t csr; + unsigned count, is_short; + uint32_t physaddr = virt_to_phys((void *)req->req.buf); + + if (use_dma) { + uint32_t dma_count; + + /* DMA interrupt generated due to a packet less than MAXP loaded into the FIFO */ + + dma_count = usb_readl(dev, ep->reg_addr) - physaddr; + req->req.actual += dma_count; + + /* Disable interrupt and DMA */ + pio_irq_disable(ep); + usb_writel(dev, JZ_REG_UDC_CNTL2, 0); + + /* Read all bytes from this packet */ + count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); + count = read_packet(ep, req, count); + + if (count) { + /* If the last packet is greater than zero, clear OUTPKTRDY manually */ + usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY); + } + done(ep, req, 0); + + if (!list_empty(&ep->queue)) { + /* advance the request queue */ + req = list_entry(ep->queue.next, struct jz4740_request, queue); + kick_dma(ep, req); + } + + return 1; + } + + /* + * PIO mode handling starts here ... + */ + + /* make sure there's a packet in the FIFO. */ + csr = usb_readb(dev, ep->csr); + if (!(csr & USB_OUTCSR_OUTPKTRDY)) { + DEBUG("%s: Packet NOT ready!\n", __FUNCTION__); + return -EINVAL; + } + + /* read all bytes from this packet */ + count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); + + is_short = (count < ep->ep.maxpacket); + + count = read_packet(ep, req, count); + + DEBUG("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + /* Clear OutPktRdy */ + usb_clearb(dev, ep->csr, USB_OUTCSR_OUTPKTRDY); + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + + if (list_empty(&ep->queue)) + pio_irq_disable(ep); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/* + * done - retire a request; caller blocked irqs + * INDEX register is preserved to keep same + */ +static void done(struct jz4740_ep *ep, struct jz4740_request *req, int status) +{ + unsigned int stopped = ep->stopped; + unsigned long flags; + uint32_t index; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + list_del_init(&req->queue); + + if (likely(req->req.status == -EINPROGRESS)) + req->req.status = status; + else + status = req->req.status; + + if (status && status != -ESHUTDOWN) + DEBUG("complete %s req %p stat %d len %u/%u\n", + ep->ep.name, &req->req, status, + req->req.actual, req->req.length); + + /* don't modify queue heads during completion callback */ + ep->stopped = 1; + /* Read current index (completion may modify it) */ + spin_lock_irqsave(&ep->dev->lock, flags); + index = usb_readb(ep->dev, JZ_REG_UDC_INDEX); + + req->req.complete(&ep->ep, &req->req); + + /* Restore index */ + jz_udc_set_index(ep->dev, index); + spin_unlock_irqrestore(&ep->dev->lock, flags); + ep->stopped = stopped; +} + +/** Enable EP interrupt */ +static void pio_irq_enable(struct jz4740_ep *ep) +{ + uint8_t index = ep_index(ep); + struct jz4740_udc *dev = ep->dev; + DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); + + if (ep_is_in(ep)) { + switch (index) { + case 1: + case 2: + usb_setw(dev, JZ_REG_UDC_INTRINE, BIT(index)); + dev->in_mask |= BIT(index); + break; + default: + DEBUG("Unknown endpoint: %d\n", index); + break; + } + } + else { + switch (index) { + case 1: + usb_setw(dev, JZ_REG_UDC_INTROUTE, BIT(index)); + dev->out_mask |= BIT(index); + break; + default: + DEBUG("Unknown endpoint: %d\n", index); + break; + } + } +} + +/** Disable EP interrupt */ +static void pio_irq_disable(struct jz4740_ep *ep) +{ + uint8_t index = ep_index(ep); + struct jz4740_udc *dev = ep->dev; + + DEBUG("%s: EP%d %s\n", __FUNCTION__, ep_index(ep), ep_is_in(ep) ? "IN": "OUT"); + + if (ep_is_in(ep)) { + switch (ep_index(ep)) { + case 1: + case 2: + usb_clearw(ep->dev, JZ_REG_UDC_INTRINE, BIT(index)); + dev->in_mask &= ~BIT(index); + break; + default: + DEBUG("Unknown endpoint: %d\n", index); + break; + } + } + else { + switch (ep_index(ep)) { + case 1: + usb_clearw(ep->dev, JZ_REG_UDC_INTROUTE, BIT(index)); + dev->out_mask &= ~BIT(index); + break; + default: + DEBUG("Unknown endpoint: %d\n", index); + break; + } + } +} + +/* + * nuke - dequeue ALL requests + */ +static void nuke(struct jz4740_ep *ep, int status) +{ + struct jz4740_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + /* Flush FIFO */ + flush(ep); + + /* called with irqs blocked */ + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct jz4740_request, queue); + done(ep, req, status); + } + + /* Disable IRQ if EP is enabled (has descriptor) */ + if (ep->desc) + pio_irq_disable(ep); +} + +/** Flush EP FIFO + * NOTE: INDEX register must be set before this call + */ +static void flush(struct jz4740_ep *ep) +{ + DEBUG("%s: %s\n", __FUNCTION__, ep->ep.name); + + switch (ep->type) { + case ep_bulk_in: + case ep_interrupt: + usb_setb(ep->dev, ep->csr, USB_INCSR_FF); + break; + case ep_bulk_out: + usb_setb(ep->dev, ep->csr, USB_OUTCSR_FF); + break; + case ep_control: + break; + } +} + +/** + * jz4740_in_epn - handle IN interrupt + */ +static void jz4740_in_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) +{ + uint32_t csr; + struct jz4740_ep *ep = &dev->ep[ep_idx + 1]; + struct jz4740_request *req; + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + jz_udc_set_index(dev, ep_index(ep)); + + csr = usb_readb(dev, ep->csr); + DEBUG("%s: %d, csr %x\n", __FUNCTION__, ep_idx, csr); + + if (csr & USB_INCSR_SENTSTALL) { + DEBUG("USB_INCSR_SENTSTALL\n"); + usb_clearb(dev, ep->csr, USB_INCSR_SENTSTALL); + return; + } + + if (!ep->desc) { + DEBUG("%s: NO EP DESC\n", __FUNCTION__); + return; + } + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct jz4740_request, queue); + + DEBUG("req: %p\n", req); + + if (!req) + return; + + write_fifo(ep, req); +} + +/* + * Bulk OUT (recv) + */ +static void jz4740_out_epn(struct jz4740_udc *dev, uint32_t ep_idx, uint32_t intr) +{ + struct jz4740_ep *ep = &dev->ep[ep_idx]; + struct jz4740_request *req; + + DEBUG("%s: %d\n", __FUNCTION__, ep_idx); + + jz_udc_set_index(dev, ep_index(ep)); + if (ep->desc) { + uint32_t csr; + + if (use_dma) { + /* DMA starts here ... */ + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct jz4740_request, queue); + + if (req) + read_fifo(ep, req); + return; + } + + /* + * PIO mode starts here ... + */ + + while ((csr = usb_readb(dev, ep->csr)) & + (USB_OUTCSR_OUTPKTRDY | USB_OUTCSR_SENTSTALL)) { + DEBUG("%s: %x\n", __FUNCTION__, csr); + + if (csr & USB_OUTCSR_SENTSTALL) { + DEBUG("%s: stall sent, flush fifo\n", + __FUNCTION__); + /* usb_set(USB_OUT_CSR1_FIFO_FLUSH, ep->csr1); */ + flush(ep); + } else if (csr & USB_OUTCSR_OUTPKTRDY) { + if (list_empty(&ep->queue)) + req = 0; + else + req = + list_entry(ep->queue.next, + struct jz4740_request, + queue); + + if (!req) { + DEBUG("%s: NULL REQ %d\n", + __FUNCTION__, ep_idx); + break; + } else { + read_fifo(ep, req); + } + } + } + } else { + /* Throw packet away.. */ + DEBUG("%s: ep %p ep_indx %d No descriptor?!?\n", __FUNCTION__, ep, ep_idx); + flush(ep); + } +} + +/** Halt specific EP + * Return 0 if success + * NOTE: Sets INDEX register to EP ! + */ +static int jz4740_set_halt(struct usb_ep *_ep, int value) +{ + struct jz4740_udc *dev; + struct jz4740_ep *ep; + unsigned long flags; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + ep = container_of(_ep, struct jz4740_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + dev = ep->dev; + + spin_lock_irqsave(&dev->lock, flags); + + jz_udc_select_ep(ep); + + DEBUG("%s, ep %d, val %d\n", __FUNCTION__, ep_index(ep), value); + + if (ep_index(ep) == 0) { + /* EP0 */ + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL); + } else if (ep_is_in(ep)) { + uint32_t csr = usb_readb(dev, ep->csr); + if (value && ((csr & USB_INCSR_FFNOTEMPT) + || !list_empty(&ep->queue))) { + /* + * Attempts to halt IN endpoints will fail (returning -EAGAIN) + * if any transfer requests are still queued, or if the controller + * FIFO still holds bytes that the host hasnÂ’t collected. + */ + spin_unlock_irqrestore(&dev->lock, flags); + DEBUG + ("Attempt to halt IN endpoint failed (returning -EAGAIN) %d %d\n", + (csr & USB_INCSR_FFNOTEMPT), + !list_empty(&ep->queue)); + return -EAGAIN; + } + flush(ep); + if (value) { + usb_setb(dev, ep->csr, USB_INCSR_SENDSTALL); + } + else { + usb_clearb(dev, ep->csr, USB_INCSR_SENDSTALL); + usb_setb(dev, ep->csr, USB_INCSR_CDT); + } + } else { + + flush(ep); + if (value) { + usb_setb(dev, ep->csr, USB_OUTCSR_SENDSTALL); + } + else { + usb_clearb(dev, ep->csr, USB_OUTCSR_SENDSTALL); + usb_setb(dev, ep->csr, USB_OUTCSR_CDT); + } + } + + if (value) { + ep->stopped = 1; + } else { + ep->stopped = 0; + } + + spin_unlock_irqrestore(&dev->lock, flags); + + DEBUG("%s %s halted\n", _ep->name, value == 0 ? "NOT" : "IS"); + + return 0; +} + + +static int jz4740_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct jz4740_ep *ep; + struct jz4740_udc *dev; + unsigned long flags; + uint32_t max, csrh = 0; + + DEBUG("%s: trying to enable %s\n", __FUNCTION__, _ep->name); + + if (!_ep || !desc) + return -EINVAL; + + ep = container_of(_ep, struct jz4740_ep, ep); + if (ep->desc || ep->type == ep_control + || desc->bDescriptorType != USB_DT_ENDPOINT + || ep->bEndpointAddress != desc->bEndpointAddress) { + DEBUG("%s, bad ep or descriptor\n", __FUNCTION__); + return -EINVAL; + } + + /* xfer types must match, except that interrupt ~= bulk */ + if (ep->bmAttributes != desc->bmAttributes + && ep->bmAttributes != USB_ENDPOINT_XFER_BULK + && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { + DEBUG("%s, %s type mismatch\n", __FUNCTION__, _ep->name); + return -EINVAL; + } + + dev = ep->dev; + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { + DEBUG("%s, bogus device state\n", __FUNCTION__); + return -ESHUTDOWN; + } + + max = le16_to_cpu(desc->wMaxPacketSize); + + spin_lock_irqsave(&ep->dev->lock, flags); + + /* Configure the endpoint */ + jz_udc_set_index(dev, desc->bEndpointAddress & 0x0F); + if (ep_is_in(ep)) { + usb_writew(dev, JZ_REG_UDC_INMAXP, max); + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: + case USB_ENDPOINT_XFER_INT: + csrh &= ~USB_INCSRH_ISO; + break; + case USB_ENDPOINT_XFER_ISOC: + csrh |= USB_INCSRH_ISO; + break; + } + usb_writeb(dev, JZ_REG_UDC_INCSRH, csrh); + } + else { + usb_writew(dev, JZ_REG_UDC_OUTMAXP, max); + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_BULK: + csrh &= ~USB_OUTCSRH_ISO; + break; + case USB_ENDPOINT_XFER_INT: + csrh &= ~USB_OUTCSRH_ISO; + csrh |= USB_OUTCSRH_DNYT; + break; + case USB_ENDPOINT_XFER_ISOC: + csrh |= USB_OUTCSRH_ISO; + break; + } + usb_writeb(dev, JZ_REG_UDC_OUTCSRH, csrh); + } + + + ep->stopped = 0; + ep->desc = desc; + ep->pio_irqs = 0; + ep->ep.maxpacket = max; + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + /* Reset halt state (does flush) */ + jz4740_set_halt(_ep, 0); + + DEBUG("%s: enabled %s\n", __FUNCTION__, _ep->name); + + return 0; +} + +/** Disable EP + * NOTE: Sets INDEX register + */ +static int jz4740_ep_disable(struct usb_ep *_ep) +{ + struct jz4740_ep *ep; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct jz4740_ep, ep); + if (!_ep || !ep->desc) { + DEBUG("%s, %s not enabled\n", __FUNCTION__, + _ep ? ep->ep.name : NULL); + return -EINVAL; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + jz_udc_select_ep(ep); + + /* Nuke all pending requests (does flush) */ + nuke(ep, -ESHUTDOWN); + + /* Disable ep IRQ */ + pio_irq_disable(ep); + + ep->desc = 0; + ep->stopped = 1; + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + DEBUG("%s: disabled %s\n", __FUNCTION__, _ep->name); + return 0; +} + +static struct usb_request *jz4740_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) +{ + struct jz4740_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = kzalloc(sizeof(*req), gfp_flags); + if (!req) + return 0; + + INIT_LIST_HEAD(&req->queue); + + return &req->req; +} + +static void jz4740_free_request(struct usb_ep *ep, struct usb_request *_req) +{ + struct jz4740_request *req; + + DEBUG("%s, %p\n", __FUNCTION__, ep); + + req = container_of(_req, struct jz4740_request, req); + WARN_ON(!list_empty(&req->queue)); + kfree(req); +} + +/*--------------------------------------------------------------------*/ + +/** Queue one request + * Kickstart transfer if needed + * NOTE: Sets INDEX register + */ +static int jz4740_queue(struct usb_ep *_ep, struct usb_request *_req, + gfp_t gfp_flags) +{ + struct jz4740_request *req; + struct jz4740_ep *ep; + struct jz4740_udc *dev; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + req = container_of(_req, struct jz4740_request, req); + if (unlikely + (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue))) { + DEBUG("%s, bad params\n", __FUNCTION__); + return -EINVAL; + } + + ep = container_of(_ep, struct jz4740_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->type != ep_control))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -EINVAL; + } + + dev = ep->dev; + if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { + DEBUG("%s, bogus device state %p\n", __FUNCTION__, dev->driver); + return -ESHUTDOWN; + } + + DEBUG("%s queue req %p, len %d buf %p\n", _ep->name, _req, _req->length, + _req->buf); + + spin_lock_irqsave(&dev->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* kickstart this i/o queue? */ + DEBUG("Add to %d Q %d %d\n", ep_index(ep), list_empty(&ep->queue), + ep->stopped); + if (list_empty(&ep->queue) && likely(!ep->stopped)) { + uint32_t csr; + + if (unlikely(ep_index(ep) == 0)) { + /* EP0 */ + list_add_tail(&req->queue, &ep->queue); + jz4740_ep0_kick(dev, ep); + req = 0; + } else if (use_dma) { + /* DMA */ + kick_dma(ep, req); + } + /* PIO */ + else if (ep_is_in(ep)) { + /* EP1 & EP2 */ + jz_udc_set_index(dev, ep_index(ep)); + csr = usb_readb(dev, ep->csr); + pio_irq_enable(ep); + if (!(csr & USB_INCSR_FFNOTEMPT)) { + if (write_fifo(ep, req) == 1) + req = 0; + } + } else { + /* EP1 */ + jz_udc_set_index(dev, ep_index(ep)); + csr = usb_readb(dev, ep->csr); + pio_irq_enable(ep); + if (csr & USB_OUTCSR_OUTPKTRDY) { + if (read_fifo(ep, req) == 1) + req = 0; + } + } + } + + /* pio or dma irq handler advances the queue. */ + if (likely(req != 0)) + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&dev->lock, flags); + + return 0; +} + +/* dequeue JUST ONE request */ +static int jz4740_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct jz4740_ep *ep; + struct jz4740_request *req; + unsigned long flags; + + DEBUG("%s, %p\n", __FUNCTION__, _ep); + + ep = container_of(_ep, struct jz4740_ep, ep); + if (!_ep || ep->type == ep_control) + return -EINVAL; + + spin_lock_irqsave(&ep->dev->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->dev->lock, flags); + return -EINVAL; + } + done(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->dev->lock, flags); + return 0; +} + +/** Return bytes in EP FIFO + * NOTE: Sets INDEX register to EP + */ +static int jz4740_fifo_status(struct usb_ep *_ep) +{ + uint32_t csr; + int count = 0; + struct jz4740_ep *ep; + unsigned long flags; + + ep = container_of(_ep, struct jz4740_ep, ep); + if (!_ep) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return -ENODEV; + } + + DEBUG("%s, %d\n", __FUNCTION__, ep_index(ep)); + + /* LPD can't report unclaimed bytes from IN fifos */ + if (ep_is_in(ep)) + return -EOPNOTSUPP; + + spin_lock_irqsave(&ep->dev->lock, flags); + jz_udc_set_index(ep->dev, ep_index(ep)); + + csr = usb_readb(ep->dev, ep->csr); + if (ep->dev->gadget.speed != USB_SPEED_UNKNOWN || + csr & 0x1) { + count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); + } + + spin_unlock_irqrestore(&ep->dev->lock, flags); + + return count; +} + +/** Flush EP FIFO + * NOTE: Sets INDEX register to EP + */ +static void jz4740_fifo_flush(struct usb_ep *_ep) +{ + struct jz4740_ep *ep; + unsigned long flags; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + ep = container_of(_ep, struct jz4740_ep, ep); + if (unlikely(!_ep || (!ep->desc && ep->type == ep_control))) { + DEBUG("%s, bad ep\n", __FUNCTION__); + return; + } + + spin_lock_irqsave(&ep->dev->lock, flags); + + jz_udc_set_index(ep->dev, ep_index(ep)); + flush(ep); + + spin_unlock_irqrestore(&ep->dev->lock, flags); +} + +/****************************************************************/ +/* End Point 0 related functions */ +/****************************************************************/ + +/* return: 0 = still running, 1 = completed, negative = errno */ +static int write_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) +{ + uint32_t max; + unsigned count; + int is_last; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + max = ep_maxpacket(ep); + + count = write_packet(ep, req, max); + + /* last packet is usually short (or a zlp) */ + if (unlikely(count != max)) + is_last = 1; + else { + if (likely(req->req.length != req->req.actual) || req->req.zero) + is_last = 0; + else + is_last = 1; + } + + DEBUG_EP0("%s: wrote %s %d bytes%s %d left %p\n", __FUNCTION__, + ep->ep.name, count, + is_last ? "/L" : "", req->req.length - req->req.actual, req); + + /* requests complete when all IN data is in the FIFO */ + if (is_last) { + done(ep, req, 0); + return 1; + } + + return 0; +} + +static inline int jz4740_fifo_read(struct jz4740_ep *ep, + unsigned char *cp, int max) +{ + int bytes; + int count = usb_readw(ep->dev, JZ_REG_UDC_OUTCOUNT); + + if (count > max) + count = max; + bytes = count; + while (count--) + *cp++ = usb_readb(ep->dev, ep->fifo); + + return bytes; +} + +static inline void jz4740_fifo_write(struct jz4740_ep *ep, + unsigned char *cp, int count) +{ + DEBUG("fifo_write: %d %d\n", ep_index(ep), count); + while (count--) + usb_writeb(ep->dev, ep->fifo, *cp++); +} + +static int read_fifo_ep0(struct jz4740_ep *ep, struct jz4740_request *req) +{ + struct jz4740_udc *dev = ep->dev; + uint32_t csr; + uint8_t *buf; + unsigned bufferspace, count, is_short; + + DEBUG_EP0("%s\n", __FUNCTION__); + + csr = usb_readb(dev, JZ_REG_UDC_CSR0); + if (!(csr & USB_CSR0_OUTPKTRDY)) + return 0; + + buf = req->req.buf + req->req.actual; + prefetchw(buf); + bufferspace = req->req.length - req->req.actual; + + /* read all bytes from this packet */ + if (likely(csr & USB_CSR0_OUTPKTRDY)) { + count = usb_readw(dev, JZ_REG_UDC_OUTCOUNT); + req->req.actual += min(count, bufferspace); + } else /* zlp */ + count = 0; + + is_short = (count < ep->ep.maxpacket); + DEBUG_EP0("read %s %02x, %d bytes%s req %p %d/%d\n", + ep->ep.name, csr, count, + is_short ? "/S" : "", req, req->req.actual, req->req.length); + + while (likely(count-- != 0)) { + uint8_t byte = (uint8_t)usb_readl(dev, ep->fifo); + + if (unlikely(bufferspace == 0)) { + /* this happens when the driver's buffer + * is smaller than what the host sent. + * discard the extra data. + */ + if (req->req.status != -EOVERFLOW) + DEBUG_EP0("%s overflow %d\n", ep->ep.name, + count); + req->req.status = -EOVERFLOW; + } else { + *buf++ = byte; + bufferspace--; + } + } + + /* completion */ + if (is_short || req->req.actual == req->req.length) { + done(ep, req, 0); + return 1; + } + + /* finished that packet. the next one may be waiting... */ + return 0; +} + +/** + * udc_set_address - set the USB address for this device + * @address: + * + * Called from control endpoint function after it decodes a set address setup packet. + */ +static void udc_set_address(struct jz4740_udc *dev, unsigned char address) +{ + DEBUG_EP0("%s: %d\n", __FUNCTION__, address); + + dev->usb_address = address; + usb_writeb(dev, JZ_REG_UDC_FADDR, address); +} + +/* + * DATA_STATE_RECV (USB_CSR0_OUTPKTRDY) + * - if error + * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits + * - else + * set USB_CSR0_SVDOUTPKTRDY bit + if last set USB_CSR0_DATAEND bit + */ +static void jz4740_ep0_out(struct jz4740_udc *dev, uint32_t csr, int kickstart) +{ + struct jz4740_request *req; + struct jz4740_ep *ep = &dev->ep[0]; + int ret; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct jz4740_request, queue); + + if (req) { + if (req->req.length == 0) { + DEBUG_EP0("ZERO LENGTH OUT!\n"); + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; + return; + } else if (kickstart) { + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY)); + return; + } + ret = read_fifo_ep0(ep, req); + if (ret) { + /* Done! */ + DEBUG_EP0("%s: finished, waiting for status\n", + __FUNCTION__); + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; + } else { + /* Not done yet.. */ + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); + } + } else { + DEBUG_EP0("NO REQ??!\n"); + } +} + +/* + * DATA_STATE_XMIT + */ +static int jz4740_ep0_in(struct jz4740_udc *dev, uint32_t csr) +{ + struct jz4740_request *req; + struct jz4740_ep *ep = &dev->ep[0]; + int ret, need_zlp = 0; + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + if (list_empty(&ep->queue)) + req = 0; + else + req = list_entry(ep->queue.next, struct jz4740_request, queue); + + if (!req) { + DEBUG_EP0("%s: NULL REQ\n", __FUNCTION__); + return 0; + } + + if (req->req.length == 0) { + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; + return 1; + } + + if (req->req.length - req->req.actual == EP0_MAXPACKETSIZE) { + /* Next write will end with the packet size, */ + /* so we need zero-length-packet */ + need_zlp = 1; + } + + ret = write_fifo_ep0(ep, req); + + if (ret == 1 && !need_zlp) { + /* Last packet */ + DEBUG_EP0("%s: finished, waiting for status\n", __FUNCTION__); + + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; + } else { + DEBUG_EP0("%s: not finished\n", __FUNCTION__); + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); + } + + if (need_zlp) { + DEBUG_EP0("%s: Need ZLP!\n", __FUNCTION__); + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_INPKTRDY); + dev->ep0state = DATA_STATE_NEED_ZLP; + } + + return 1; +} + +static int jz4740_handle_get_status(struct jz4740_udc *dev, + struct usb_ctrlrequest *ctrl) +{ + struct jz4740_ep *ep0 = &dev->ep[0]; + struct jz4740_ep *qep; + int reqtype = (ctrl->bRequestType & USB_RECIP_MASK); + uint16_t val = 0; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + + if (reqtype == USB_RECIP_INTERFACE) { + /* This is not supported. + * And according to the USB spec, this one does nothing.. + * Just return 0 + */ + DEBUG_SETUP("GET_STATUS: USB_RECIP_INTERFACE\n"); + } else if (reqtype == USB_RECIP_DEVICE) { + DEBUG_SETUP("GET_STATUS: USB_RECIP_DEVICE\n"); + val |= (1 << 0); /* Self powered */ + /*val |= (1<<1); *//* Remote wakeup */ + } else if (reqtype == USB_RECIP_ENDPOINT) { + int ep_num = (ctrl->wIndex & ~USB_DIR_IN); + + DEBUG_SETUP + ("GET_STATUS: USB_RECIP_ENDPOINT (%d), ctrl->wLength = %d\n", + ep_num, ctrl->wLength); + + if (ctrl->wLength > 2 || ep_num > 3) + return -EOPNOTSUPP; + + qep = &dev->ep[ep_num]; + if (ep_is_in(qep) != ((ctrl->wIndex & USB_DIR_IN) ? 1 : 0) + && ep_index(qep) != 0) { + return -EOPNOTSUPP; + } + + jz_udc_set_index(dev, ep_index(qep)); + + /* Return status on next IN token */ + switch (qep->type) { + case ep_control: + val = + (usb_readb(dev, qep->csr) & USB_CSR0_SENDSTALL) == + USB_CSR0_SENDSTALL; + break; + case ep_bulk_in: + case ep_interrupt: + val = + (usb_readb(dev, qep->csr) & USB_INCSR_SENDSTALL) == + USB_INCSR_SENDSTALL; + break; + case ep_bulk_out: + val = + (usb_readb(dev, qep->csr) & USB_OUTCSR_SENDSTALL) == + USB_OUTCSR_SENDSTALL; + break; + } + + /* Back to EP0 index */ + jz_udc_set_index(dev, 0); + + DEBUG_SETUP("GET_STATUS, ep: %d (%x), val = %d\n", ep_num, + ctrl->wIndex, val); + } else { + DEBUG_SETUP("Unknown REQ TYPE: %d\n", reqtype); + return -EOPNOTSUPP; + } + + /* Clear "out packet ready" */ + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); + /* Put status to FIFO */ + jz4740_fifo_write(ep0, (uint8_t *)&val, sizeof(val)); + /* Issue "In packet ready" */ + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); + + return 0; +} + +/* + * WAIT_FOR_SETUP (OUTPKTRDY) + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL bits + * - else + * set USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND bits + */ +static void jz4740_ep0_setup(struct jz4740_udc *dev, uint32_t csr) +{ + struct jz4740_ep *ep = &dev->ep[0]; + struct usb_ctrlrequest ctrl; + int i; + + DEBUG_SETUP("%s: %x\n", __FUNCTION__, csr); + + /* Nuke all previous transfers */ + nuke(ep, -EPROTO); + + /* read control req from fifo (8 bytes) */ + jz4740_fifo_read(ep, (unsigned char *)&ctrl, 8); + + DEBUG_SETUP("SETUP %02x.%02x v%04x i%04x l%04x\n", + ctrl.bRequestType, ctrl.bRequest, + ctrl.wValue, ctrl.wIndex, ctrl.wLength); + + /* Set direction of EP0 */ + if (likely(ctrl.bRequestType & USB_DIR_IN)) { + ep->bEndpointAddress |= USB_DIR_IN; + } else { + ep->bEndpointAddress &= ~USB_DIR_IN; + } + + /* Handle some SETUP packets ourselves */ + switch (ctrl.bRequest) { + case USB_REQ_SET_ADDRESS: + if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + + DEBUG_SETUP("USB_REQ_SET_ADDRESS (%d)\n", ctrl.wValue); + udc_set_address(dev, ctrl.wValue); + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); + return; + + case USB_REQ_SET_CONFIGURATION: + if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + + DEBUG_SETUP("USB_REQ_SET_CONFIGURATION (%d)\n", ctrl.wValue); +/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ + + /* Enable RESUME and SUSPEND interrupts */ + usb_setb(dev, JZ_REG_UDC_INTRUSBE, (USB_INTR_RESUME | USB_INTR_SUSPEND)); + break; + + case USB_REQ_SET_INTERFACE: + if (ctrl.bRequestType != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) + break; + + DEBUG_SETUP("USB_REQ_SET_INTERFACE (%d)\n", ctrl.wValue); +/* usb_setb(JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND));*/ + break; + + case USB_REQ_GET_STATUS: + if (jz4740_handle_get_status(dev, &ctrl) == 0) + return; + + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + if (ctrl.bRequestType == USB_RECIP_ENDPOINT) { + struct jz4740_ep *qep; + int ep_num = (ctrl.wIndex & 0x0f); + + /* Support only HALT feature */ + if (ctrl.wValue != 0 || ctrl.wLength != 0 + || ep_num > 3 || ep_num < 1) + break; + + qep = &dev->ep[ep_num]; + spin_unlock(&dev->lock); + if (ctrl.bRequest == USB_REQ_SET_FEATURE) { + DEBUG_SETUP("SET_FEATURE (%d)\n", + ep_num); + jz4740_set_halt(&qep->ep, 1); + } else { + DEBUG_SETUP("CLR_FEATURE (%d)\n", + ep_num); + jz4740_set_halt(&qep->ep, 0); + } + spin_lock(&dev->lock); + + jz_udc_set_index(dev, 0); + + /* Reply with a ZLP on next IN token */ + usb_setb(dev, JZ_REG_UDC_CSR0, + (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND)); + return; + } + break; + + default: + break; + } + + /* gadget drivers see class/vendor specific requests, + * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, + * and more. + */ + if (dev->driver) { + /* device-2-host (IN) or no data setup command, process immediately */ + spin_unlock(&dev->lock); + + i = dev->driver->setup(&dev->gadget, &ctrl); + spin_lock(&dev->lock); + + if (unlikely(i < 0)) { + /* setup processing failed, force stall */ + DEBUG_SETUP + (" --> ERROR: gadget setup FAILED (stalling), setup returned %d\n", + i); + jz_udc_set_index(dev, 0); + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND | USB_CSR0_SENDSTALL)); + + /* ep->stopped = 1; */ + dev->ep0state = WAIT_FOR_SETUP; + } + else { + DEBUG_SETUP("gadget driver setup ok (%d)\n", ctrl.wLength); +/* if (!ctrl.wLength) { + usb_setb(JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); + }*/ + } + } +} + +/* + * DATA_STATE_NEED_ZLP + */ +static void jz4740_ep0_in_zlp(struct jz4740_udc *dev, uint32_t csr) +{ + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + usb_setb(dev, JZ_REG_UDC_CSR0, (USB_CSR0_INPKTRDY | USB_CSR0_DATAEND)); + dev->ep0state = WAIT_FOR_SETUP; +} + +/* + * handle ep0 interrupt + */ +static void jz4740_handle_ep0(struct jz4740_udc *dev, uint32_t intr) +{ + struct jz4740_ep *ep = &dev->ep[0]; + uint32_t csr; + + DEBUG("%s:%s[%d]\n", __FILE__, __func__, __LINE__); + /* Set index 0 */ + jz_udc_set_index(dev, 0); + csr = usb_readb(dev, JZ_REG_UDC_CSR0); + + DEBUG_EP0("%s: csr = %x state = \n", __FUNCTION__, csr);//, state_names[dev->ep0state]); + + /* + * if SENT_STALL is set + * - clear the SENT_STALL bit + */ + if (csr & USB_CSR0_SENTSTALL) { + DEBUG_EP0("%s: USB_CSR0_SENTSTALL is set: %x\n", __FUNCTION__, csr); + usb_clearb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SENDSTALL | USB_CSR0_SENTSTALL); + nuke(ep, -ECONNABORTED); + dev->ep0state = WAIT_FOR_SETUP; + return; + } + + /* + * if a transfer is in progress && INPKTRDY and OUTPKTRDY are clear + * - fill EP0 FIFO + * - if last packet + * - set IN_PKT_RDY | DATA_END + * - else + * set IN_PKT_RDY + */ + if (!(csr & (USB_CSR0_INPKTRDY | USB_CSR0_OUTPKTRDY))) { + DEBUG_EP0("%s: INPKTRDY and OUTPKTRDY are clear\n", + __FUNCTION__); + + switch (dev->ep0state) { + case DATA_STATE_XMIT: + DEBUG_EP0("continue with DATA_STATE_XMIT\n"); + jz4740_ep0_in(dev, csr); + return; + case DATA_STATE_NEED_ZLP: + DEBUG_EP0("continue with DATA_STATE_NEED_ZLP\n"); + jz4740_ep0_in_zlp(dev, csr); + return; + default: + /* Stall? */ +// DEBUG_EP0("Odd state!! state = %s\n", +// state_names[dev->ep0state]); + dev->ep0state = WAIT_FOR_SETUP; + /* nuke(ep, 0); */ + /* usb_setb(ep->csr, USB_CSR0_SENDSTALL); */ +// break; + return; + } + } + + /* + * if SETUPEND is set + * - abort the last transfer + * - set SERVICED_SETUP_END_BIT + */ + if (csr & USB_CSR0_SETUPEND) { + DEBUG_EP0("%s: USB_CSR0_SETUPEND is set: %x\n", __FUNCTION__, csr); + + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDSETUPEND); + nuke(ep, 0); + dev->ep0state = WAIT_FOR_SETUP; + } + + /* + * if USB_CSR0_OUTPKTRDY is set + * - read data packet from EP0 FIFO + * - decode command + * - if error + * set SVDOUTPKTRDY | DATAEND | SENDSTALL bits + * - else + * set SVDOUTPKTRDY | DATAEND bits + */ + if (csr & USB_CSR0_OUTPKTRDY) { + + DEBUG_EP0("%s: EP0_OUT_PKT_RDY is set: %x\n", __FUNCTION__, + csr); + + switch (dev->ep0state) { + case WAIT_FOR_SETUP: + DEBUG_EP0("WAIT_FOR_SETUP\n"); + jz4740_ep0_setup(dev, csr); + break; + + case DATA_STATE_RECV: + DEBUG_EP0("DATA_STATE_RECV\n"); + jz4740_ep0_out(dev, csr, 0); + break; + + default: + /* send stall? */ + DEBUG_EP0("strange state!! 2. send stall? state = %d\n", + dev->ep0state); + break; + } + } +} + +static void jz4740_ep0_kick(struct jz4740_udc *dev, struct jz4740_ep *ep) +{ + uint32_t csr; + + jz_udc_set_index(dev, 0); + + DEBUG_EP0("%s: %x\n", __FUNCTION__, csr); + + /* Clear "out packet ready" */ + + if (ep_is_in(ep)) { + usb_setb(dev, JZ_REG_UDC_CSR0, USB_CSR0_SVDOUTPKTRDY); + csr = usb_readb(dev, JZ_REG_UDC_CSR0); + dev->ep0state = DATA_STATE_XMIT; + jz4740_ep0_in(dev, csr); + } else { + csr = usb_readb(dev, JZ_REG_UDC_CSR0); + dev->ep0state = DATA_STATE_RECV; + jz4740_ep0_out(dev, csr, 1); + } +} + +/** Handle USB RESET interrupt + */ +static void jz4740_reset_irq(struct jz4740_udc *dev) +{ + dev->gadget.speed = (usb_readb(dev, JZ_REG_UDC_POWER) & USB_POWER_HSMODE) ? + USB_SPEED_HIGH : USB_SPEED_FULL; + + DEBUG_SETUP("%s: address = %d, speed = %s\n", __FUNCTION__, dev->usb_address, + (dev->gadget.speed == USB_SPEED_HIGH) ? "HIGH":"FULL" ); +} + +/* + * jz4740 usb device interrupt handler. + */ +static irqreturn_t jz4740_udc_irq(int irq, void *_dev) +{ + struct jz4740_udc *dev = _dev; + uint8_t index; + + uint32_t intr_usb = usb_readb(dev, JZ_REG_UDC_INTRUSB) & 0x7; /* mask SOF */ + uint32_t intr_in = usb_readw(dev, JZ_REG_UDC_INTRIN); + uint32_t intr_out = usb_readw(dev, JZ_REG_UDC_INTROUT); + uint32_t intr_dma = usb_readb(dev, JZ_REG_UDC_INTR); + + if (!intr_usb && !intr_in && !intr_out && !intr_dma) + return IRQ_HANDLED; + + + DEBUG("intr_out=%x intr_in=%x intr_usb=%x\n", + intr_out, intr_in, intr_usb); + + spin_lock(&dev->lock); + index = usb_readb(dev, JZ_REG_UDC_INDEX); + + /* Check for resume from suspend mode */ + if ((intr_usb & USB_INTR_RESUME) && + (usb_readb(dev, JZ_REG_UDC_INTRUSBE) & USB_INTR_RESUME)) { + DEBUG("USB resume\n"); + dev->driver->resume(&dev->gadget); /* We have suspend(), so we must have resume() too. */ + } + + /* Check for system interrupts */ + if (intr_usb & USB_INTR_RESET) { + DEBUG("USB reset\n"); + jz4740_reset_irq(dev); + } + + /* Check for endpoint 0 interrupt */ + if (intr_in & USB_INTR_EP0) { + DEBUG("USB_INTR_EP0 (control)\n"); + jz4740_handle_ep0(dev, intr_in); + } + + /* Check for Bulk-IN DMA interrupt */ + if (intr_dma & 0x1) { + int ep_num; + struct jz4740_ep *ep; + ep_num = (usb_readl(dev, JZ_REG_UDC_CNTL1) >> 4) & 0xf; + ep = &dev->ep[ep_num + 1]; + jz_udc_set_index(dev, ep_num); + usb_setb(dev, ep->csr, USB_INCSR_INPKTRDY); +/* jz4740_in_epn(dev, ep_num, intr_in);*/ + } + + /* Check for Bulk-OUT DMA interrupt */ + if (intr_dma & 0x2) { + int ep_num; + ep_num = (usb_readl(dev, JZ_REG_UDC_CNTL2) >> 4) & 0xf; + jz4740_out_epn(dev, ep_num, intr_out); + } + + /* Check for each configured endpoint interrupt */ + if (intr_in & USB_INTR_INEP1) { + DEBUG("USB_INTR_INEP1\n"); + jz4740_in_epn(dev, 1, intr_in); + } + + if (intr_in & USB_INTR_INEP2) { + DEBUG("USB_INTR_INEP2\n"); + jz4740_in_epn(dev, 2, intr_in); + } + + if (intr_out & USB_INTR_OUTEP1) { + DEBUG("USB_INTR_OUTEP1\n"); + jz4740_out_epn(dev, 1, intr_out); + } + + /* Check for suspend mode */ + if ((intr_usb & USB_INTR_SUSPEND) && + (usb_readb(dev, JZ_REG_UDC_INTRUSBE) & USB_INTR_SUSPEND)) { + DEBUG("USB suspend\n"); + dev->driver->suspend(&dev->gadget); + /* Host unloaded from us, can do something, such as flushing + the NAND block cache etc. */ + } + + jz_udc_set_index(dev, index); + + spin_unlock(&dev->lock); + + return IRQ_HANDLED; +} + + + +/*-------------------------------------------------------------------------*/ + +/* Common functions - Added by River */ +static struct jz4740_udc udc_dev; + +static inline struct jz4740_udc *gadget_to_udc(struct usb_gadget *gadget) +{ + return container_of(gadget, struct jz4740_udc, gadget); +} +/* End added */ + +static int jz4740_udc_get_frame(struct usb_gadget *_gadget) +{ + DEBUG("%s, %p\n", __FUNCTION__, _gadget); + return usb_readw(gadget_to_udc(_gadget), JZ_REG_UDC_FRAME); +} + +static int jz4740_udc_wakeup(struct usb_gadget *_gadget) +{ + /* host may not have enabled remote wakeup */ + /*if ((UDCCS0 & UDCCS0_DRWF) == 0) + return -EHOSTUNREACH; + udc_set_mask_UDCCR(UDCCR_RSM); */ + return -ENOTSUPP; +} + +static int jz4740_udc_pullup(struct usb_gadget *_gadget, int on) +{ + struct jz4740_udc *udc = gadget_to_udc(_gadget); + + unsigned long flags; + + local_irq_save(flags); + + if (on) { + udc->state = UDC_STATE_ENABLE; + udc_enable(udc); + } else { + udc->state = UDC_STATE_DISABLE; + udc_disable(udc); + } + + local_irq_restore(flags); + + return 0; +} + +static const struct usb_gadget_ops jz4740_udc_ops = { + .get_frame = jz4740_udc_get_frame, + .wakeup = jz4740_udc_wakeup, + .pullup = jz4740_udc_pullup, + /* current versions must always be self-powered */ +}; + +static struct usb_ep_ops jz4740_ep_ops = { + .enable = jz4740_ep_enable, + .disable = jz4740_ep_disable, + + .alloc_request = jz4740_alloc_request, + .free_request = jz4740_free_request, + + .queue = jz4740_queue, + .dequeue = jz4740_dequeue, + + .set_halt = jz4740_set_halt, + .fifo_status = jz4740_fifo_status, + .fifo_flush = jz4740_fifo_flush, +}; + + +/*-------------------------------------------------------------------------*/ + +static struct jz4740_udc udc_dev = { + .usb_address = 0, + .gadget = { + .ops = &jz4740_udc_ops, + .ep0 = &udc_dev.ep[0].ep, + .name = "jz-udc", + .dev = { + .init_name = "gadget", + }, + }, + + /* control endpoint */ + .ep[0] = { + .ep = { + .name = "ep0", + .ops = &jz4740_ep_ops, + .maxpacket = EP0_MAXPACKETSIZE, + }, + .dev = &udc_dev, + + .bEndpointAddress = 0, + .bmAttributes = 0, + + .type = ep_control, + .fifo = JZ_REG_UDC_EP_FIFO(0), + .csr = JZ_REG_UDC_CSR0, + }, + + /* bulk out endpoint */ + .ep[1] = { + .ep = { + .name = "ep1out-bulk", + .ops = &jz4740_ep_ops, + .maxpacket = EPBULK_MAXPACKETSIZE, + }, + .dev = &udc_dev, + + .bEndpointAddress = 1, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .type = ep_bulk_out, + .fifo = JZ_REG_UDC_EP_FIFO(1), + .csr = JZ_REG_UDC_OUTCSR, + }, + + /* bulk in endpoint */ + .ep[2] = { + .ep = { + .name = "ep1in-bulk", + .ops = &jz4740_ep_ops, + .maxpacket = EPBULK_MAXPACKETSIZE, + }, + .dev = &udc_dev, + + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + + .type = ep_bulk_in, + .fifo = JZ_REG_UDC_EP_FIFO(1), + .csr = JZ_REG_UDC_INCSR, + }, + + /* interrupt in endpoint */ + .ep[3] = { + .ep = { + .name = "ep2in-int", + .ops = &jz4740_ep_ops, + .maxpacket = EPINTR_MAXPACKETSIZE, + }, + .dev = &udc_dev, + + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + + .type = ep_interrupt, + .fifo = JZ_REG_UDC_EP_FIFO(2), + .csr = JZ_REG_UDC_INCSR, + }, +}; + +static void gadget_release(struct device *_dev) +{ +} + + +static int jz4740_udc_probe(struct platform_device *pdev) +{ + struct jz4740_udc *dev = &udc_dev; + int ret; + + spin_lock_init(&dev->lock); + the_controller = dev; + + dev->dev = &pdev->dev; + dev_set_name(&dev->gadget.dev, "gadget"); + dev->gadget.dev.parent = &pdev->dev; + dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + dev->gadget.dev.release = gadget_release; + + ret = device_register(&dev->gadget.dev); + if (ret) + return ret; + + platform_set_drvdata(pdev, dev); + + dev->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!dev->mem) { + ret = -ENOENT; + dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); + goto err_device_unregister; + } + + dev->mem = request_mem_region(dev->mem->start, resource_size(dev->mem), pdev->name); + + if (!dev->mem) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to request mmio memory region\n"); + goto err_device_unregister; + } + + dev->base = ioremap(dev->mem->start, resource_size(dev->mem)); + + if (!dev->base) { + ret = -EBUSY; + dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); + goto err_release_mem_region; + } + + dev->irq = platform_get_irq(pdev, 0); + + ret = request_irq(dev->irq, jz4740_udc_irq, IRQF_DISABLED, + pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", ret); + goto err_iounmap; + } + + udc_disable(dev); + udc_reinit(dev); + + return 0; + +err_iounmap: + iounmap(dev->base); +err_release_mem_region: + release_mem_region(dev->mem->start, resource_size(dev->mem)); +err_device_unregister: + device_unregister(&dev->gadget.dev); + platform_set_drvdata(pdev, NULL); + + the_controller = 0; + + return ret; +} + +static int jz4740_udc_remove(struct platform_device *pdev) +{ + struct jz4740_udc *dev = platform_get_drvdata(pdev); + + if (dev->driver) + return -EBUSY; + + udc_disable(dev); +#ifdef UDC_PROC_FILE + remove_proc_entry(proc_node_name, NULL); +#endif + + free_irq(dev->irq, dev); + iounmap(dev->base); + release_mem_region(dev->mem->start, resource_size(dev->mem)); + + platform_set_drvdata(pdev, NULL); + device_unregister(&dev->gadget.dev); + the_controller = NULL; + + return 0; +} + +static struct platform_driver udc_driver = { + .probe = jz4740_udc_probe, + .remove = jz4740_udc_remove, + .driver = { + .name = "jz-udc", + .owner = THIS_MODULE, + }, +}; + +/*-------------------------------------------------------------------------*/ + +static int __init udc_init (void) +{ + return platform_driver_register(&udc_driver); +} + +static void __exit udc_exit (void) +{ + platform_driver_unregister(&udc_driver); +} + +module_init(udc_init); +module_exit(udc_exit); + +MODULE_DESCRIPTION("JZ4740 USB Device Controller"); +MODULE_AUTHOR("Wei Jianli "); +MODULE_LICENSE("GPL"); diff -ruN linux-2.6.31-vanilla/drivers/usb/gadget/jz4740_udc.h linux-2.6.31/drivers/usb/gadget/jz4740_udc.h --- linux-2.6.31-vanilla/drivers/usb/gadget/jz4740_udc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/usb/gadget/jz4740_udc.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,97 @@ +/* + * linux/drivers/usb/gadget/jz4740_udc.h + * + * Ingenic JZ4740 on-chip high speed USB device controller + * + * Copyright (C) 2006 Ingenic Semiconductor Inc. + * Author: + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __USB_GADGET_JZ4740_H__ +#define __USB_GADGET_JZ4740_H__ + +/*-------------------------------------------------------------------------*/ + +// Max packet size +#define EP0_MAXPACKETSIZE 64 +#define EPBULK_MAXPACKETSIZE 512 +#define EPINTR_MAXPACKETSIZE 64 + +#define UDC_MAX_ENDPOINTS 4 + +/*-------------------------------------------------------------------------*/ + +typedef enum ep_type { + ep_control, ep_bulk_in, ep_bulk_out, ep_interrupt +} ep_type_t; + +struct jz4740_ep { + struct usb_ep ep; + struct jz4740_udc *dev; + + const struct usb_endpoint_descriptor *desc; + unsigned long pio_irqs; + + uint8_t stopped; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + + ep_type_t type; + size_t fifo; + u32 csr; + + uint32_t reg_addr; + struct list_head queue; +}; + +struct jz4740_request { + struct usb_request req; + struct list_head queue; +}; + +enum ep0state { + WAIT_FOR_SETUP, /* between STATUS ack and SETUP report */ + DATA_STATE_XMIT, /* data tx stage */ + DATA_STATE_NEED_ZLP, /* data tx zlp stage */ + WAIT_FOR_OUT_STATUS, /* status stages */ + DATA_STATE_RECV, /* data rx stage */ +}; + +/* For function binding with UDC Disable - Added by River */ +typedef enum { + UDC_STATE_ENABLE = 0, + UDC_STATE_DISABLE, +}udc_state_t; + +struct jz4740_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct device *dev; + spinlock_t lock; + + enum ep0state ep0state; + struct jz4740_ep ep[UDC_MAX_ENDPOINTS]; + + unsigned char usb_address; + + udc_state_t state; + + struct resource *mem; + void __iomem *base; + int irq; + uint32_t in_mask; + uint32_t out_mask; +}; + +extern struct jz4740_udc *the_controller; + +#define ep_is_in(EP) (((EP)->bEndpointAddress&USB_DIR_IN)==USB_DIR_IN) +#define ep_maxpacket(EP) ((EP)->ep.maxpacket) +#define ep_index(EP) ((EP)->bEndpointAddress&0xF) + +#endif /* __USB_GADGET_JZ4740_H__ */ diff -ruN linux-2.6.31-vanilla/drivers/usb/gadget/udc_hotplug.h linux-2.6.31/drivers/usb/gadget/udc_hotplug.h --- linux-2.6.31-vanilla/drivers/usb/gadget/udc_hotplug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/usb/gadget/udc_hotplug.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,50 @@ +/* + * Ingenic USB Device Contoller Hotplug External Interfaces + */ + +#ifndef __UDC_HOTPLUG_H__ +#define __UDC_HOTPLUG_H__ + +#include + +typedef enum { + BROADCAST_TYPE_STATE = 0, + BROADCAST_TYPE_EVENT, +}udc_hotplug_broadcast_type_t; + +typedef enum { + EVENT_STATE_OFFLINE = 0, + EVENT_STATE_ONLINE, +}udc_hotplug_event_state_t; + +typedef enum { + EVENT_TYPE_USB = 0, + EVENT_TYPE_CABLE, +}udc_hotplug_event_type_t; + +enum { + EVENT_FLAG_UDC_PHY_TOUCHED = 0, +}; + +typedef struct { + udc_hotplug_event_type_t type; + udc_hotplug_event_state_t state; + unsigned long flags; +}udc_hotplug_event_t; + +/* Register notifier */ +int udc_hotplug_register_notifier(struct notifier_block *n, int request_state); + +/* Unregister notifier */ +int udc_hotplug_unregister_notifier(struct notifier_block *n); + +/* Start keep alive */ +int udc_hotplug_start_keep_alive(unsigned long timer_interval_in_jiffies, unsigned long counter_limit); + +/* Do keep alive */ +void udc_hotplug_do_keep_alive(void); + +/* Stop keep alive */ +void udc_hotplug_stop_keep_alive(void); + +#endif /* Define __UDC_HOTPLUG_H__ */ diff -ruN linux-2.6.31-vanilla/drivers/usb/gadget/udc_hotplug_core.c linux-2.6.31/drivers/usb/gadget/udc_hotplug_core.c --- linux-2.6.31-vanilla/drivers/usb/gadget/udc_hotplug_core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/usb/gadget/udc_hotplug_core.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,836 @@ +/* + * Ingenic USB Device Controller Hotplug Core Function + * Detection mechanism and code are based on the old version of udc_hotplug.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "udc_hotplug.h" + +#define PFX "jz_hotplug_udc" + +#define D(msg, fmt...) \ +// printk(KERN_ERR PFX": %s(): "msg, __func__, ##fmt); + +/* HAVE_DETECT_SYNC + Provide a lock like seqlock keep the synchronization between the start and the end of a detection, + If the lock seems not synchronous(new interrupt comes, when doing our detection) in the end of a detection, + the result of the detection is discarded. No event will be broadcast, and the detection will be restarted. + + Use to filter out more significant events when the interrupt is too noisy. +*/ + +//#define HAVE_DETECT_SYNC 1 + +#if defined (HAVE_DETECT_SYNC) +#define NR_RESTART_TIMES 3 +#define NR_JIFFIES_SLEEP_BEFORE_RESTART 7 +#endif + +#define NR_GPIO_STABLE_TIMES 50 +#define NR_JIFFIES_USB_DETECT_WAIT 11 + +#define DEFAULT_KEEP_ALIVE_TIMER_INTERVAL (2 * HZ) +#define DEFAULT_KEEP_ALIVE_COUNTER_LIMIT 2 + +#define UDC_HOTPLUG_PIN GPIO_UDC_HOTPLUG +#define UDC_HOTPLUG_IRQ (IRQ_GPIO_0 + UDC_HOTPLUG_PIN) + +/* UDC State bits */ +enum { + /* Online state. */ + BIT_CABLE_ONLINE = 0, + BIT_USB_ONLINE, + + /* State changed ?*/ + BIT_CABLE_CHANGE, + BIT_USB_CHANGE, + + /* What detection will be done ? */ + BIT_DO_CABLE_DETECT, + BIT_DO_USB_DETECT, + + /* What detection is requested ? */ + BIT_REQUEST_CABLE_DETECT, + BIT_REQUEST_USB_DETECT, + + /* Indicate whether a detection is finisned. */ + BIT_USB_DETECT_DONE, + BIT_CABLE_DETECT_DONE, + + BIT_UDC_PHY_TOUCHED, + + /* Keep alive */ + BIT_KEEP_ALIVE, + BIT_KEEP_ALIVE_TIMEOUT, +}; + +struct uh_data { + /* Notifier */ + struct blocking_notifier_head notifier_head; + + /* Thread */ + struct task_struct *kthread; + + /* Wait queue */ + wait_queue_head_t kthread_wq; /* Kernel thread sleep here. */ + wait_queue_head_t wq; /* Others sleep here. */ + + /* UDC State */ + unsigned long state; + + /* Current Event */ + udc_hotplug_event_t cur_uh_event; + +#if defined (HAVE_DETECT_SYNC) + /* Sync seq */ + unsigned long irq_sync_seq; + unsigned long our_sync_seq; +#endif + + /* Keep alive */ + struct timer_list keep_alive_timer; + + unsigned long keep_alive_counter_limit; + unsigned long keep_alive_timer_interval; + unsigned long keep_alive_counter; +}; + +static struct uh_data *g_puh_data = NULL; + +#if defined (HAVE_DETECT_SYNC) +/* Seq sync function */ + +static inline int is_seq_sync(struct uh_data *uh) +{ + return (uh->our_sync_seq == uh->irq_sync_seq); +} + +static inline void reset_seq(struct uh_data *uh) +{ + uh->our_sync_seq = uh->irq_sync_seq = 0; + + return; +} + +static inline void sync_seq(struct uh_data *uh) +{ + uh->our_sync_seq = uh->irq_sync_seq; + + return; +} +#endif + +/* Call kernel thread to detect. */ +static inline void start_detect(struct uh_data *uh) +{ + D("called.\n"); + +#if defined (HAVE_DETECT_SYNC) + uh->irq_sync_seq ++; +#endif + + wake_up_process(uh->kthread); + + return; +} + +static void wait_gpio_pin_stable(struct uh_data *uh) +{ + unsigned long pin = 0; + int i = 1; + + pin = __gpio_get_pin(UDC_HOTPLUG_PIN); + + while (i < NR_GPIO_STABLE_TIMES) { + if (__gpio_get_pin(UDC_HOTPLUG_PIN) != pin) { + pin = __gpio_get_pin(UDC_HOTPLUG_PIN); + i = 1; + }else + i++; + + sleep_on_timeout(&uh->wq, 1); + } + + return; +} + +/* Do cable detection */ +static void cable_detect(struct uh_data *uh) +{ + D("Wait pin stable.\n"); + + /* Wait GPIO pin stable first. */ + wait_gpio_pin_stable(uh); + + if (__gpio_get_pin(UDC_HOTPLUG_PIN)) { + D("Cable online.\n"); + + if (!test_and_set_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable state change to online.\n"); + + set_bit(BIT_CABLE_CHANGE, &uh->state); + } + }else { + D("Cable offline.\n"); + + /* Clear keep alive bit. */ + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + if (test_and_clear_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable state change to offline.\n"); + + set_bit(BIT_CABLE_CHANGE, &uh->state); + } + } + + set_bit(BIT_CABLE_DETECT_DONE, &uh->state); + + return; +} + +/* Really do USB detection */ +static int do_usb_detect(struct uh_data *uh) +{ + u32 intr_usb; + int rv; + + D("called.\n"); + + __intc_mask_irq(IRQ_UDC); + + /* Now enable PHY to start detect */ +#ifdef CONFIG_SOC_JZ4740 + REG_CPM_SCR |= CPM_SCR_USBPHY_ENABLE; +#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + REG_CPM_OPCR |= CPM_OPCR_UDCPHY_ENABLE; +#endif + /* Clear IRQs */ + REG16(USB_REG_INTRINE) = 0; + REG16(USB_REG_INTROUTE) = 0; + REG8(USB_REG_INTRUSBE) = 0; + + /* disable UDC IRQs first */ + REG16(USB_REG_INTRINE) = 0; + REG16(USB_REG_INTROUTE) = 0; + REG8(USB_REG_INTRUSBE) = 0; + + /* Disable DMA */ + REG32(USB_REG_CNTL1) = 0; + REG32(USB_REG_CNTL2) = 0; + + /* Enable HS Mode */ + REG8(USB_REG_POWER) |= USB_POWER_HSENAB; + /* Enable soft connect */ + REG8(USB_REG_POWER) |= USB_POWER_SOFTCONN; + + D("enable phy! %x %x %x %x %x\n", + REG8(USB_REG_POWER), + REG_CPM_OPCR, + REG16(USB_REG_INTRINE), + REG16(USB_REG_INTROUTE), + REG8(USB_REG_INTRUSBE)); + + /* Wait a moment. */ + sleep_on_timeout(&uh->wq, NR_JIFFIES_USB_DETECT_WAIT); + + intr_usb = REG8(USB_REG_INTRUSB); + if ((intr_usb & USB_INTR_RESET) || + (intr_usb & USB_INTR_RESUME) || + (intr_usb & USB_INTR_SUSPEND)) + { + rv = 1; + } + else + { + rv = 0; + } + + /* Detect finish ,clean every thing */ + /* Disconnect from usb */ + REG8(USB_REG_POWER) &= ~USB_POWER_SOFTCONN; + /* Disable the USB PHY */ +#ifdef CONFIG_SOC_JZ4740 + REG_CPM_SCR &= ~CPM_SCR_USBPHY_ENABLE; +#elif defined(CONFIG_SOC_JZ4750) || defined(CONFIG_SOC_JZ4750D) + REG_CPM_OPCR &= ~CPM_OPCR_UDCPHY_ENABLE; +#endif + /* Clear IRQs */ + REG16(USB_REG_INTRINE) = 0; + REG16(USB_REG_INTROUTE) = 0; + REG8(USB_REG_INTRUSBE) = 0; + __intc_ack_irq(IRQ_UDC); + __intc_unmask_irq(IRQ_UDC); + + mdelay(1); + + return rv; +} + +/* Do USB bus protocol detection */ +static void usb_detect(struct uh_data *uh) +{ + int rv = 0; + + D("Called.\n"); + + /* If the cable has already been offline, we just pass the real USB detection. */ + if (test_bit(BIT_CABLE_ONLINE, &uh->state)) { + + D("Do real detection.\n"); + + rv = do_usb_detect(uh); + set_bit(BIT_UDC_PHY_TOUCHED, &uh->state); + }else{ + clear_bit(BIT_UDC_PHY_TOUCHED, &uh->state); + D("No need to do real detection.\n"); + } + + if (rv) { + if (!test_and_set_bit(BIT_USB_ONLINE, &uh->state)) + set_bit(BIT_USB_CHANGE, &uh->state); + }else{ + /* Clear keep alive bit. */ + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + if (test_and_clear_bit(BIT_USB_ONLINE, &uh->state)) + set_bit(BIT_USB_CHANGE, &uh->state); + } + + set_bit(BIT_USB_DETECT_DONE, &uh->state); + return; +} + +/* USB is active ? */ +static int usb_is_active(void) +{ + unsigned long tmp; + + tmp = REG16(USB_REG_FRAME); + + mdelay(2); /* USB 1.1 Frame length is 1ms, USB 2.0 HS Frame length is 125us */ + + rmb(); + + return tmp == REG16(USB_REG_FRAME) ? 0 : 1; +} + +/* Broadcast event to notifier */ +static void do_broadcast_event(struct uh_data *uh) +{ + udc_hotplug_event_t *e = &uh->cur_uh_event; + + /* Collect Information */ + if (test_and_clear_bit(BIT_CABLE_CHANGE, &uh->state)) { + e->type = EVENT_TYPE_CABLE; + e->state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + e->flags = 0; + + D("Broadcast cable event -> State: %s.\n", (e->state == EVENT_STATE_ONLINE ? "Online" : "Offline")); + + /* Kick chain. */ + blocking_notifier_call_chain(&uh->notifier_head, BROADCAST_TYPE_EVENT, e); + } + + if (test_and_clear_bit(BIT_USB_CHANGE, &uh->state)) { + e->type = EVENT_TYPE_USB; + e->state = (test_bit(BIT_USB_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE : EVENT_STATE_OFFLINE; + e->flags = 0; + + if (test_bit(BIT_UDC_PHY_TOUCHED, &uh->state)) { + set_bit(EVENT_FLAG_UDC_PHY_TOUCHED, &e->flags); + } + + D("Broadcast USB event -> State: %s.\n", (e->state == EVENT_STATE_ONLINE ? "Online" : "Offline")); + + /* Kick chain. */ + blocking_notifier_call_chain(&uh->notifier_head, BROADCAST_TYPE_EVENT, e); + } + + return; +} + +/* Handle pending request */ +static inline void handle_request(struct uh_data *uh) +{ + if (test_and_clear_bit(BIT_REQUEST_CABLE_DETECT, &uh->state)) + set_bit(BIT_DO_CABLE_DETECT, &uh->state); + + if (test_and_clear_bit(BIT_REQUEST_USB_DETECT, &uh->state)) + set_bit(BIT_DO_USB_DETECT, &uh->state); + + return; +} + +/* Have pending request ? */ +static inline int pending_request(struct uh_data *uh) +{ + if (test_bit(BIT_REQUEST_CABLE_DETECT, &uh->state) || test_bit(BIT_REQUEST_USB_DETECT, &uh->state)) + return 1; + else + return 0; +} + +#if defined (HAVE_DETECT_SYNC) +static void prepare_restart(struct uh_data *uh, wait_queue_head_t *wq) +{ + + D("Called.\n"); + + if (test_bit(BIT_CABLE_DETECT_DONE, &uh->state)) + set_bit(BIT_DO_CABLE_DETECT, &uh->state); + + if (test_bit(BIT_USB_DETECT_DONE, &uh->state)) + set_bit(BIT_DO_USB_DETECT, &uh->state); + + sleep_on_timeout(wq, NR_JIFFIES_SLEEP_BEFORE_RESTART); + + sync_seq(uh); + + return; +} + +/* Called from kernel thread */ +static void udc_pnp_detect(struct uh_data *uh) +{ + int nr_restart = 0; + + D("Do UDC detection.\n"); + + while (nr_restart != NR_RESTART_TIMES) { + /* Do cable detection ? */ + if (test_bit(BIT_DO_CABLE_DETECT, &uh->state)) { + D("Do cable detection.\n"); + + cable_detect(uh); + } + + /* Need restart ? */ + if (!is_seq_sync(uh)) { + nr_restart ++; + + prepare_restart(uh, &uh->wq); + continue; + } + + /* Do USB detection ? */ + if (test_bit(BIT_DO_USB_DETECT, &uh->state)) { + D("Do USB detection.\n"); + + usb_detect(uh); + } + + /* Need restart ? */ + if (!is_seq_sync(uh)) { + nr_restart ++; + + prepare_restart(uh, &uh->wq); + continue; + } + + /* Done */ + D("Done.\n"); + + clear_bit(BIT_DO_CABLE_DETECT, &uh->state); + clear_bit(BIT_DO_USB_DETECT, &uh->state); + + break; + } + + return; +} + +static inline void broadcast_event(struct uh_data *uh) +{ + /* Sync ? */ + if (is_seq_sync(uh)) { + D("Sync -> Broadcast event.\n"); + + do_broadcast_event(uh); + }else{ + D("Not sync -> Prepare restarting.\n"); + + prepare_restart(uh, &uh->kthread_wq); + } +} + +static inline void udc_pnp_thread_sleep(struct uh_data *uh) +{ + /* Sync ? -> Sleep. */ + if ( !pending_request(uh) || is_seq_sync(uh)) { + D("Sleep.\n"); + + sleep_on(&uh->kthread_wq); + } + + return; +} + +#else /* !HAVE_DETECT_SYNC */ + +/* Called from kernel thread */ +static void udc_pnp_detect(struct uh_data *uh) +{ + D("Do UDC detection.\n"); + + /* Do cable detection ? */ + if (test_bit(BIT_DO_CABLE_DETECT, &uh->state)) { + D("Do cable detection.\n"); + + cable_detect(uh); + } + + /* Do USB detection ? */ + if (test_bit(BIT_DO_USB_DETECT, &uh->state)) { + D("Do USB detection.\n"); + + usb_detect(uh); + } + + /* Done */ + D("Done.\n"); + + clear_bit(BIT_DO_CABLE_DETECT, &uh->state); + clear_bit(BIT_DO_USB_DETECT, &uh->state); + + return; +} + +static inline void broadcast_event(struct uh_data *uh) +{ + D("Broadcast event.\n"); + + do_broadcast_event(uh); + + return; +} + +static inline void udc_pnp_thread_sleep(struct uh_data *uh) +{ + if (!pending_request(uh)) { + D("Sleep.\n"); + + sleep_on(&uh->kthread_wq); + } + + return; +} +#endif /* HAVE_DETECT_SYNC */ + +/* Kernel thread */ +static int udc_pnp_thread(void *data) +{ + struct uh_data *uh = (struct uh_data *)data; + + while (!kthread_should_stop()) { + /* Sleep. */ + udc_pnp_thread_sleep(uh); + + D("Running.\n"); + + if (kthread_should_stop()) + break; + +#if defined (HAVE_DETECT_SYNC) + /* Sync */ + sync_seq(uh); +#endif + + D("Will do UDC detection.\n"); + + handle_request(uh); + + /* Do detect */ + udc_pnp_detect(uh); + + D("Done.\n"); + + /* Broadcast event. */ + broadcast_event(uh); + } + + D("Exit.\n"); + + return 0; +} + +static irqreturn_t udc_pnp_irq(int irq, void *dev_id) +{ + struct uh_data *uh = (struct uh_data *)dev_id; + + D("called.\n"); + + /* clear interrupt pending status */ + __gpio_ack_irq(UDC_HOTPLUG_PIN); + + set_bit(BIT_REQUEST_CABLE_DETECT, &uh->state); + set_bit(BIT_REQUEST_USB_DETECT, &uh->state); + + start_detect(uh); + + return IRQ_HANDLED; +} + +static void __init init_gpio(struct uh_data *uh) +{ + /* get current pin level */ + __gpio_disable_pull(UDC_HOTPLUG_PIN); + __gpio_as_input(UDC_HOTPLUG_PIN); + udelay(1); + + cable_detect(uh); + + /* Because of every plug IN/OUT action will casue more than one interrupt, + So whether rising trigger or falling trigger method can both start the detection. + */ + + __gpio_as_irq_rise_edge(UDC_HOTPLUG_PIN); + + if (test_bit(BIT_CABLE_ONLINE, &uh->state)) { + D("Cable Online -> Do start detection.\n"); + + set_bit(BIT_REQUEST_CABLE_DETECT, &uh->state); + set_bit(BIT_REQUEST_USB_DETECT, &uh->state); + + start_detect(uh); + }else{ + D("Cable Offline.\n"); + } + + return; +} + +/* ---------------------------------------------------------------------------------- */ +/* Export routines */ +static void udc_hotplug_keep_alive_timer_func(unsigned long data) +{ + struct uh_data *uh = (struct uh_data *)data; + + D("Timer running.\n"); + + /* Decrease the counter. */ + if (test_bit(BIT_KEEP_ALIVE, &uh->state) && !(--uh->keep_alive_counter)) { + + if (!usb_is_active()) { + D("Timeout.\n"); + + set_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state); + + clear_bit(BIT_USB_ONLINE, &uh->state); + set_bit(BIT_USB_CHANGE, &uh->state); + + /* No detection needed. We just want to broadcast our event. */ + start_detect(uh); + } + } + + /* Set next active time. */ + if (test_bit(BIT_KEEP_ALIVE, &uh->state) && !test_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state)) + mod_timer(&uh->keep_alive_timer, uh->keep_alive_timer_interval + jiffies); + else + D("Timer will stop.\n"); + + return; +} + +int udc_hotplug_register_notifier(struct notifier_block *n, int request_state) +{ + struct uh_data *uh = g_puh_data; + + udc_hotplug_event_t e; + + D("Register notifier: 0x%p.\n", (void *)n); + + /* Notifer will be registered is requesting current state. */ + if (request_state) { + + BUG_ON(!n->notifier_call); + + /* Cable State */ + e.type = EVENT_TYPE_CABLE; + e.state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + + n->notifier_call(n, BROADCAST_TYPE_STATE, &e); + + /* USB State */ + e.type = EVENT_TYPE_USB; + e.state = (test_bit(BIT_CABLE_ONLINE, &uh->state)) ? EVENT_STATE_ONLINE: EVENT_STATE_OFFLINE; + + n->notifier_call(n, BROADCAST_TYPE_STATE, &e); + } + + return blocking_notifier_chain_register(&uh->notifier_head, n); + +}EXPORT_SYMBOL(udc_hotplug_register_notifier); + +int udc_hotplug_unregister_notifier(struct notifier_block *n) +{ + struct uh_data *uh = g_puh_data; + + D("Unregister notifier: 0x%p.\n", (void *)n); + + return blocking_notifier_chain_unregister(&uh->notifier_head, n); + +}EXPORT_SYMBOL(udc_hotplug_unregister_notifier); + +/* Start keep alive, 0 - Use default value */ +int udc_hotplug_start_keep_alive(unsigned long timer_interval_in_jiffies, unsigned long counter_limit) +{ + struct uh_data *uh = g_puh_data; + + /* Already started. */ + if (test_and_set_bit(BIT_KEEP_ALIVE, &uh->state)) + return 0; + + if (timer_interval_in_jiffies) + uh->keep_alive_timer_interval = timer_interval_in_jiffies; + else + uh->keep_alive_timer_interval = DEFAULT_KEEP_ALIVE_TIMER_INTERVAL; + + if (counter_limit) + uh->keep_alive_counter_limit = counter_limit; + else + uh->keep_alive_counter_limit = DEFAULT_KEEP_ALIVE_COUNTER_LIMIT; + + uh->keep_alive_counter = uh->keep_alive_counter_limit; + + /* Active our timer. */ + return mod_timer(&uh->keep_alive_timer, 3 + jiffies); + +}EXPORT_SYMBOL(udc_hotplug_start_keep_alive); + +void udc_hotplug_do_keep_alive(void) +{ + struct uh_data *uh = g_puh_data; + + D("Keep alive.\n"); + + /* Reset counter */ + uh->keep_alive_counter = uh->keep_alive_counter_limit; + + /* We are alive again. */ + if (test_and_clear_bit(BIT_KEEP_ALIVE_TIMEOUT, &uh->state)) { + D("Reactive timer.\n"); + + /* Active timer. */ + set_bit(BIT_KEEP_ALIVE, &uh->state); + mod_timer(&uh->keep_alive_timer, 3 + jiffies); + } + + return; +}EXPORT_SYMBOL(udc_hotplug_do_keep_alive); + +void udc_hotplug_stop_keep_alive(void) +{ + struct uh_data *uh = g_puh_data; + + clear_bit(BIT_KEEP_ALIVE, &uh->state); + + return; + +}EXPORT_SYMBOL(udc_hotplug_stop_keep_alive); + +/* ----------------------------------------------------------------------------- */ + +/* + * Module init and exit + */ +static int __init udc_hotplug_init(void) +{ + struct uh_data *uh; + + unsigned long status = 0; + + int rv; + + g_puh_data = (struct uh_data *)kzalloc(sizeof(struct uh_data), GFP_KERNEL); + if (!g_puh_data) { + printk(KERN_ERR PFX": Failed to allocate memory.\n"); + return -ENOMEM; + } + + uh = g_puh_data; + + set_bit(1, &status); + + BLOCKING_INIT_NOTIFIER_HEAD(&uh->notifier_head); + + init_waitqueue_head(&uh->kthread_wq); + init_waitqueue_head(&uh->wq); + + init_timer(&uh->keep_alive_timer); + + uh->keep_alive_timer.function = udc_hotplug_keep_alive_timer_func; + uh->keep_alive_timer.expires = jiffies - 1; /* Add a stopped timer */ + uh->keep_alive_timer.data = (unsigned long)uh; + + add_timer(&uh->keep_alive_timer); + +#if defined (HAVE_DETECT_SYNC) + reset_seq(uh); +#endif + + /* Create pnp thread and register IRQ */ + uh->kthread = kthread_run(udc_pnp_thread, uh, "kudcd"); + if (IS_ERR(uh->kthread)) { + printk(KERN_ERR PFX": Failed to create system monitor thread.\n"); + rv = PTR_ERR(uh->kthread); + goto err; + } + + set_bit(2, &status); + + rv = request_irq(UDC_HOTPLUG_IRQ, udc_pnp_irq, IRQF_DISABLED, "udc_pnp", uh); + if (rv) { + printk(KERN_ERR PFX": Could not get udc hotplug irq %d\n", UDC_HOTPLUG_IRQ); + goto err; + } + + init_gpio(uh); + +#if defined (HAVE_DETECT_SYNC) + printk(KERN_ERR PFX": Registered(HAVE_DETECT_SYNC).\n"); +#else + printk(KERN_ERR PFX": Registered.\n"); +#endif + return 0; + +err: + if (test_bit(2, &status)) { + kthread_stop(uh->kthread); + } + + if (test_bit(1, &status)) { + kfree(g_puh_data); + } + + return rv; +} + +static void __exit udc_hotplug_exit(void) +{ + free_irq(UDC_HOTPLUG_IRQ, g_puh_data); + + kthread_stop(g_puh_data->kthread); + + kfree(g_puh_data); + + return; +} + +module_init(udc_hotplug_init); +module_exit(udc_hotplug_exit); + +MODULE_AUTHOR("River Wang "); +MODULE_LICENSE("GPL"); diff -ruN linux-2.6.31-vanilla/drivers/video/backlight/gpm940b0.c linux-2.6.31/drivers/video/backlight/gpm940b0.c --- linux-2.6.31-vanilla/drivers/video/backlight/gpm940b0.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/video/backlight/gpm940b0.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC LCD framebuffer driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include + +struct gpm940b0 { + struct spi_device *spi; + struct lcd_device *lcd; + struct backlight_device *bl; + unsigned enabled:1; +}; + +static int gpm940b0_write_reg(struct spi_device *spi, uint8_t reg, + uint8_t data) +{ + uint8_t buf[2]; + buf[0] = ((reg & 0x40) << 1) | (reg & 0x3f); + buf[1] = data; + + return spi_write(spi, buf, sizeof(buf)); +} + +static void gpm940b0_power_disable(struct gpm940b0 *gpm940b0) +{ + int ret = gpm940b0_write_reg(gpm940b0->spi, 0x5, 0xc6) ; + if (ret < 0) + printk("Failed to disable power: %d\n", ret); +} + +static void gpm940b0_power_enable(struct gpm940b0 *gpm940b0) +{ + gpm940b0_write_reg(gpm940b0->spi, 0x5, 0xc7); +} + + +static int gpm940b0_set_power(struct lcd_device *lcd, int power) +{ + struct gpm940b0 *gpm940b0 = lcd_get_data(lcd); + + switch (power) { + case FB_BLANK_UNBLANK: + gpm940b0->enabled = 1; + gpm940b0_power_enable(gpm940b0); + break; + default: + gpm940b0->enabled = 0; + gpm940b0_power_disable(gpm940b0); + break; + } + return 0; +} + +static int gpm940b0_set_contrast(struct lcd_device *lcd, int contrast) +{ + struct gpm940b0 *gpm940b0 = lcd_get_data(lcd); + gpm940b0_write_reg(gpm940b0->spi, 0x0d, contrast); + return 0; +} + +static int gpm940b0_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) +{ + if (mode->xres != 320 && mode->yres != 240) + return -EINVAL; + + return 0; +} + +/* +int gpm940b0_bl_update_status(struct backlight_device *bl) +{ + struct gpm940b0 *gpm940b0 = bl_get_data(bl); + + gpm940b0->reg5 &= ~0x38; + gpm940b0->reg5 |= ((bl->props.brightness << 3) & 0x38); + + gpm940b0_write_reg(gpm940b0->spi, 0x5, gpm940b0->reg5); + + return 0; +}*/ + +static ssize_t reg_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + char *buf2; + uint32_t reg = simple_strtoul(buf, &buf2, 10); + uint32_t val = simple_strtoul(buf2 + 1, NULL, 10); + struct gpm940b0 *gpm940b0 = dev_get_drvdata(dev); + + if (reg < 0 || val < 0) + return -EINVAL; + + gpm940b0_write_reg(gpm940b0->spi, reg, val); + return count; +} + +static DEVICE_ATTR(reg, 0644, NULL, reg_write); + +static struct lcd_ops gpm940b0_lcd_ops = { + .set_power = gpm940b0_set_power, + .set_contrast = gpm940b0_set_contrast, + .set_mode = gpm940b0_set_mode, +}; + +#if 0 +static struct backlight_ops gpm940b0_bl_ops = { +/* .get_brightness = gpm940b0_bl_get_brightness,*/ + .update_status = gpm940b0_bl_update_status, +}; +#endif + +static int __devinit gpm940b0_probe(struct spi_device *spi) +{ + int ret; + struct gpm940b0 *gpm940b0; + + gpm940b0 = kmalloc(sizeof(*gpm940b0), GFP_KERNEL); + + spi->bits_per_word = 8; + + ret = spi_setup(spi); + if (ret) { + dev_err(&spi->dev, "Failed to setup spi\n"); + goto err_free_gpm940b0; + } + + gpm940b0->spi = spi; + + gpm940b0->lcd = lcd_device_register("gpm940b0-lcd", &spi->dev, gpm940b0, + &gpm940b0_lcd_ops); + + if (IS_ERR(gpm940b0->lcd)) { + ret = PTR_ERR(gpm940b0->lcd); + dev_err(&spi->dev, "Failed to register lcd device: %d\n", ret); + goto err_free_gpm940b0; + } + + gpm940b0->lcd->props.max_contrast = 255; + +#if 0 + gpm940b0->bl = backlight_device_register("gpm940b0-bl", &spi->dev, gpm940b0, + &gpm940b0_bl_ops); + + if (IS_ERR(gpm940b0->bl)) { + ret = PTR_ERR(gpm940b0->bl); + dev_err(&spi->dev, "Failed to register backlight device: %d\n", ret); + gpm940b0->bl = NULL; + } else { + gpm940b0->bl->props.max_brightness = 8; + gpm940b0->bl->props.brightness = 0; + gpm940b0->bl->props.power = FB_BLANK_UNBLANK; + } +#endif + + ret = device_create_file(&spi->dev, &dev_attr_reg); + if (ret) + goto err_unregister_lcd; + + gpm940b0->enabled = 1; + dev_set_drvdata(&spi->dev, gpm940b0); + + gpm940b0_write_reg(spi, 0x13, 0x01); + gpm940b0_write_reg(spi, 0x5, 0xc7); + return 0; +err_unregister_lcd: + lcd_device_unregister(gpm940b0->lcd); +err_free_gpm940b0: + kfree(gpm940b0); + return ret; +} + +static int __devexit gpm940b0_remove(struct spi_device *spi) +{ + struct gpm940b0 *gpm940b0 = spi_get_drvdata(spi); +#if 0 + if (gpm940b0->bl) + backlight_device_unregister(gpm940b0->bl); +#endif + + lcd_device_unregister(gpm940b0->lcd); + + spi_set_drvdata(spi, NULL); + kfree(gpm940b0); + return 0; +} + +#ifdef CONFIG_PM + +static int gpm940b0_suspend(struct spi_device *spi, pm_message_t state) +{ + struct gpm940b0 *gpm940b0 = spi_get_drvdata(spi); + if (gpm940b0->enabled) { + gpm940b0_power_disable(gpm940b0); + mdelay(10); + } + return 0; +} + +static int gpm940b0_resume(struct spi_device *spi) +{ + struct gpm940b0 *gpm940b0 = spi_get_drvdata(spi); + if (gpm940b0->enabled) + gpm940b0_power_enable(gpm940b0); + return 0; +} + +#else +#define gpm940b0_suspend NULL +#define gpm940b0_resume NULL +#endif + +static struct spi_driver gpm940b0_driver = { + .driver = { + .name = "gpm940b0", + .owner = THIS_MODULE, + }, + .probe = gpm940b0_probe, + .remove = __devexit_p(gpm940b0_remove), + .suspend = gpm940b0_suspend, + .resume = gpm940b0_resume, +}; + +static int __init gpm940b0_init(void) +{ + return spi_register_driver(&gpm940b0_driver); +} +module_init(gpm940b0_init); + +static void __exit gpm940b0_exit(void) +{ + return spi_unregister_driver(&gpm940b0_driver); +} +module_exit(gpm940b0_exit) + +MODULE_AUTHOR("Lars-Peter Clausen"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("LCD and backlight controll for Giantplus GPM940B0"); +MODULE_ALIAS("spi:gpm940b0"); diff -ruN linux-2.6.31-vanilla/drivers/video/jz4740_fb.c linux-2.6.31/drivers/video/jz4740_fb.c --- linux-2.6.31-vanilla/drivers/video/jz4740_fb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/drivers/video/jz4740_fb.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC LCD framebuffer driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define JZ_REG_LCD_CFG 0x00 +#define JZ_REG_LCD_VSYNC 0x04 +#define JZ_REG_LCD_HSYNC 0x08 +#define JZ_REG_LCD_VAT 0x0C +#define JZ_REG_LCD_DAH 0x10 +#define JZ_REG_LCD_DAV 0x14 +#define JZ_REG_LCD_PS 0x18 +#define JZ_REG_LCD_CLS 0x1C +#define JZ_REG_LCD_SPL 0x20 +#define JZ_REG_LCD_REV 0x24 +#define JZ_REG_LCD_CTRL 0x30 +#define JZ_REG_LCD_STATE 0x34 +#define JZ_REG_LCD_IID 0x38 +#define JZ_REG_LCD_DA0 0x40 +#define JZ_REG_LCD_SA0 0x44 +#define JZ_REG_LCD_FID0 0x48 +#define JZ_REG_LCD_CMD0 0x4C +#define JZ_REG_LCD_DA1 0x50 +#define JZ_REG_LCD_SA1 0x54 +#define JZ_REG_LCD_FID1 0x58 +#define JZ_REG_LCD_CMD1 0x5C + +#define JZ_LCD_CFG_SLCD BIT(31) +#define JZ_LCD_CFG_PSM BIT(23) +#define JZ_LCD_CFG_CLSM BIT(22) +#define JZ_LCD_CFG_SPLM BIT(21) +#define JZ_LCD_CFG_REVM BIT(20) +#define JZ_LCD_CFG_HSYNCM BIT(19) +#define JZ_LCD_CFG_PCLKM BIT(18) +#define JZ_LCD_CFG_INV BIT(17) +#define JZ_LCD_CFG_SYNC_DIR BIT(16) +#define JZ_LCD_CFG_PSP BIT(15) +#define JZ_LCD_CFG_CLSP BIT(14) +#define JZ_LCD_CFG_SPLP BIT(13) +#define JZ_LCD_CFG_REVP BIT(12) +#define JZ_LCD_CFG_HSYNCP BIT(11) +#define JZ_LCD_CFG_PCLKP BIT(10) +#define JZ_LCD_CFG_DEP BIT(9) +#define JZ_LCD_CFG_VSYNCP BIT(8) +#define JZ_LCD_CFG_18_BIT BIT(7) +#define JZ_LCD_CFG_PDW BIT(5) | BIT(4) +#define JZ_LCD_CFG_MODE_MASK 0xf + +#define JZ_LCD_CTRL_BURST_4 (0x0 << 28) +#define JZ_LCD_CTRL_BURST_8 (0x1 << 28) +#define JZ_LCD_CTRL_BURST_16 (0x2 << 28) +#define JZ_LCD_CTRL_RGB555 BIT(27) +#define JZ_LCD_CTRL_OFUP BIT(26) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24) +#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24) +#define JZ_LCD_CTRL_PDD_MASK (0xff << 16) +#define JZ_LCD_CTRL_EOF_IRQ BIT(13) +#define JZ_LCD_CTRL_SOF_IRQ BIT(12) +#define JZ_LCD_CTRL_OFU_IRQ BIT(11) +#define JZ_LCD_CTRL_IFU0_IRQ BIT(10) +#define JZ_LCD_CTRL_IFU1_IRQ BIT(9) +#define JZ_LCD_CTRL_DD_IRQ BIT(8) +#define JZ_LCD_CTRL_QDD_IRQ BIT(7) +#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6) +#define JZ_LCD_CTRL_LSB_FISRT BIT(5) +#define JZ_LCD_CTRL_DISABLE BIT(4) +#define JZ_LCD_CTRL_ENABLE BIT(3) +#define JZ_LCD_CTRL_BPP_1 0x0 +#define JZ_LCD_CTRL_BPP_2 0x1 +#define JZ_LCD_CTRL_BPP_4 0x2 +#define JZ_LCD_CTRL_BPP_8 0x3 +#define JZ_LCD_CTRL_BPP_15_16 0x4 +#define JZ_LCD_CTRL_BPP_18_24 0x5 + +#define JZ_LCD_CMD_SOF_IRQ BIT(15) +#define JZ_LCD_CMD_EOF_IRQ BIT(16) +#define JZ_LCD_CMD_ENABLE_PAL BIT(12) + +#define JZ_LCD_SYNC_MASK 0x3ff + +struct jzfb_framedesc { + uint32_t next; + uint32_t addr; + uint32_t id; + uint32_t cmd; +} __attribute__((packed)); + +struct jzfb { + struct fb_info *fb; + struct platform_device *pdev; + void __iomem *base; + struct resource *mem; + struct jz4740_fb_platform_data *pdata; + + void *devmem; + size_t devmem_size; + dma_addr_t devmem_phys; + void *vidmem; + size_t vidmem_size; + dma_addr_t vidmem_phys; + struct jzfb_framedesc *framedesc; + + uint32_t pseudo_palette[16]; +}; + +static struct fb_fix_screeninfo jzfb_fix __devinitdata = { + .id = "JZ4740 FB", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .accel = FB_ACCEL_NONE, +}; + +int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, + unsigned transp, struct fb_info *fb) +{ + ((uint32_t*)fb->pseudo_palette)[regno] = red << 16 | green << 8 | blue; + return 0; +} + +static int jzfb_get_controller_bpp(struct jzfb *jzfb) +{ + switch(jzfb->pdata->bpp) { + case 18: + case 24: + return 32; + break; + default: + return jzfb->pdata->bpp; + } +} + +static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + struct jzfb* jzfb = fb->par; + struct fb_videomode *mode = jzfb->pdata->modes; + int i; + + if (fb->var.bits_per_pixel != jzfb_get_controller_bpp(jzfb) && + fb->var.bits_per_pixel != jzfb->pdata->bpp) + return -EINVAL; + + for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) { + if (mode->xres == fb->var.xres && mode->yres == fb->var.yres) + break; + } + + if (i == jzfb->pdata->num_modes) + return -EINVAL; + + fb_videomode_to_var(&fb->var, fb->mode); + + switch (jzfb->pdata->bpp) { + case 8: + break; + case 15: + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 16: + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 6; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + break; + case 18: + var->red.offset = 16; + var->red.length = 6; + var->green.offset = 8; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 6; + fb->var.bits_per_pixel = 32; + break; + case 32: + case 24: + var->transp.offset = 24; + var->transp.length = 8; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + fb->var.bits_per_pixel = 32; + break; + default: + break; + } + + return 0; +} + +static int jzfb_set_par(struct fb_info *info) +{ + struct jzfb* jzfb = info->par; + struct fb_var_screeninfo *var = &info->var; + uint16_t hds, vds; + uint16_t hde, vde; + uint16_t ht, vt; + uint32_t ctrl; + + hds = var->hsync_len + var->left_margin; + hde = hds + var->xres; + ht = hde + var->right_margin; + + vds = var->vsync_len + var->upper_margin; + vde = vds + var->yres; + vt = vde + var->lower_margin; + + writel(var->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC); + writel(var->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC); + + writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT); + + writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH); + writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV); + + ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16; + ctrl |= JZ_LCD_CTRL_ENABLE; + + switch (jzfb->pdata->bpp) { + case 1: + ctrl |= JZ_LCD_CTRL_BPP_1; + break; + case 2: + ctrl |= JZ_LCD_CTRL_BPP_2; + break; + case 4: + ctrl |= JZ_LCD_CTRL_BPP_4; + break; + case 8: + ctrl |= JZ_LCD_CTRL_BPP_8; + break; + case 15: + ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */ + case 16: + ctrl |= JZ_LCD_CTRL_BPP_15_16; + break; + case 18: + case 24: + case 32: + ctrl |= JZ_LCD_CTRL_BPP_18_24; + break; + default: + break; + } + writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL); + + return 0; +} + + +static int jzfb_alloc_vidmem(struct jzfb *jzfb) +{ + size_t devmem_size; + int max_videosize = 0; + struct fb_videomode *mode = jzfb->pdata->modes; + struct jzfb_framedesc *framedesc; + void *page; + int i; + + for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) { + if (max_videosize < mode->xres * mode->yres) + max_videosize = mode->xres * mode->yres; + } + + max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3; + + devmem_size = max_videosize + sizeof(struct jzfb_framedesc); + + jzfb->devmem_size = devmem_size; + jzfb->devmem = dma_alloc_coherent(&jzfb->pdev->dev, + PAGE_ALIGN(devmem_size), + &jzfb->devmem_phys, GFP_KERNEL); + + if (!jzfb->devmem) { + return -ENOMEM; + } + + for (page = jzfb->vidmem; + page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size); + page += PAGE_SIZE) { + SetPageReserved(virt_to_page(page)); + } + + + framedesc = jzfb->devmem + max_videosize; + jzfb->vidmem = jzfb->devmem; + jzfb->vidmem_phys = jzfb->devmem_phys; + + framedesc->next = jzfb->devmem_phys + max_videosize; + framedesc->addr = jzfb->devmem_phys; + framedesc->id = 0; + framedesc->cmd = 0; + framedesc->cmd |= max_videosize / 4; + + jzfb->framedesc = framedesc; + + + return 0; +} + +static void jzfb_free_devmem(struct jzfb *jzfb) +{ + dma_free_coherent(&jzfb->pdev->dev, jzfb->devmem_size, jzfb->devmem, + jzfb->devmem_phys); +} + +static struct fb_ops jzfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = jzfb_check_var, + .fb_set_par = jzfb_set_par, +/* .fb_blank = jzfb_blank,*/ + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_setcolreg = jzfb_setcolreg, +}; + +static int __devinit jzfb_probe(struct platform_device *pdev) +{ + int ret; + struct jzfb *jzfb; + struct fb_info *fb; + struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data; + struct resource *mem; + + if (!pdata) { + dev_err(&pdev->dev, "Missing platform data\n"); + return -ENOENT; + } + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!mem) { + dev_err(&pdev->dev, "Failed to get register memory resource\n"); + return -ENOENT; + } + + mem = request_mem_region(mem->start, resource_size(mem), pdev->name); + + if (!mem) { + dev_err(&pdev->dev, "Failed to request register memory region\n"); + return -EBUSY; + } + + + fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev); + + if (!fb) { + dev_err(&pdev->dev, "Failed to allocate framebuffer device\n"); + ret = -ENOMEM; + goto err_release_mem_region; + } + + fb->fbops = &jzfb_ops; + fb->flags = FBINFO_DEFAULT; + + jzfb = fb->par; + jzfb->pdev = pdev; + jzfb->pdata = pdata; + jzfb->mem = mem; + + jzfb->base = ioremap(mem->start, resource_size(mem)); + + if (!jzfb->base) { + dev_err(&pdev->dev, "Failed to ioremap register memory region\n"); + ret = -EBUSY; + goto err_framebuffer_release; + } + + platform_set_drvdata(pdev, jzfb); + + fb_videomode_to_modelist(pdata->modes, pdata->num_modes, + &fb->modelist); + fb->mode = pdata->modes; + + fb_videomode_to_var(&fb->var, fb->mode); + fb->var.bits_per_pixel = pdata->bpp; + jzfb_check_var(&fb->var, fb); + + ret = jzfb_alloc_vidmem(jzfb); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate video memory\n"); + goto err_iounmap; + } + + fb->fix = jzfb_fix; + fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8; + fb->fix.mmio_start = mem->start; + fb->fix.mmio_len = resource_size(mem); + fb->fix.smem_start = jzfb->vidmem_phys; + fb->fix.smem_len = fb->fix.line_length * fb->var.yres; + fb->screen_base = jzfb->vidmem; + fb->pseudo_palette = jzfb->pseudo_palette; + + fb_alloc_cmap(&fb->cmap, 256, 0); + + jzfb_set_par(fb); + writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0); + + ret = register_framebuffer(fb); + if (ret) { + dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret); + goto err_free_devmem; + } + + return 0; +err_free_devmem: + jzfb_free_devmem(jzfb); +err_iounmap: + iounmap(jzfb->base); +err_framebuffer_release: + framebuffer_release(fb); +err_release_mem_region: + release_mem_region(mem->start, resource_size(mem)); + return ret; +} + +static int __devexit jzfb_remove(struct platform_device *pdev) +{ + struct jzfb *jzfb = platform_get_drvdata(pdev); + + iounmap(jzfb->base); + release_mem_region(jzfb->mem->start, resource_size(jzfb->mem)); + jzfb_free_devmem(jzfb); + platform_set_drvdata(pdev, NULL); + framebuffer_release(jzfb->fb); + return 0; +} + +static struct platform_driver jzfb_driver = { + .probe = jzfb_probe, + .remove = __devexit_p(jzfb_remove), + + .driver = { + .name = "jz4740-fb", + }, +}; + +int __init jzfb_init(void) +{ + return platform_driver_register(&jzfb_driver); +} +module_init(jzfb_init); + +void __exit jzfb_exit(void) +{ + platform_driver_unregister(&jzfb_driver); +} +module_exit(jzfb_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("JZ4720/JZ4740 SoC LCD framebuffer driver"); +MODULE_ALIAS("platform:jz4740-fb"); +MODULE_ALIAS("platform:jz4720-fb"); diff -ruN linux-2.6.31-vanilla/include/linux/jz4740-adc.h linux-2.6.31/include/linux/jz4740-adc.h --- linux-2.6.31-vanilla/include/linux/jz4740-adc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/include/linux/jz4740-adc.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,25 @@ + +#ifndef __LINUX_JZ4740_ADC +#define __LINUX_JZ4740_ADC + +#include + +enum jz_adc_battery_scale { + JZ_ADC_BATTERY_SCALE_2V5, /* Mesures voltages up to 2.5V */ + JZ_ADC_BATTERY_SCALE_7V5, /* Mesures voltages up to 7.5V */ +}; + +/* + * jz4740_adc_read_battery_voltage - Read battery voltage from the ADC PBAT pin + * @dev: Pointer to a jz4740-adc device + * @scale: Whether to use 2.5V or 7.5V scale + * + * Returns: Battery voltage in mircovolts + * + * Context: Process +*/ +long jz4740_adc_read_battery_voltage(struct device *dev, + enum jz_adc_battery_scale scale); + + +#endif diff -ruN linux-2.6.31-vanilla/include/linux/jz4740_fb.h linux-2.6.31/include/linux/jz4740_fb.h --- linux-2.6.31-vanilla/include/linux/jz4740_fb.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/include/linux/jz4740_fb.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __LINUX_JZ4740_FB_H +#define __LINUX_JZ4740_FB_H + +#include + +enum jz4740_fb_lcd_type { + JZ_LCD_TYPE_GENERIC_16_18_BIT = 0, + JZ_LCD_TYPE_SPECIAL_TFT_1 = 1, + JZ_LCD_TYPE_SPECIAL_TFT_2 = 2, + JZ_LCD_TYPE_SPECIAL_TFT_3 = 3, + JZ_LCD_TYPE_NON_INTERLACED_CCIR656 = 5, + JZ_LCD_TYPE_INTERLACED_CCIR656 = 7, + JZ_LCD_TYPE_SINGLE_COLOR_STN = 8, + JZ_LCD_TYPE_SINGLE_MONOCHROME_STN = 9, + JZ_LCD_TYPE_DUAL_COLOR_STN = 10, + JZ_LCD_TYPE_8BIT_SERIAL = 11, +}; + +/* +* width: width of the lcd display in mm +* height: height of the lcd display in mm +* num_modes: size of modes +* modes: list of valid video modes +* bpp: bits per pixel for the lcd +* lcd_type: lcd type +*/ + +struct jz4740_fb_platform_data { + unsigned int width; + unsigned int height; + + size_t num_modes; + struct fb_videomode *modes; + int bpp; + enum jz4740_fb_lcd_type lcd_type; +}; + +#endif diff -ruN linux-2.6.31-vanilla/include/linux/mtd/jz4740_nand.h linux-2.6.31/include/linux/mtd/jz4740_nand.h --- linux-2.6.31-vanilla/include/linux/mtd/jz4740_nand.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/include/linux/mtd/jz4740_nand.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * JZ4720/JZ4740 SoC NAND controller driver + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __JZ_NAND_H__ +#define __JZ_NAND_H__ + +#include +#include + +struct jz_nand_platform_data { + int num_partitions; + struct mtd_partition *partitions; + + struct nand_ecclayout *ecc_layout; + + unsigned int busy_gpio; + + void (*ident_callback)(struct platform_device *, struct nand_chip *, + struct mtd_partition **, int *num_partitions); +}; + +#endif diff -ruN linux-2.6.31-vanilla/include/linux/power/jz4740-battery.h linux-2.6.31/include/linux/power/jz4740-battery.h --- linux-2.6.31-vanilla/include/linux/power/jz4740-battery.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/include/linux/power/jz4740-battery.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2009, Jiejing Zhang + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef __JZ4740_BATTERY_H +#define __JZ4740_BATTERY_H + +struct jz_batt_info { + int dc_dect_gpio; /* GPIO port of DC charger detection */ + int usb_dect_gpio; /* GPIO port of USB charger detection */ + int charg_stat_gpio; /* GPIO port of Charger state */ + + int min_voltag; /* Mininal battery voltage in uV */ + int max_voltag; /* Maximum battery voltage in uV */ + int batt_tech; /* Battery technology */ +}; + +#endif diff -ruN linux-2.6.31-vanilla/sound/soc/codecs/jzcodec.c linux-2.6.31/sound/soc/codecs/jzcodec.c --- linux-2.6.31-vanilla/sound/soc/codecs/jzcodec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/codecs/jzcodec.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define JZ_REG_CODEC_1 0x0 +#define JZ_REG_CODEC_2 0x1 + +#define JZ_CODEC_1_LINE_ENABLE BIT(29) +#define JZ_CODEC_1_MIC_ENABLE BIT(28) +#define JZ_CODEC_1_SW1_ENABLE BIT(27) +#define JZ_CODEC_1_ADC_ENABLE BIT(26) +#define JZ_CODEC_1_SW2_ENABLE BIT(25) +#define JZ_CODEC_1_DAC_ENABLE BIT(24) +#define JZ_CODEC_1_VREF_DISABLE BIT(20) +#define JZ_CODEC_1_VREF_AMP_DISABLE BIT(19) +#define JZ_CODEC_1_VREF_PULL_DOWN BIT(18) +#define JZ_CODEC_1_VREF_LOW_CURRENT BIT(17) +#define JZ_CODEC_1_VREF_HIGH_CURRENT BIT(16) +#define JZ_CODEC_1_HEADPHONE_DISABLE BIT(14) +#define JZ_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13) +#define JZ_CODEC_1_HEADPHONE_CHANGE BIT(12) +#define JZ_CODEC_1_HEADPHONE_PULL_DOWN_M BIT(11) +#define JZ_CODEC_1_HEADPHONE_PULL_DOWN_R BIT(10) +#define JZ_CODEC_1_HEADPHONE_POWER_DOWN_M BIT(9) +#define JZ_CODEC_1_HEADPHONE_POWER_DOWN BIT(8) +#define JZ_CODEC_1_SUSPEND BIT(1) +#define JZ_CODEC_1_RESET BIT(0) + +#define JZ_CODEC_1_LINE_ENABLE_OFFSET 29 +#define JZ_CODEC_1_MIC_ENABLE_OFFSET 28 +#define JZ_CODEC_1_SW1_ENABLE_OFFSET 27 +#define JZ_CODEC_1_ADC_ENABLE_OFFSET 26 +#define JZ_CODEC_1_SW2_ENABLE_OFFSET 25 +#define JZ_CODEC_1_DAC_ENABLE_OFFSET 24 +#define JZ_CODEC_1_HEADPHONE_DISABLE_OFFSET 14 +#define JZ_CODEC_1_HEADPHONE_POWER_DOWN_OFFSET 8 + +#define JZ_CODEC_2_INPUT_VOLUME_MASK 0x1f0000 +#define JZ_CODEC_2_SAMPLE_RATE_MASK 0x000f00 +#define JZ_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030 +#define JZ_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003 + +#define JZ_CODEC_2_INPUT_VOLUME_OFFSET 16 +#define JZ_CODEC_2_SAMPLE_RATE_OFFSET 8 +#define JZ_CODEC_2_MIC_BOOST_GAIN_OFFSET 4 +#define JZ_CODEC_2_HEADPHONE_VOLUME_OFFSET 0 + +struct jz_codec { + void __iomem *base; + struct resource *mem; + + uint32_t reg_cache[2]; + struct snd_soc_codec codec; +}; + +inline static struct jz_codec *codec_to_jz(struct snd_soc_codec *codec) +{ + return container_of(codec, struct jz_codec, codec); +} + +static unsigned int jz_codec_read(struct snd_soc_codec *codec, unsigned int reg) +{ + struct jz_codec *jz_codec = codec_to_jz(codec); + return readl(jz_codec->base + (reg << 2)); +} + +static int jz_codec_write(struct snd_soc_codec *codec, unsigned int reg, +unsigned int val) +{ + struct jz_codec *jz_codec = codec_to_jz(codec); + jz_codec->reg_cache[reg] = val; + + writel(val, jz_codec->base + (reg << 2)); + return 0; +} + +static const struct snd_kcontrol_new jz_codec_controls[] = { + SOC_SINGLE("Master Playback Volume", JZ_REG_CODEC_2, + JZ_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), + SOC_SINGLE("Capture Volume", JZ_REG_CODEC_2, + JZ_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), + SOC_SINGLE("Master Playback Switch", JZ_REG_CODEC_1, + JZ_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), + SOC_SINGLE("Mic Capture Volume", JZ_REG_CODEC_2, + JZ_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), +}; + +static const struct snd_kcontrol_new jz_codec_output_controls[] = { + SOC_DAPM_SINGLE("Bypass Switch", JZ_REG_CODEC_1, + JZ_CODEC_1_SW1_ENABLE_OFFSET, 1, 0), + SOC_DAPM_SINGLE("DAC Switch", JZ_REG_CODEC_1, + JZ_CODEC_1_SW2_ENABLE_OFFSET, 1, 0), +}; + +static const struct snd_kcontrol_new jz_codec_input_controls[] = +{ + SOC_DAPM_SINGLE("Line Capture Switch", JZ_REG_CODEC_1, + JZ_CODEC_1_LINE_ENABLE_OFFSET, 1, 0), + SOC_DAPM_SINGLE("Mic Capture Switch", JZ_REG_CODEC_1, + JZ_CODEC_1_MIC_ENABLE_OFFSET, 1, 0), +}; + +static const struct snd_soc_dapm_widget jz_codec_dapm_widgets[] = { + SND_SOC_DAPM_ADC("ADC", "Capture", JZ_REG_CODEC_1, + JZ_CODEC_1_ADC_ENABLE_OFFSET, 0), + SND_SOC_DAPM_DAC("DAC", "Playback", JZ_REG_CODEC_1, + JZ_CODEC_1_DAC_ENABLE_OFFSET, 0), + + SND_SOC_DAPM_MIXER("Output Mixer", JZ_REG_CODEC_1, + JZ_CODEC_1_HEADPHONE_POWER_DOWN_OFFSET, 1, + jz_codec_output_controls, + ARRAY_SIZE(jz_codec_output_controls)), + + SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, + jz_codec_input_controls, + ARRAY_SIZE(jz_codec_input_controls)), + SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("LOUT"), + SND_SOC_DAPM_OUTPUT("ROUT"), + + SND_SOC_DAPM_INPUT("MIC"), + SND_SOC_DAPM_INPUT("LIN"), + SND_SOC_DAPM_INPUT("RIN"), +}; + +static const struct snd_soc_dapm_route jz_codec_dapm_routes[] = { + + {"Line Input", NULL, "LIN"}, + {"Line Input", NULL, "RIN"}, + + {"Input Mixer", "Line Capture Switch", "Line Input"}, + {"Input Mixer", "Mic Capture Switch", "MIC"}, + + {"ADC", NULL, "Input Mixer"}, + + {"Output Mixer", "Bypass Switch", "Input Mixer"}, + {"Output Mixer", "DAC Switch", "DAC"}, + + {"LOUT", NULL, "Output Mixer"}, + {"ROUT", NULL, "Output Mixer"}, +}; + +static int jz_codec_hw_params(struct snd_pcm_substream *substream, struct +snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + uint32_t val; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_device *socdev = rtd->socdev; + struct snd_soc_codec *codec = socdev->card->codec; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_S18_3LE: + break; + default: + return -EINVAL; + break; + } + + switch (params_rate(params)) { + case 8000: + val = 0; + break; + case 11025: + val = 1; + break; + case 12000: + val = 2; + break; + case 16000: + val = 3; + break; + case 22050: + val = 4; + break; + case 24000: + val = 5; + break; + case 32000: + val = 6; + break; + case 44100: + val = 7; + break; + case 48000: + val = 8; + break; + default: + return -EINVAL; + } + + val <<= JZ_CODEC_2_SAMPLE_RATE_OFFSET; + + snd_soc_update_bits(codec, JZ_REG_CODEC_2, + JZ_CODEC_2_SAMPLE_RATE_MASK, val); + + return 0; +} + +static int jz_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + return 0; +} + +static int jz_codec_set_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + return 0; +} + + +static struct snd_soc_dai_ops jz_codec_dai_ops = { + .hw_params = jz_codec_hw_params, + .set_fmt = jz_codec_set_fmt, +/* .set_clkdiv = jz_codec_set_clkdiv,*/ + .set_sysclk = jz_codec_set_sysclk, +}; + +struct snd_soc_dai jz_codec_dai = { + .name = "jz-codec", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_44100, + .formats = SNDRV_PCM_FORMAT_S18_3LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_44100, + .formats = SNDRV_PCM_FORMAT_S16_LE, + }, + .ops = &jz_codec_dai_ops, + .symmetric_rates = 1, +}; +EXPORT_SYMBOL_GPL(jz_codec_dai); + +static int jz_codec_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + + if (codec->bias_level == SND_SOC_BIAS_OFF && level != SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_RESET, JZ_CODEC_1_RESET); + udelay(2); + + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_SUSPEND | JZ_CODEC_1_RESET, 0); + } + switch (level) { + case SND_SOC_BIAS_ON: + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_VREF_DISABLE | JZ_CODEC_1_VREF_AMP_DISABLE | + JZ_CODEC_1_HEADPHONE_POWER_DOWN_M | + JZ_CODEC_1_VREF_LOW_CURRENT | JZ_CODEC_1_VREF_HIGH_CURRENT, + 0); + break; + case SND_SOC_BIAS_PREPARE: + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_VREF_LOW_CURRENT | JZ_CODEC_1_VREF_HIGH_CURRENT, + JZ_CODEC_1_VREF_LOW_CURRENT | JZ_CODEC_1_VREF_HIGH_CURRENT); + break; + case SND_SOC_BIAS_STANDBY: + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_VREF_DISABLE | JZ_CODEC_1_VREF_AMP_DISABLE, + JZ_CODEC_1_VREF_DISABLE | JZ_CODEC_1_VREF_AMP_DISABLE); + break; + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, JZ_REG_CODEC_1, + JZ_CODEC_1_SUSPEND, JZ_CODEC_1_SUSPEND); + break; + } + codec->bias_level = level; + + return 0; +} + + +static struct snd_soc_codec *jz_codec_codec; + +static int jz_codec_dev_probe(struct platform_device *pdev) +{ + int ret; + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + struct snd_soc_codec *codec = jz_codec_codec; + + BUG_ON(!codec); + + socdev->card->codec = codec; + + ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); + if (ret) { + dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret); + goto err; + } + snd_soc_add_controls(codec, jz_codec_controls, + ARRAY_SIZE(jz_codec_controls)); + + snd_soc_dapm_new_controls(codec, jz_codec_dapm_widgets, + ARRAY_SIZE(jz_codec_dapm_widgets)); + + snd_soc_dapm_add_routes(codec, jz_codec_dapm_routes, + ARRAY_SIZE(jz_codec_dapm_routes)); + + snd_soc_dapm_new_widgets(codec); + + ret = snd_soc_init_card(socdev); + + if (ret) { + dev_err(&pdev->dev, "Failed to register card\n"); + goto err; + } + + return 0; + +err: + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return ret; +} + +static int jz_codec_dev_remove(struct platform_device *pdev) +{ + struct snd_soc_device *socdev = platform_get_drvdata(pdev); + snd_soc_free_pcms(socdev); + snd_soc_dapm_free(socdev); + + return 0; +} + +struct snd_soc_codec_device soc_codec_dev_jzcodec = { + .probe = jz_codec_dev_probe, + .remove = jz_codec_dev_remove, +}; +EXPORT_SYMBOL_GPL(soc_codec_dev_jzcodec); + +static int __devinit jz_codec_probe(struct platform_device *pdev) +{ + int ret; + struct jz_codec *jz_codec; + struct snd_soc_codec *codec; + + jz_codec = kzalloc(sizeof(*jz_codec), GFP_KERNEL); + + if (!jz_codec) + return -ENOMEM; + + jz_codec->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!jz_codec->mem) { + dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); + ret = -ENOENT; + goto err_free_jz_codec; + } + + jz_codec->mem = request_mem_region(jz_codec->mem->start, + resource_size(jz_codec->mem), pdev->name); + + if (!jz_codec->mem) { + dev_err(&pdev->dev, "Failed to request mmio memory region\n"); + ret = -EBUSY; + goto err_free_jz_codec; + } + + jz_codec->base = ioremap(jz_codec->mem->start, resource_size(jz_codec->mem)); + + if (!jz_codec->base) { + dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); + ret = -EBUSY; + goto err_release_mem_region; + } + + jz_codec_dai.dev = &pdev->dev; + + codec = &jz_codec->codec; + + codec->dev = &pdev->dev; + codec->name = "jz-codec"; + codec->owner = THIS_MODULE; + + codec->read = jz_codec_read; + codec->write = jz_codec_write; + codec->set_bias_level = jz_codec_set_bias_level; + codec->bias_level = SND_SOC_BIAS_OFF; + + codec->dai = &jz_codec_dai; + codec->num_dai = 1; + + codec->reg_cache = jz_codec->reg_cache; + codec->reg_cache_size = 2; + + codec->private_data = jz_codec; + + mutex_init(&codec->mutex); + INIT_LIST_HEAD(&codec->dapm_widgets); + INIT_LIST_HEAD(&codec->dapm_paths); + + jz_codec_codec = codec; + + platform_set_drvdata(pdev, jz_codec); + ret = snd_soc_register_codec(codec); + + if (ret) { + dev_err(&pdev->dev, "Failed to register codec\n"); + goto err_iounmap; + } + + ret = snd_soc_register_dai(&jz_codec_dai); + if (ret) { + dev_err(&pdev->dev, "Failed to register codec dai\n"); + goto err_unregister_codec; + } + + jz_codec_set_bias_level (codec, SND_SOC_BIAS_STANDBY); + + return 0; +err_unregister_codec: + snd_soc_unregister_codec(codec); +err_iounmap: + iounmap(jz_codec->base); +err_release_mem_region: + release_mem_region(jz_codec->mem->start, resource_size(jz_codec->mem)); +err_free_jz_codec: + kfree(jz_codec); + + return ret; +} + +static int __devexit jz_codec_remove(struct platform_device *pdev) +{ + struct jz_codec *jz_codec = platform_get_drvdata(pdev); + + snd_soc_unregister_dai(&jz_codec_dai); + snd_soc_unregister_codec(&jz_codec->codec); + + iounmap(jz_codec->base); + release_mem_region(jz_codec->mem->start, resource_size(jz_codec->mem)); + + platform_set_drvdata(pdev, NULL); + kfree(jz_codec); + + return 0; +} + +static struct platform_driver jz_codec_driver = { + .probe = jz_codec_probe, + .remove = __devexit_p(jz_codec_remove), + .driver = { + .name = "jz4740-codec", + .owner = THIS_MODULE, + }, +}; + +static int __init jz_codec_init(void) +{ + return platform_driver_register(&jz_codec_driver); +} +module_init(jz_codec_init); + +static void __exit jz_codec_exit(void) +{ + platform_driver_unregister(&jz_codec_driver); +} +module_exit(jz_codec_exit); + +MODULE_DESCRIPTION("JZ4720/JZ4740 SoC internal codec driver"); +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:jz-codec"); diff -ruN linux-2.6.31-vanilla/sound/soc/codecs/jzcodec.h linux-2.6.31/sound/soc/codecs/jzcodec.h --- linux-2.6.31-vanilla/sound/soc/codecs/jzcodec.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/codecs/jzcodec.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef _ICODEC_H +#define _ICODEC_H + +#define JZCODEC_SYSCLK 0 + +extern struct snd_soc_dai jz_codec_dai; +extern struct snd_soc_codec_device soc_codec_dev_jzcodec; + +#endif diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/Kconfig linux-2.6.31/sound/soc/jz4740/Kconfig --- linux-2.6.31-vanilla/sound/soc/jz4740/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/Kconfig 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,21 @@ +config SND_JZ4740_SOC + tristate "SoC Audio for Ingenic JZ4740 SoC" + depends on SOC_JZ4740 && SND_SOC + help + Say Y or M if you want to add support for codecs attached to + the Jz4740 AC97, I2S or SSP interface. You will also need + to select the audio interfaces to support below. + +config SND_JZ4740_SOC_QI_LB60 + tristate "SoC Audio support for Qi Hardware Ben Nanonote" + depends on SND_JZ4740_SOC && JZ4740_QI_LB60 + select SND_JZ4740_SOC_I2S + select SND_SOC_JZCODEC + help + Say Y if you want to add support for SoC audio of internal codec on Ingenic Jz4740 QI_LB60 board. + +config SND_JZ4740_SOC_I2S + depends on SND_JZ4740_SOC + tristate "SoC Audio (I2S protocol) for Ingenic jz4740 chip" + help + Say Y if you want to use I2S protocol and I2S codec on Ingenic Jz4740 QI_LB60 board. diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/Makefile linux-2.6.31/sound/soc/jz4740/Makefile --- linux-2.6.31-vanilla/sound/soc/jz4740/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/Makefile 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,13 @@ +# +# Jz4740 Platform Support +# +snd-soc-jz4740-objs := jz4740-pcm.o +snd-soc-jz4740-i2s-objs := jz4740-i2s.o + +obj-$(CONFIG_SND_JZ4740_SOC) += snd-soc-jz4740.o +obj-$(CONFIG_SND_JZ4740_SOC_I2S) += snd-soc-jz4740-i2s.o + +# Jz4740 Machine Support +snd-soc-qi-lb60-objs := qi_lb60.o + +obj-$(CONFIG_SND_JZ4740_SOC_QI_LB60) += snd-soc-qi-lb60.o diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-i2s.c linux-2.6.31/sound/soc/jz4740/jz4740-i2s.c --- linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-i2s.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/jz4740-i2s.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,309 @@ +/* + * 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. + * + * Jiejing Zhang(kzjeef(at)gmail.com) 2009: Make jz soc sound card + * loaded by soc-core. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jz4740-pcm.h" +#include "jz4740-i2s.h" + +static struct jz4740_dma_client jz4740_dma_client_out = { + .name = "I2S PCM Stereo out" +}; + +static struct jz4740_dma_client jz4740_dma_client_in = { + .name = "I2S PCM Stereo in" +}; + +static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = { + .client = &jz4740_dma_client_out, + .channel = DMA_ID_AIC_TX, + .dma_addr = AIC_DR, + .dma_size = 2, +}; + +static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = { + .client = &jz4740_dma_client_in, + .channel = DMA_ID_AIC_RX, + .dma_addr = AIC_DR, + .dma_size = 2, +}; + +static int jz4740_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + /*struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;*/ + + return 0; +} + +static int jz4740_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, + unsigned int fmt) +{ + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* 1 : ac97 , 0 : i2s */ + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* 0 : slave */ + break; + case SND_SOC_DAIFMT_CBM_CFS: + /* 1 : master */ + break; + default: + break; + } + + return 0; +} + +/* +* Set Jz4740 Clock source +*/ +static int jz4740_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai, + int clk_id, unsigned int freq, int dir) +{ + return 0; +} + +static void jz4740_snd_tx_ctrl(int on) +{ + if (on) { + /* enable replay */ + __i2s_enable_transmit_dma(); + __i2s_enable_replay(); + __i2s_enable(); + + } else { + /* disable replay & capture */ + __i2s_disable_replay(); + __i2s_disable_record(); + __i2s_disable_receive_dma(); + __i2s_disable_transmit_dma(); + __i2s_disable(); + } +} + +static void jz4740_snd_rx_ctrl(int on) +{ + if (on) { + /* enable capture */ + __i2s_enable_receive_dma(); + __i2s_enable_record(); + __i2s_enable(); + + } else { + /* disable replay & capture */ + __i2s_disable_replay(); + __i2s_disable_record(); + __i2s_disable_receive_dma(); + __i2s_disable_transmit_dma(); + __i2s_disable(); + } +} + +static int jz4740_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; + /* int channels = params_channels(params); */ + + jz4740_snd_rx_ctrl(0); + jz4740_snd_rx_ctrl(0); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_out; + /*if (channels == 1) + __aic_enable_mono2stereo(); + else + __aic_disable_mono2stereo();*/ + } else + cpu_dai->dma_data = &jz4740_i2s_pcm_stereo_in; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + __i2s_set_transmit_trigger(4); + __i2s_set_receive_trigger(3); + __i2s_set_oss_sample_size(8); + __i2s_set_iss_sample_size(8); + break; + case SNDRV_PCM_FORMAT_S16_LE: + /* playback sample:16 bits, burst:16 bytes */ + __i2s_set_transmit_trigger(4); + /* capture sample:16 bits, burst:16 bytes */ + __i2s_set_receive_trigger(3); + __i2s_set_oss_sample_size(16); + __i2s_set_iss_sample_size(16); + break; + } + + return 0; +} + +static int jz4740_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) +{ + int ret = 0; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + jz4740_snd_rx_ctrl(1); + else + jz4740_snd_tx_ctrl(1); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + jz4740_snd_rx_ctrl(0); + else + jz4740_snd_tx_ctrl(0); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static void jz4740_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + } else { + } + + return; +} + +static int jz4740_i2s_probe(struct platform_device *pdev, struct snd_soc_dai *dai) +{ + __i2s_internal_codec(); + __i2s_as_slave(); + __i2s_select_i2s(); + __aic_select_i2s(); + mdelay(2); + + __i2s_disable(); + __i2s_reset(); + mdelay(2); + + __i2s_disable(); + __i2s_internal_codec(); + __i2s_as_slave(); + __i2s_select_i2s(); + __aic_select_i2s(); + __i2s_set_oss_sample_size(16); + __i2s_set_iss_sample_size(16); + __aic_play_lastsample(); + + __i2s_disable_record(); + __i2s_disable_replay(); + __i2s_disable_loopback(); + __i2s_set_transmit_trigger(7); + __i2s_set_receive_trigger(7); + + jz4740_snd_tx_ctrl(0); + jz4740_snd_rx_ctrl(0); + + return 0; +} + +#ifdef CONFIG_PM +static int jz4740_i2s_suspend(struct snd_soc_dai *dai) +{ + if (!dai->active) + return 0; + + return 0; +} + +static int jz4740_i2s_resume(struct snd_soc_dai *dai) +{ + if (!dai->active) + return 0; + + return 0; +} + +#else +#define jz4740_i2s_suspend NULL +#define jz4740_i2s_resume NULL +#endif + +#define JZ4740_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ + SNDRV_PCM_RATE_48000) + +struct snd_soc_dai_ops snd_jz4740_i2s_dai_ops = { + .startup = jz4740_i2s_startup, + .shutdown = jz4740_i2s_shutdown, + .trigger = jz4740_i2s_trigger, + .hw_params = jz4740_i2s_hw_params, + .set_fmt = jz4740_i2s_set_dai_fmt, + .set_sysclk = jz4740_i2s_set_dai_sysclk, +}; + +struct snd_soc_dai jz4740_i2s_dai = { + .name = "jz4740-i2s", + .id = 0, + .probe = jz4740_i2s_probe, + .suspend = jz4740_i2s_suspend, + .resume = jz4740_i2s_resume, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = JZ4740_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = JZ4740_I2S_RATES, + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &snd_jz4740_i2s_dai_ops, +}; + +EXPORT_SYMBOL_GPL(jz4740_i2s_dai); + +static int __init jz4740_i2s_init(void) +{ + return snd_soc_register_dai(&jz4740_i2s_dai); +} + +static void __exit jz4740_i2s_exit(void) +{ + snd_soc_unregister_dai(&jz4740_i2s_dai); +} + +module_init(jz4740_i2s_init); +module_exit(jz4740_i2s_exit); + +/* Module information */ +MODULE_AUTHOR("Richard, cjfeng@ingenic.cn, www.ingenic.cn"); +MODULE_DESCRIPTION("jz4740 I2S SoC Interface"); +MODULE_LICENSE("GPL"); diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-i2s.h linux-2.6.31/sound/soc/jz4740/jz4740-i2s.h --- linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-i2s.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/jz4740-i2s.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,18 @@ +/* + * 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 _JZ4740_I2S_H +#define _JZ4740_I2S_H + +/* jz4740 DAI ID's */ +#define JZ4740_DAI_I2S 0 + +/* I2S clock */ +#define JZ4740_I2S_SYSCLK 0 + +extern struct snd_soc_dai jz4740_i2s_dai; + +#endif diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-pcm.c linux-2.6.31/sound/soc/jz4740/jz4740-pcm.c --- linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-pcm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/jz4740-pcm.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,686 @@ +/* + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include "jz4740-pcm.h" + +static long sum_bytes = 0; +static int first_transfer = 0; +static int printk_flag = 0; +static int tran_bit = 0; +#ifdef CONFIG_SND_OSSEMUL +static int hw_params_cnt = 0; +#endif + +static struct jz4740_dma_client jz4740_dma_client_out = { + .name = "I2S PCM Stereo out" +}; + +static struct jz4740_dma_client jz4740_dma_client_in = { + .name = "I2S PCM Stereo in" +}; + +static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_out = { + .client = &jz4740_dma_client_out, + .channel = DMA_ID_AIC_TX, + .dma_addr = AIC_DR, + .dma_size = 2, +}; + +static struct jz4740_pcm_dma_params jz4740_i2s_pcm_stereo_in = { + .client = &jz4740_dma_client_in, + .channel = DMA_ID_AIC_RX, + .dma_addr = AIC_DR, + .dma_size = 2, +}; + + +struct jz4740_dma_buf_aic { + struct jz4740_dma_buf_aic *next; + int size; /* buffer size in bytes */ + dma_addr_t data; /* start of DMA data */ + dma_addr_t ptr; /* where the DMA got to [1] */ + void *id; /* client's id */ +}; + +struct jz4740_runtime_data { + spinlock_t lock; + int state; + int aic_dma_flag; /* start dma transfer or not */ + unsigned int dma_loaded; + unsigned int dma_limit; + unsigned int dma_period; + dma_addr_t dma_start; + dma_addr_t dma_pos; + dma_addr_t dma_end; + struct jz4740_pcm_dma_params *params; + + dma_addr_t user_cur_addr; /* user current write buffer start address */ + unsigned int user_cur_len; /* user current write buffer length */ + + /* buffer list and information */ + struct jz4740_dma_buf_aic *curr; /* current dma buffer */ + struct jz4740_dma_buf_aic *next; /* next buffer to load */ + struct jz4740_dma_buf_aic *end; /* end of queue */ + +}; + +/* identify hardware playback capabilities */ +static const struct snd_pcm_hardware jz4740_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S8, + .rates = SNDRV_PCM_RATE_8000_48000/*0x3fe*/, + .rate_min = 8000, + .rate_min = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 128 * 1024,//16 * 1024 + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE * 2, + .periods_min = 2, + .periods_max = 128,//16, + .fifo_size = 32, +}; + +/* jz4740__dma_buf_enqueue + * + * queue an given buffer for dma transfer. + * + * data the physical address of the buffer data + * size the size of the buffer in bytes + * +*/ +static int jz4740_dma_buf_enqueue(struct jz4740_runtime_data *prtd, dma_addr_t data, int size) +{ + struct jz4740_dma_buf_aic *aic_buf; + + aic_buf = kzalloc(sizeof(struct jz4740_dma_buf_aic), GFP_KERNEL); + if (aic_buf == NULL) { + printk("aic buffer allocate failed,no memory!\n"); + return -ENOMEM; + } + aic_buf->next = NULL; + aic_buf->data = aic_buf->ptr = data; + aic_buf->size = size; + if( prtd->curr == NULL) { + prtd->curr = aic_buf; + prtd->end = aic_buf; + prtd->next = NULL; + } else { + if (prtd->end == NULL) + printk("prtd->end is NULL\n"); + prtd->end->next = aic_buf; + prtd->end = aic_buf; + } + + /* if necessary, update the next buffer field */ + if (prtd->next == NULL) + prtd->next = aic_buf; + + return 0; +} + + +void audio_start_dma(struct jz4740_runtime_data *prtd, int mode) +{ + unsigned long flags; + struct jz4740_dma_buf_aic *aic_buf; + int channel; + + switch (mode) { + case DMA_MODE_WRITE: + /* free cur aic_buf */ + if (first_transfer == 1) { + first_transfer = 0; + } else { + aic_buf = prtd->curr; + if (aic_buf != NULL) { + prtd->curr = aic_buf->next; + prtd->next = aic_buf->next; + aic_buf->next = NULL; + kfree(aic_buf); + aic_buf = NULL; + } + } + + aic_buf = prtd->next; + channel = prtd->params->channel; + if (aic_buf) { + disable_dma(channel); + jz_set_alsa_dma(channel, mode, tran_bit); + set_dma_addr(channel, aic_buf->data); + set_dma_count(channel, aic_buf->size); + enable_dma(channel); + prtd->aic_dma_flag |= AIC_START_DMA; + } else { + printk("next buffer is NULL for playback\n"); + prtd->aic_dma_flag &= ~AIC_START_DMA; + return; + } + break; + case DMA_MODE_READ: + /* free cur aic_buf */ + if (first_transfer == 1) { + first_transfer = 0; + } else { + aic_buf = prtd->curr; + if (aic_buf != NULL) { + prtd->curr = aic_buf->next; + prtd->next = aic_buf->next; + aic_buf->next = NULL; + kfree(aic_buf); + aic_buf = NULL; + } + } + + aic_buf = prtd->next; + channel = prtd->params->channel; + + if (aic_buf) { + disable_dma(channel); + jz_set_alsa_dma(channel, mode, tran_bit); + set_dma_addr(channel, aic_buf->data); + set_dma_count(channel, aic_buf->size); + enable_dma(channel); + prtd->aic_dma_flag |= AIC_START_DMA; + } else { + printk("next buffer is NULL for capture\n"); + prtd->aic_dma_flag &= ~AIC_START_DMA; + return; + } + break; + } + /* dump_jz_dma_channel(channel); */ +} + +/* + * place a dma buffer onto the queue for the dma system to handle. +*/ +static void jz4740_pcm_enqueue(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + /*struct snd_dma_buffer *buf = &substream->dma_buffer;*/ + dma_addr_t pos = prtd->dma_pos; + int ret; + + while (prtd->dma_loaded < prtd->dma_limit) { + unsigned long len = prtd->dma_period; + + if ((pos + len) > prtd->dma_end) { + len = prtd->dma_end - pos; + } + ret = jz4740_dma_buf_enqueue(prtd, pos, len); + if (ret == 0) { + prtd->dma_loaded++; + pos += prtd->dma_period; + if (pos >= prtd->dma_end) + pos = prtd->dma_start; + } else + break; + } + + prtd->dma_pos = pos; +} + +/* + * call the function:jz4740_pcm_dma_irq() after DMA has transfered the current buffer + */ +static irqreturn_t jz4740_pcm_dma_irq(int dma_ch, void *dev_id) +{ + struct snd_pcm_substream *substream = dev_id; + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + /*struct jz4740_dma_buf_aic *aic_buf = prtd->curr;*/ + int channel = prtd->params->channel; + unsigned long flags; + + disable_dma(channel); + prtd->aic_dma_flag &= ~AIC_START_DMA; + /* must clear TT bit in DCCSR to avoid interrupt again */ + if (__dmac_channel_transmit_end_detected(channel)) { + __dmac_channel_clear_transmit_end(channel); + } + if (__dmac_channel_transmit_halt_detected(channel)) { + __dmac_channel_clear_transmit_halt(channel); + } + + if (__dmac_channel_address_error_detected(channel)) { + __dmac_channel_clear_address_error(channel); + } + + if (substream) + snd_pcm_period_elapsed(substream); + + spin_lock(&prtd->lock); + prtd->dma_loaded--; + if (prtd->state & ST_RUNNING) { + jz4740_pcm_enqueue(substream); + } + spin_unlock(&prtd->lock); + + local_irq_save(flags); + if (prtd->state & ST_RUNNING) { + if (prtd->dma_loaded) { + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + audio_start_dma(prtd, DMA_MODE_WRITE); + else + audio_start_dma(prtd, DMA_MODE_READ); + } + } + local_irq_restore(flags); + return IRQ_HANDLED; +} + +/* some parameter about DMA operation */ +static int jz4740_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct jz4740_pcm_dma_params *dma = &jz4740_i2s_pcm_stereo_out; + size_t totbytes = params_buffer_bytes(params); + int ret; + + if (!dma) + return 0; + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + tran_bit = 8; + break; + case SNDRV_PCM_FORMAT_S16_LE: + tran_bit = 16; + break; + } + + /* prepare DMA */ + prtd->params = dma; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = jz_request_dma(DMA_ID_AIC_TX, prtd->params->client->name, + jz4740_pcm_dma_irq, IRQF_DISABLED, substream); + if (ret < 0) + return ret; + prtd->params->channel = ret; + } else { + ret = jz_request_dma(DMA_ID_AIC_RX, prtd->params->client->name, + jz4740_pcm_dma_irq, IRQF_DISABLED, substream); + if (ret < 0) + return ret; + prtd->params->channel = ret; + } + + snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); + runtime->dma_bytes = totbytes; + + spin_lock_irq(&prtd->lock); + prtd->dma_loaded = 0; + prtd->aic_dma_flag = 0; + prtd->dma_limit = runtime->hw.periods_min; + prtd->dma_period = params_period_bytes(params); + prtd->dma_start = runtime->dma_addr; + prtd->dma_pos = prtd->dma_start; + prtd->dma_end = prtd->dma_start + totbytes; + prtd->curr = NULL; + prtd->next = NULL; + prtd->end = NULL; + sum_bytes = 0; + first_transfer = 1; + printk_flag = 0; + + __dmac_disable_descriptor(prtd->params->channel); + __dmac_channel_disable_irq(prtd->params->channel); + spin_unlock_irq(&prtd->lock); + return ret; +} + +static int jz4740_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct jz4740_runtime_data *prtd = substream->runtime->private_data; + + snd_pcm_set_runtime_buffer(substream, NULL); + if (prtd->params) { + jz_free_dma(prtd->params->channel); + prtd->params = NULL; + } + + return 0; +} + +/* set some dma para for playback/capture */ +static int jz4740_dma_ctrl(int channel) +{ + + disable_dma(channel); + + /* must clear TT bit in DCCSR to avoid interrupt again */ + if (__dmac_channel_transmit_end_detected(channel)) { + __dmac_channel_clear_transmit_end(channel); + } + if (__dmac_channel_transmit_halt_detected(channel)) { + __dmac_channel_clear_transmit_halt(channel); + } + + if (__dmac_channel_address_error_detected(channel)) { + __dmac_channel_clear_address_error(channel); + } + + return 0; + +} + +static int jz4740_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct jz4740_runtime_data *prtd = substream->runtime->private_data; + int ret = 0; + + /* return if this is a bufferless transfer e.g */ + if (!prtd->params) + return 0; + + /* flush the DMA channel and DMA channel bit check */ + jz4740_dma_ctrl(prtd->params->channel); + prtd->dma_loaded = 0; + prtd->dma_pos = prtd->dma_start; + + /* enqueue dma buffers */ + jz4740_pcm_enqueue(substream); + + return ret; + +} + +static int jz4740_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + prtd->state |= ST_RUNNING; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + audio_start_dma(prtd, DMA_MODE_WRITE); + } else { + audio_start_dma(prtd, DMA_MODE_READ); + } + + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + prtd->state &= ~ST_RUNNING; + break; + + case SNDRV_PCM_TRIGGER_RESUME: + printk(" RESUME \n"); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + printk(" RESTART \n"); + break; + + default: + ret = -EINVAL; + } + + return ret; +} + +static snd_pcm_uframes_t +jz4740_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + struct jz4740_dma_buf_aic *aic_buf = prtd->curr; + long count,res; + + dma_addr_t ptr; + snd_pcm_uframes_t x; + int channel = prtd->params->channel; + + spin_lock(&prtd->lock); +#if 1 + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + count = get_dma_residue(channel); + count = aic_buf->size - count; + ptr = aic_buf->data + count; + res = ptr - prtd->dma_start; + } else { + count = get_dma_residue(channel); + count = aic_buf->size - count; + ptr = aic_buf->data + count; + res = ptr - prtd->dma_start; + } + +# else + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { + count = get_dma_residue(channel); + count = aic_buf->size - count; + ptr = aic_buf->data + count; + REG_DMAC_DSAR(channel) = ptr; + res = ptr - prtd->dma_start; + } else { + ptr = REG_DMAC_DSAR(channel); + if (ptr == 0x0) + printk("\ndma address is 00000000 in running!\n"); + res = ptr - prtd->dma_start; + } + } else { + if ((prtd->aic_dma_flag & AIC_START_DMA) == 0) { + count = get_dma_residue(channel); + count = aic_buf->size - count; + ptr = aic_buf->data + count; + REG_DMAC_DTAR(channel) = ptr; + res = ptr - prtd->dma_start; + } else { + ptr = REG_DMAC_DTAR(channel); + if (ptr == 0x0) + printk("\ndma address is 00000000 in running!\n"); + res = ptr - prtd->dma_start; + } + } +#endif + spin_unlock(&prtd->lock); + x = bytes_to_frames(runtime, res); + if (x == runtime->buffer_size) + x = 0; + + return x; +} + +static int jz4740_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd; + +#ifdef CONFIG_SND_OSSEMUL + hw_params_cnt = 0; +#endif + snd_soc_set_runtime_hwparams(substream, &jz4740_pcm_hardware); + prtd = kzalloc(sizeof(struct jz4740_runtime_data), GFP_KERNEL); + if (prtd == NULL) + return -ENOMEM; + + spin_lock_init(&prtd->lock); + + runtime->private_data = prtd; + REG_AIC_I2SCR = 0x10; + return 0; +} + +static int jz4740_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct jz4740_runtime_data *prtd = runtime->private_data; + struct jz4740_dma_buf_aic *aic_buf = NULL; + +#ifdef CONFIG_SND_OSSEMUL + hw_params_cnt = 0; +#endif + + if (prtd) + aic_buf = prtd->curr; + + while (aic_buf != NULL) { + prtd->curr = aic_buf->next; + prtd->next = aic_buf->next; + aic_buf->next = NULL; + kfree(aic_buf); + aic_buf = NULL; + aic_buf = prtd->curr; + } + + if (prtd) { + prtd->curr = NULL; + prtd->next = NULL; + prtd->end = NULL; + kfree(prtd); + } + + return 0; +} + +static int jz4740_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + return remap_pfn_range(vma, vma->vm_start, + substream->dma_buffer.addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, vma->vm_page_prot); +} + +struct snd_pcm_ops jz4740_pcm_ops = { + .open = jz4740_pcm_open, + .close = jz4740_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = jz4740_pcm_hw_params, + .hw_free = jz4740_pcm_hw_free, + .prepare = jz4740_pcm_prepare, + .trigger = jz4740_pcm_trigger, + .pointer = jz4740_pcm_pointer, + .mmap = jz4740_pcm_mmap, +}; + +static int jz4740_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) +{ + struct snd_pcm_substream *substream = pcm->streams[stream].substream; + struct snd_dma_buffer *buf = &substream->dma_buffer; + size_t size = jz4740_pcm_hardware.buffer_bytes_max; + buf->dev.type = SNDRV_DMA_TYPE_DEV; + buf->dev.dev = pcm->card->dev; + buf->private_data = NULL; + + /*buf->area = dma_alloc_coherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL);*/ + buf->area = dma_alloc_noncoherent(pcm->card->dev, size, + &buf->addr, GFP_KERNEL); + if (!buf->area) + return -ENOMEM; + buf->bytes = size; + return 0; +} + +static void jz4740_pcm_free_dma_buffers(struct snd_pcm *pcm) +{ + struct snd_pcm_substream *substream; + struct snd_dma_buffer *buf; + int stream; + + for (stream = 0; stream < 2; stream++) { + substream = pcm->streams[stream].substream; + if (!substream) + continue; + + buf = &substream->dma_buffer; + if (!buf->area) + continue; + + dma_free_noncoherent(pcm->card->dev, buf->bytes, + buf->area, buf->addr); + buf->area = NULL; + } +} + +static u64 jz4740_pcm_dmamask = DMA_BIT_MASK(32); + +int jz4740_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, + struct snd_pcm *pcm) +{ + int ret = 0; + + printk("pcm new\n"); + + if (!card->dev->dma_mask) + card->dev->dma_mask = &jz4740_pcm_dmamask; + if (!card->dev->coherent_dma_mask) + card->dev->coherent_dma_mask = DMA_BIT_MASK(32); + + if (dai->playback.channels_min) { + ret = jz4740_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_PLAYBACK); + if (ret) + goto out; + } + + if (dai->capture.channels_min) { + ret = jz4740_pcm_preallocate_dma_buffer(pcm, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) + goto out; + } + out: + + return ret; +} + +struct snd_soc_platform jz4740_soc_platform = { + .name = "jz4740-audio", + .pcm_ops = &jz4740_pcm_ops, + .pcm_new = jz4740_pcm_new, + .pcm_free = jz4740_pcm_free_dma_buffers, +}; + +EXPORT_SYMBOL_GPL(jz4740_soc_platform); + +static int __init jz4740_soc_platform_init(void) +{ + return snd_soc_register_platform(&jz4740_soc_platform); +} +module_init(jz4740_soc_platform_init); + +static void __exit jz4740_soc_platform_exit(void) +{ + snd_soc_unregister_platform(&jz4740_soc_platform); +} +module_exit(jz4740_soc_platform_exit); + +MODULE_AUTHOR("Richard"); +MODULE_DESCRIPTION("Ingenic Jz4740 PCM DMA module"); +MODULE_LICENSE("GPL"); diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-pcm.h linux-2.6.31/sound/soc/jz4740/jz4740-pcm.h --- linux-2.6.31-vanilla/sound/soc/jz4740/jz4740-pcm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/jz4740-pcm.h 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,33 @@ +/* + * + * 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 _JZ4740_PCM_H +#define _JZ4740_PCM_H + +#include + +#define ST_RUNNING (1<<0) +#define ST_OPENED (1<<1) + +#define AIC_START_DMA (1<<0) +#define AIC_END_DMA (1<<1) + +struct jz4740_dma_client { + char *name; +}; + +struct jz4740_pcm_dma_params { + struct jz4740_dma_client *client; /* stream identifier */ + int channel; /* Channel ID */ + dma_addr_t dma_addr; + int dma_size; /* Size of the DMA transfer */ +}; + +/* platform data */ +extern struct snd_soc_platform jz4740_soc_platform; + +#endif diff -ruN linux-2.6.31-vanilla/sound/soc/jz4740/qi_lb60.c linux-2.6.31/sound/soc/jz4740/qi_lb60.c --- linux-2.6.31-vanilla/sound/soc/jz4740/qi_lb60.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.31/sound/soc/jz4740/qi_lb60.c 2009-11-19 19:00:26.000000000 +0100 @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2009, Lars-Peter Clausen + * + * 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. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../codecs/jzcodec.h" +#include "jz4740-pcm.h" +#include "jz4740-i2s.h" + + +#define QI_LB60_SND_GPIO JZ_GPIO_PORTB(29) +#define QI_LB60_AMP_GPIO JZ_GPIO_PORTD(4) + +static int qi_lb60_spk_event(struct snd_soc_dapm_widget *widget, + struct snd_kcontrol *ctrl, int event) +{ + int on = 0; + if (event & SND_SOC_DAPM_POST_PMU) + on = 1; + else if (event & SND_SOC_DAPM_PRE_PMD) + on = 0; + + gpio_set_value(QI_LB60_SND_GPIO, on); + gpio_set_value(QI_LB60_AMP_GPIO, on); + + return 0; +} + +static const struct snd_soc_dapm_widget qi_lb60_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", qi_lb60_spk_event), + SND_SOC_DAPM_MIC("Mic", NULL), +}; + +static const struct snd_soc_dapm_route qi_lb60_routes[] = { + {"Mic", NULL, "MIC"}, + {"Speaker", NULL, "LOUT"}, + {"Speaker", NULL, "ROUT"}, +}; + +#define QI_LB60_DAIFMT (SND_SOC_DAIFMT_I2S | \ + SND_SOC_DAIFMT_NB_NF | \ + SND_SOC_DAIFMT_CBM_CFM) + +static int qi_lb60_codec_init(struct snd_soc_codec *codec) +{ + int ret; + struct snd_soc_dai *cpu_dai = codec->socdev->card->dai_link->cpu_dai; + struct snd_soc_dai *codec_dai = codec->socdev->card->dai_link->codec_dai; + + snd_soc_dapm_nc_pin(codec, "LIN"); + snd_soc_dapm_nc_pin(codec, "RIN"); + + ret = snd_soc_dai_set_fmt(codec_dai, QI_LB60_DAIFMT); + if (ret < 0) { + dev_err(codec->dev, "Failed to set codec dai format: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, QI_LB60_DAIFMT); + if (ret < 0) { + dev_err(codec->dev, "Failed to set cpu dai format: %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, JZCODEC_SYSCLK, 111, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec->dev, "Failed to set codec dai sysclk: %d\n", ret); + return ret; + } + + snd_soc_dapm_new_controls(codec, qi_lb60_widgets, ARRAY_SIZE(qi_lb60_widgets)); + + snd_soc_dapm_add_routes(codec, qi_lb60_routes, ARRAY_SIZE(qi_lb60_routes)); + + snd_soc_dapm_sync(codec); + + return 0; +} + +static struct snd_soc_dai_link qi_lb60_dai = { + .name = "jz-codec", + .stream_name = "JZCODEC", + .cpu_dai = &jz4740_i2s_dai, + .codec_dai = &jz_codec_dai, + .init = qi_lb60_codec_init, +}; + +static struct snd_soc_card qi_lb60 = { + .name = "QI LB60", + .dai_link = &qi_lb60_dai, + .num_links = 1, + .platform = &jz4740_soc_platform, +}; + +static struct snd_soc_device qi_lb60_snd_devdata = { + .card = &qi_lb60, + .codec_dev = &soc_codec_dev_jzcodec, +}; + +static struct platform_device *qi_lb60_snd_device; + +static int __init qi_lb60_init(void) +{ + int ret; + + qi_lb60_snd_device = platform_device_alloc("soc-audio", -1); + + if (!qi_lb60_snd_device) + return -ENOMEM; + + + ret = gpio_request(QI_LB60_SND_GPIO, "SND"); + if (ret) { + pr_err("qi_lb60 snd: Failed to request SND GPIO(%d): %d\n", + QI_LB60_SND_GPIO, ret); + goto err_device_put; + } + + ret = gpio_request(QI_LB60_AMP_GPIO, "AMP"); + if (ret) { + pr_err("qi_lb60 snd: Failed to request AMP GPIO(%d): %d\n", + QI_LB60_AMP_GPIO, ret); + goto err_gpio_free_snd; + } + + gpio_direction_output(JZ_GPIO_PORTB(29), 0); + gpio_direction_output(JZ_GPIO_PORTD(4), 0); + + platform_set_drvdata(qi_lb60_snd_device, &qi_lb60_snd_devdata); + qi_lb60_snd_devdata.dev = &qi_lb60_snd_device->dev; + ret = platform_device_add(qi_lb60_snd_device); + if (ret) { + pr_err("qi_lb60 snd: Failed to add snd soc device: %d\n", ret); + goto err_unset_pdata; + } + + return 0; + +err_unset_pdata: + platform_set_drvdata(qi_lb60_snd_device, NULL); +/*err_gpio_free_amp:*/ + gpio_free(QI_LB60_AMP_GPIO); +err_gpio_free_snd: + gpio_free(QI_LB60_SND_GPIO); +err_device_put: + platform_device_put(qi_lb60_snd_device); + + return ret; +} +module_init(qi_lb60_init); + +static void __exit qi_lb60_exit(void) +{ + gpio_free(QI_LB60_AMP_GPIO); + gpio_free(QI_LB60_SND_GPIO); + platform_device_unregister(qi_lb60_snd_device); +} +module_exit(qi_lb60_exit); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("ALSA SoC QI LB60 Audio support"); +MODULE_LICENSE("GPL v2");