* [PATCH] linux: vmx25 module (i.mx25) kernel patches * defconfig - default kernel config for vmx25 * linux-patch - add partial support for vmx25 baseboard pheripherals Signed-off-by: sujak.marek <sujak.marek@gmail.com>
@ 2011-01-28 9:19 sujak.marek
2011-01-28 11:52 ` Petr Štetiar
0 siblings, 1 reply; 3+ messages in thread
From: sujak.marek @ 2011-01-28 9:19 UTC (permalink / raw)
To: openembedded-devel
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 943280 bytes --]
---
recipes/linux/linux-2.6.35/vmx25/defconfig | 1771 ++
.../vmx25/linux-2.6.35-vmx25-20110112.patch |28459 ++++++++++++++++++++
2 files changed, 30230 insertions(+), 0 deletions(-)
create mode 100644 recipes/linux/linux-2.6.35/vmx25/defconfig
create mode 100644 recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch
diff --git a/recipes/linux/linux-2.6.35/vmx25/defconfig b/recipes/linux/linux-2.6.35/vmx25/defconfig
new file mode 100644
index 0000000..cbd23c5
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/vmx25/defconfig
@@ -0,0 +1,1771 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.35
+# Thu Jan 27 12:12:40 2011
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_FIQ=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+# CONFIG_TREE_RCU is not set
+# CONFIG_TREE_PREEMPT_RCU is not set
+CONFIG_TINY_RCU=y
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_AIO is not set
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+# CONFIG_SLUB is not set
+CONFIG_SLOB=y
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+CONFIG_IMX_HAVE_PLATFORM_FLEXCAN=y
+CONFIG_IMX_HAVE_PLATFORM_IMX_I2C=y
+CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y
+CONFIG_IMX_HAVE_PLATFORM_MXC_NAND=y
+CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX1 is not set
+# CONFIG_ARCH_MX2 is not set
+CONFIG_ARCH_MX25=y
+# CONFIG_ARCH_MX3 is not set
+# CONFIG_ARCH_MXC91231 is not set
+# CONFIG_ARCH_MX5 is not set
+
+#
+# MX25 platforms:
+#
+# CONFIG_MACH_MX25_3DS is not set
+CONFIG_MACH_VMX25=y
+CONFIG_MACH_VMX_BASEBOARD=y
+# CONFIG_VMX_SD_ON_MODULE is not set
+CONFIG_VMX_SD_ON_BOARD=y
+CONFIG_MXC_SDMA_API=y
+CONFIG_MXC_IRQ_PRIOR=y
+CONFIG_MXC_PWM=y
+CONFIG_ARCH_MXC_IOMUX_V3=y
+CONFIG_ARCH_MXC_AUDMUX_V2=y
+CONFIG_MXC_SSI_PORTS=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+# CONFIG_OABI_COMPAT is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttymxc0,115200 mem=32M@0x80000000 mem=32M@0x90000000 ip=dhcp ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs otg_mode=host video=imxfb:VGA-16@60"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_NVS=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+
+#
+# CAN Device Drivers
+#
+# CONFIG_CAN_VCAN is not set
+CONFIG_CAN_DEV=y
+CONFIG_CAN_CALC_BITTIMING=y
+CONFIG_CAN_MCP251X=y
+CONFIG_HAVE_CAN_FLEXCAN=y
+CONFIG_CAN_FLEXCAN=y
+# CONFIG_CAN_SJA1000 is not set
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+# CONFIG_DEVTMPFS_MOUNT is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# MXC support drivers
+#
+
+#
+# i.MX ADC support
+#
+# CONFIG_IMX_ADC is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+# CONFIG_MTD_BLKDEVS is not set
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=y
+# CONFIG_M25PXX_USE_FAST_READ is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_MXC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+CONFIG_MTD_UBI_GLUEBI=y
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_FEC=y
+# CONFIG_FEC2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_APMPOWER is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_COMPAT is not set
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+# CONFIG_I2C_SMBUS is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_IMX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_IMX=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=y
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+CONFIG_W1=y
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+CONFIG_W1_MASTER_MXC=y
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+CONFIG_W1_SLAVE_SMEM=y
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Native drivers
+#
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7411 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ASC7621 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_G760A is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM73 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4215 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_LM95241 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_SHT15 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_EMC1403 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_ADS7871 is not set
+# CONFIG_SENSORS_AMC6821 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_TMP102 is not set
+# CONFIG_SENSORS_TMP401 is not set
+# CONFIG_SENSORS_TMP421 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3_SPI is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_MAX63XX_WATCHDOG is not set
+CONFIG_IMX2_WDT=y
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+# CONFIG_MFD_SUPPORT is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+CONFIG_HAVE_FB_IMX=y
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_IMX=y
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_GENERIC is not set
+CONFIG_BACKLIGHT_PWM=y
+# CONFIG_BACKLIGHT_ADP8860 is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+CONFIG_SOUND_OSS_CORE=y
+# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_IMX_SOC=y
+CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_SGTL5000=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MXC=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=y
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=300
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+CONFIG_USB_GADGET_FSL_USB2=y
+CONFIG_USB_FSL_USB2=y
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+CONFIG_USB_GADGET_DUALSPEED=y
+# CONFIG_USB_ZERO is not set
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_MASS_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_NOKIA is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+# CONFIG_MMC_SDHCI_PLTFM is not set
+# CONFIG_MMC_MXC is not set
+# CONFIG_MMC_SPI is not set
+CONFIG_MMC_SDHCI_MXC=y
+# CONFIG_MMC_SDHCI_MXC_SELECT2 is not set
+# CONFIG_MMC_SDHCI_MXC_PIO_MODE is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_MXC is not set
+CONFIG_RTC_DRV_IMXDI=y
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=y
+# CONFIG_EXT4_FS_XATTR is not set
+# CONFIG_EXT4_DEBUG is not set
+CONFIG_JBD=y
+CONFIG_JBD2=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=y
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-15"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+CONFIG_NLS_CODEPAGE_1250=y
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_MEMORY_INIT is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch b/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch
new file mode 100644
index 0000000..f9aafd6
--- /dev/null
+++ b/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch
@@ -0,0 +1,28459 @@
+diff -urN linux.35.old/arch/arm/configs/vmx25_defconfig linux.35.new/arch/arm/configs/vmx25_defconfig
+--- linux.35.old/arch/arm/configs/vmx25_defconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/configs/vmx25_defconfig 2010-12-21 12:20:30.725765123 +0100
+@@ -0,0 +1,1866 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.35
++# Tue Dec 21 12:20:04 2010
++#
++CONFIG_ARM=y
++CONFIG_HAVE_PWM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_GENERIC_TIME=y
++# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_HAVE_PROC_CPU=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_NEED_DMA_MAP_STATE=y
++CONFIG_FIQ=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++CONFIG_CONSTRUCTORS=y
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_CROSS_COMPILE=""
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_HAVE_KERNEL_GZIP=y
++CONFIG_HAVE_KERNEL_LZMA=y
++CONFIG_HAVE_KERNEL_LZO=y
++CONFIG_KERNEL_GZIP=y
++# CONFIG_KERNEL_BZIP2 is not set
++# CONFIG_KERNEL_LZMA is not set
++# CONFIG_KERNEL_LZO is not set
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++CONFIG_POSIX_MQUEUE_SYSCTL=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++
++#
++# RCU Subsystem
++#
++# CONFIG_TREE_RCU is not set
++# CONFIG_TREE_PREEMPT_RCU is not set
++CONFIG_TINY_RCU=y
++# CONFIG_TREE_RCU_TRACE is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=16
++# CONFIG_CGROUPS is not set
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++# CONFIG_RELAY is not set
++# CONFIG_NAMESPACES is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_ANON_INODES=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++CONFIG_ELF_CORE=y
++CONFIG_BASE_FULL=y
++CONFIG_FUTEX=y
++CONFIG_EPOLL=y
++CONFIG_SIGNALFD=y
++CONFIG_TIMERFD=y
++CONFIG_EVENTFD=y
++CONFIG_SHMEM=y
++# CONFIG_AIO is not set
++CONFIG_HAVE_PERF_EVENTS=y
++CONFIG_PERF_USE_VMALLOC=y
++
++#
++# Kernel Performance Events And Counters
++#
++# CONFIG_PERF_EVENTS is not set
++# CONFIG_PERF_COUNTERS is not set
++# CONFIG_VM_EVENT_COUNTERS is not set
++CONFIG_COMPAT_BRK=y
++# CONFIG_SLAB is not set
++# CONFIG_SLUB is not set
++CONFIG_SLOB=y
++# CONFIG_PROFILING is not set
++CONFIG_HAVE_OPROFILE=y
++CONFIG_HAVE_KPROBES=y
++CONFIG_HAVE_KRETPROBES=y
++CONFIG_HAVE_CLK=y
++
++#
++# GCOV-based kernel profiling
++#
++# CONFIG_SLOW_WORK is not set
++CONFIG_HAVE_GENERIC_DMA_COHERENT=y
++CONFIG_RT_MUTEXES=y
++CONFIG_BASE_SMALL=0
++# CONFIG_MODULES is not set
++CONFIG_BLOCK=y
++# CONFIG_LBDAF is not set
++# CONFIG_BLK_DEV_BSG is not set
++# CONFIG_BLK_DEV_INTEGRITY is not set
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_DEADLINE=y
++# CONFIG_IOSCHED_CFQ is not set
++CONFIG_DEFAULT_DEADLINE=y
++# CONFIG_DEFAULT_CFQ is not set
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="deadline"
++# CONFIG_INLINE_SPIN_TRYLOCK is not set
++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK is not set
++# CONFIG_INLINE_SPIN_LOCK_BH is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_SPIN_UNLOCK is not set
++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_READ_TRYLOCK is not set
++# CONFIG_INLINE_READ_LOCK is not set
++# CONFIG_INLINE_READ_LOCK_BH is not set
++# CONFIG_INLINE_READ_LOCK_IRQ is not set
++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_READ_UNLOCK is not set
++# CONFIG_INLINE_READ_UNLOCK_BH is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
++# CONFIG_INLINE_WRITE_TRYLOCK is not set
++# CONFIG_INLINE_WRITE_LOCK is not set
++# CONFIG_INLINE_WRITE_LOCK_BH is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
++# CONFIG_INLINE_WRITE_UNLOCK is not set
++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
++# CONFIG_MUTEX_SPIN_ON_OWNER is not set
++# CONFIG_FREEZER is not set
++
++#
++# System Type
++#
++CONFIG_MMU=y
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# CONFIG_ARCH_REALVIEW is not set
++# CONFIG_ARCH_VERSATILE is not set
++# CONFIG_ARCH_VEXPRESS is not set
++# CONFIG_ARCH_AT91 is not set
++# CONFIG_ARCH_BCMRING is not set
++# CONFIG_ARCH_CLPS711X is not set
++# CONFIG_ARCH_CNS3XXX is not set
++# CONFIG_ARCH_GEMINI is not set
++# CONFIG_ARCH_EBSA110 is not set
++# CONFIG_ARCH_EP93XX is not set
++# CONFIG_ARCH_FOOTBRIDGE is not set
++CONFIG_ARCH_MXC=y
++# CONFIG_ARCH_STMP3XXX is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_DOVE is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_MMP is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_W90X900 is not set
++# CONFIG_ARCH_NUC93X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_MSM is not set
++# CONFIG_ARCH_SHMOBILE is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_S3C64XX is not set
++# CONFIG_ARCH_S5P6440 is not set
++# CONFIG_ARCH_S5P6442 is not set
++# CONFIG_ARCH_S5PC100 is not set
++# CONFIG_ARCH_S5PV210 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_U300 is not set
++# CONFIG_ARCH_U8500 is not set
++# CONFIG_ARCH_NOMADIK is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_PLAT_SPEAR is not set
++CONFIG_IMX_HAVE_PLATFORM_FLEXCAN=y
++CONFIG_IMX_HAVE_PLATFORM_IMX_I2C=y
++CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y
++CONFIG_IMX_HAVE_PLATFORM_MXC_NAND=y
++CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y
++
++#
++# Freescale MXC Implementations
++#
++# CONFIG_ARCH_MX1 is not set
++# CONFIG_ARCH_MX2 is not set
++CONFIG_ARCH_MX25=y
++# CONFIG_ARCH_MX3 is not set
++# CONFIG_ARCH_MXC91231 is not set
++# CONFIG_ARCH_MX5 is not set
++
++#
++# MX25 platforms:
++#
++# CONFIG_MACH_MX25_3DS is not set
++CONFIG_MACH_VMX25=y
++CONFIG_MACH_VMX_BASEBOARD=y
++# CONFIG_VMX_SD_ON_MODULE is not set
++CONFIG_VMX_SD_ON_BOARD=y
++CONFIG_MXC_SDMA_API=y
++CONFIG_MXC_IRQ_PRIOR=y
++CONFIG_MXC_PWM=y
++CONFIG_ARCH_MXC_IOMUX_V3=y
++CONFIG_ARCH_MXC_AUDMUX_V2=y
++CONFIG_MXC_SSI_PORTS=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_ARM926T=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5TJ=y
++CONFIG_CPU_PABRT_LEGACY=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++CONFIG_ARM_L1_CACHE_SHIFT=5
++CONFIG_COMMON_CLKDEV=y
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++CONFIG_NO_HZ=y
++# CONFIG_HIGH_RES_TIMERS is not set
++CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
++CONFIG_VMSPLIT_3G=y
++# CONFIG_VMSPLIT_2G is not set
++# CONFIG_VMSPLIT_1G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++# CONFIG_PREEMPT_NONE is not set
++# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_PREEMPT=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++# CONFIG_OABI_COMPAT is not set
++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
++# CONFIG_HIGHMEM is not set
++CONFIG_SELECT_MEMORY_MODEL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_SPARSEMEM_MANUAL is not set
++CONFIG_FLATMEM=y
++CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=999999
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++# CONFIG_KSM is not set
++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
++CONFIG_ALIGNMENT_TRAP=y
++# CONFIG_UACCESS_WITH_MEMCPY is not set
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="console=ttymxc0,115200 mem=32M@0x80000000 mem=32M@0x90000000 ip=dhcp ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs otg_mode=host video=imxfb:VGA-16@60"
++# CONFIG_CMDLINE_FORCE is not set
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++CONFIG_CPU_IDLE=y
++CONFIG_CPU_IDLE_GOV_LADDER=y
++CONFIG_CPU_IDLE_GOV_MENU=y
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++# CONFIG_VFP is not set
++
++#
++# Userspace binary formats
++#
++CONFIG_BINFMT_ELF=y
++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
++CONFIG_HAVE_AOUT=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
++
++#
++# Power management options
++#
++# CONFIG_PM is not set
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++# CONFIG_IP_MULTICAST is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++# CONFIG_IP_PNP_BOOTP is not set
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++# CONFIG_INET_DIAG is not set
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# CONFIG_RDS is not set
++# CONFIG_TIPC is not set
++# CONFIG_ATM is not set
++# CONFIG_L2TP is not set
++# CONFIG_BRIDGE is not set
++# CONFIG_NET_DSA is not set
++# CONFIG_VLAN_8021Q is not set
++# CONFIG_DECNET is not set
++# CONFIG_LLC2 is not set
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_PHONET is not set
++# CONFIG_IEEE802154 is not set
++# CONFIG_NET_SCHED is not set
++# CONFIG_DCB is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++CONFIG_CAN=y
++CONFIG_CAN_RAW=y
++CONFIG_CAN_BCM=y
++
++#
++# CAN Device Drivers
++#
++# CONFIG_CAN_VCAN is not set
++CONFIG_CAN_DEV=y
++CONFIG_CAN_CALC_BITTIMING=y
++CONFIG_CAN_MCP251X=y
++CONFIG_HAVE_CAN_FLEXCAN=y
++CONFIG_CAN_FLEXCAN=y
++# CONFIG_CAN_SJA1000 is not set
++
++#
++# CAN USB interfaces
++#
++# CONFIG_CAN_EMS_USB is not set
++CONFIG_CAN_DEBUG_DEVICES=y
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_WIRELESS is not set
++# CONFIG_WIMAX is not set
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++# CONFIG_CAIF is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_DEVTMPFS=y
++# CONFIG_DEVTMPFS_MOUNT is not set
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++# CONFIG_FW_LOADER is not set
++# CONFIG_SYS_HYPERVISOR is not set
++
++#
++# MXC support drivers
++#
++
++#
++# i.MX ADC support
++#
++# CONFIG_IMX_ADC is not set
++CONFIG_CONNECTOR=y
++CONFIG_PROC_EVENTS=y
++CONFIG_MTD=y
++# CONFIG_MTD_DEBUG is not set
++CONFIG_MTD_CONCAT=y
++CONFIG_MTD_PARTITIONS=y
++# CONFIG_MTD_REDBOOT_PARTS is not set
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++# CONFIG_MTD_BLKDEVS is not set
++# CONFIG_MTD_BLOCK is not set
++# CONFIG_MTD_BLOCK_RO is not set
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_SM_FTL is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++CONFIG_MTD_M25P80=y
++# CONFIG_M25PXX_USE_FAST_READ is not set
++# CONFIG_MTD_SST25L is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# CONFIG_MTD_DOC2001PLUS is not set
++CONFIG_MTD_NAND_ECC=y
++# CONFIG_MTD_NAND_ECC_SMC is not set
++CONFIG_MTD_NAND=y
++# CONFIG_MTD_NAND_VERIFY_WRITE is not set
++# CONFIG_MTD_SM_COMMON is not set
++# CONFIG_MTD_NAND_MUSEUM_IDS is not set
++CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++CONFIG_MTD_NAND_MXC=y
++# CONFIG_MTD_ONENAND is not set
++
++#
++# LPDDR flash memory drivers
++#
++# CONFIG_MTD_LPDDR is not set
++
++#
++# UBI - Unsorted block images
++#
++CONFIG_MTD_UBI=y
++CONFIG_MTD_UBI_WL_THRESHOLD=4096
++CONFIG_MTD_UBI_BEB_RESERVE=1
++CONFIG_MTD_UBI_GLUEBI=y
++
++#
++# UBI debugging options
++#
++# CONFIG_MTD_UBI_DEBUG is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_DRBD is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++# CONFIG_BLK_DEV_RAM is not set
++# CONFIG_CDROM_PKTCDVD is not set
++# CONFIG_ATA_OVER_ETH is not set
++# CONFIG_MG_DISK is not set
++CONFIG_MISC_DEVICES=y
++# CONFIG_AD525X_DPOT is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_ISL29003 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_DS1682 is not set
++# CONFIG_TI_DAC7512 is not set
++# CONFIG_C2PORT is not set
++
++#
++# EEPROM support
++#
++CONFIG_EEPROM_AT24=y
++# CONFIG_EEPROM_AT25 is not set
++# CONFIG_EEPROM_LEGACY is not set
++# CONFIG_EEPROM_MAX6875 is not set
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_IWMC3200TOP is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++CONFIG_SCSI_MOD=y
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=y
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=y
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++CONFIG_CHR_DEV_SG=y
++# CONFIG_CHR_DEV_SCH is not set
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++# CONFIG_SCSI_LOWLEVEL is not set
++# CONFIG_SCSI_DH is not set
++# CONFIG_SCSI_OSD_INITIATOR is not set
++# CONFIG_ATA is not set
++# CONFIG_MD is not set
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH is not set
++CONFIG_PHYLIB=y
++
++#
++# MII PHY device drivers
++#
++# CONFIG_MARVELL_PHY is not set
++# CONFIG_DAVICOM_PHY is not set
++# CONFIG_QSEMI_PHY is not set
++# CONFIG_LXT_PHY is not set
++# CONFIG_CICADA_PHY is not set
++# CONFIG_VITESSE_PHY is not set
++CONFIG_SMSC_PHY=y
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_PHY is not set
++# CONFIG_NATIONAL_PHY is not set
++# CONFIG_STE10XP is not set
++# CONFIG_LSI_ET1011C_PHY is not set
++# CONFIG_MICREL_PHY is not set
++# CONFIG_FIXED_PHY is not set
++# CONFIG_MDIO_BITBANG is not set
++CONFIG_NET_ETHERNET=y
++CONFIG_MII=y
++# CONFIG_AX88796 is not set
++# CONFIG_SMC91X is not set
++# CONFIG_DM9000 is not set
++# CONFIG_ENC28J60 is not set
++# CONFIG_ETHOC is not set
++# CONFIG_SMC911X is not set
++# CONFIG_SMSC911X is not set
++# CONFIG_DNET is not set
++# CONFIG_IBM_NEW_EMAC_ZMII is not set
++# CONFIG_IBM_NEW_EMAC_RGMII is not set
++# CONFIG_IBM_NEW_EMAC_TAH is not set
++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
++# CONFIG_B44 is not set
++# CONFIG_KS8842 is not set
++# CONFIG_KS8851 is not set
++# CONFIG_KS8851_MLL is not set
++CONFIG_FEC=y
++# CONFIG_FEC2 is not set
++# CONFIG_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++# CONFIG_WLAN is not set
++
++#
++# Enable WiMAX (Networking options) to see the WiMAX drivers
++#
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++# CONFIG_USB_IPHETH is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++# CONFIG_PHONE is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++# CONFIG_INPUT_SPARSEKMAP is not set
++
++#
++# Userland interfaces
++#
++CONFIG_INPUT_MOUSEDEV=y
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
++CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVBUG is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ADP5588 is not set
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_QT2160 is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++CONFIG_KEYBOARD_GPIO=y
++# CONFIG_KEYBOARD_TCA6416 is not set
++# CONFIG_KEYBOARD_MATRIX is not set
++# CONFIG_KEYBOARD_LM8323 is not set
++# CONFIG_KEYBOARD_MAX7359 is not set
++CONFIG_KEYBOARD_IMX=y
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_OPENCORES is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++CONFIG_INPUT_MOUSE=y
++# CONFIG_MOUSE_PS2 is not set
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_APPLETOUCH is not set
++# CONFIG_MOUSE_BCM5974 is not set
++# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_MOUSE_GPIO is not set
++# CONFIG_MOUSE_SYNAPTICS_I2C is not set
++# CONFIG_INPUT_JOYSTICK is not set
++# CONFIG_INPUT_TABLET is not set
++CONFIG_INPUT_TOUCHSCREEN=y
++CONFIG_TOUCHSCREEN_ADS7846=y
++# CONFIG_TOUCHSCREEN_AD7877 is not set
++# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
++# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
++# CONFIG_TOUCHSCREEN_AD7879 is not set
++# CONFIG_TOUCHSCREEN_DYNAPRO is not set
++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
++# CONFIG_TOUCHSCREEN_EETI is not set
++# CONFIG_TOUCHSCREEN_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO is not set
++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
++# CONFIG_TOUCHSCREEN_MCS5000 is not set
++# CONFIG_TOUCHSCREEN_MTOUCH is not set
++# CONFIG_TOUCHSCREEN_INEXIO is not set
++# CONFIG_TOUCHSCREEN_MK712 is not set
++# CONFIG_TOUCHSCREEN_PENMOUNT is not set
++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++CONFIG_TOUCHSCREEN_MXC_TSC=y
++# CONFIG_TOUCHSCREEN_WM97XX is not set
++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_TOUCHSCREEN_TSC2007 is not set
++# CONFIG_TOUCHSCREEN_W90X900 is not set
++# CONFIG_TOUCHSCREEN_TPS6507X is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++CONFIG_CONSOLE_TRANSLATIONS=y
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++# CONFIG_N_GSM is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++# CONFIG_SERIAL_MAX3100 is not set
++CONFIG_SERIAL_IMX=y
++CONFIG_SERIAL_IMX_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++# CONFIG_SERIAL_TIMBERDALE is not set
++# CONFIG_SERIAL_ALTERA_JTAGUART is not set
++# CONFIG_SERIAL_ALTERA_UART is not set
++CONFIG_UNIX98_PTYS=y
++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
++# CONFIG_LEGACY_PTYS is not set
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++# CONFIG_RAMOOPS is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++# CONFIG_I2C_COMPAT is not set
++CONFIG_I2C_CHARDEV=y
++# CONFIG_I2C_HELPER_AUTO is not set
++# CONFIG_I2C_SMBUS is not set
++
++#
++# I2C Algorithms
++#
++# CONFIG_I2C_ALGOBIT is not set
++# CONFIG_I2C_ALGOPCF is not set
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++# CONFIG_I2C_DESIGNWARE is not set
++# CONFIG_I2C_GPIO is not set
++CONFIG_I2C_IMX=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_SIMTEC is not set
++# CONFIG_I2C_XILINX is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++CONFIG_SPI=y
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++CONFIG_SPI_BITBANG=y
++# CONFIG_SPI_GPIO is not set
++CONFIG_SPI_IMX=y
++# CONFIG_SPI_XILINX is not set
++# CONFIG_SPI_DESIGNWARE is not set
++
++#
++# SPI Protocol Masters
++#
++CONFIG_SPI_SPIDEV=y
++# CONFIG_SPI_TLE62X0 is not set
++
++#
++# PPS support
++#
++# CONFIG_PPS is not set
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO expanders:
++#
++# CONFIG_GPIO_IT8761E is not set
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX7300 is not set
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++# CONFIG_GPIO_ADP5588 is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++# CONFIG_GPIO_MC33880 is not set
++
++#
++# AC97 GPIO expanders:
++#
++
++#
++# MODULbus GPIO expanders:
++#
++CONFIG_W1=y
++CONFIG_W1_CON=y
++
++#
++# 1-wire Bus Masters
++#
++# CONFIG_W1_MASTER_DS2490 is not set
++# CONFIG_W1_MASTER_DS2482 is not set
++CONFIG_W1_MASTER_MXC=y
++# CONFIG_W1_MASTER_DS1WM is not set
++# CONFIG_W1_MASTER_GPIO is not set
++
++#
++# 1-wire Slaves
++#
++# CONFIG_W1_SLAVE_THERM is not set
++CONFIG_W1_SLAVE_SMEM=y
++# CONFIG_W1_SLAVE_DS2431 is not set
++# CONFIG_W1_SLAVE_DS2433 is not set
++# CONFIG_W1_SLAVE_DS2760 is not set
++# CONFIG_W1_SLAVE_BQ27000 is not set
++# CONFIG_POWER_SUPPLY is not set
++CONFIG_HWMON=y
++# CONFIG_HWMON_VID is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++
++#
++# Native drivers
++#
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7411 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7475 is not set
++# CONFIG_SENSORS_ASC7621 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_G760A is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM73 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_LTC4215 is not set
++# CONFIG_SENSORS_LTC4245 is not set
++# CONFIG_SENSORS_LM95241 is not set
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_SHT15 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_EMC1403 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_ADS7871 is not set
++# CONFIG_SENSORS_AMC6821 is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_TMP102 is not set
++# CONFIG_SENSORS_TMP401 is not set
++# CONFIG_SENSORS_TMP421 is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_SENSORS_LIS3_SPI is not set
++# CONFIG_SENSORS_LIS3_I2C is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_NOWAYOUT=y
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++# CONFIG_MAX63XX_WATCHDOG is not set
++CONFIG_IMX2_WDT=y
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++# CONFIG_MFD_SUPPORT is not set
++# CONFIG_REGULATOR is not set
++CONFIG_MEDIA_SUPPORT=y
++
++#
++# Multimedia core support
++#
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L2_COMMON=y
++# CONFIG_VIDEO_ALLOW_V4L1 is not set
++CONFIG_VIDEO_V4L1_COMPAT=y
++# CONFIG_DVB_CORE is not set
++CONFIG_VIDEO_MEDIA=y
++
++#
++# Multimedia drivers
++#
++CONFIG_IR_CORE=y
++CONFIG_VIDEO_IR=y
++# CONFIG_RC_MAP is not set
++# CONFIG_IR_NEC_DECODER is not set
++# CONFIG_IR_RC5_DECODER is not set
++# CONFIG_IR_RC6_DECODER is not set
++# CONFIG_IR_JVC_DECODER is not set
++# CONFIG_IR_SONY_DECODER is not set
++# CONFIG_IR_IMON is not set
++CONFIG_MEDIA_TUNER=y
++CONFIG_MEDIA_TUNER_CUSTOMISE=y
++# CONFIG_MEDIA_TUNER_SIMPLE is not set
++# CONFIG_MEDIA_TUNER_TDA8290 is not set
++# CONFIG_MEDIA_TUNER_TDA827X is not set
++# CONFIG_MEDIA_TUNER_TDA18271 is not set
++# CONFIG_MEDIA_TUNER_TDA9887 is not set
++# CONFIG_MEDIA_TUNER_TEA5761 is not set
++# CONFIG_MEDIA_TUNER_TEA5767 is not set
++# CONFIG_MEDIA_TUNER_MT20XX is not set
++# CONFIG_MEDIA_TUNER_MT2060 is not set
++# CONFIG_MEDIA_TUNER_MT2266 is not set
++# CONFIG_MEDIA_TUNER_MT2131 is not set
++# CONFIG_MEDIA_TUNER_QT1010 is not set
++# CONFIG_MEDIA_TUNER_XC2028 is not set
++# CONFIG_MEDIA_TUNER_XC5000 is not set
++# CONFIG_MEDIA_TUNER_MXL5005S is not set
++# CONFIG_MEDIA_TUNER_MXL5007T is not set
++# CONFIG_MEDIA_TUNER_MC44S803 is not set
++# CONFIG_MEDIA_TUNER_MAX2165 is not set
++CONFIG_VIDEO_V4L2=y
++# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
++# CONFIG_V4L_MEM2MEM_DRIVERS is not set
++CONFIG_RADIO_ADAPTERS=y
++# CONFIG_I2C_SI4713 is not set
++# CONFIG_RADIO_SI4713 is not set
++# CONFIG_USB_DSBR is not set
++# CONFIG_RADIO_SI470X is not set
++# CONFIG_USB_MR800 is not set
++# CONFIG_RADIO_TEA5764 is not set
++# CONFIG_RADIO_SAA7706H is not set
++# CONFIG_RADIO_TEF6862 is not set
++CONFIG_RADIO_SI4705=y
++# CONFIG_DAB is not set
++
++#
++# Graphics support
++#
++CONFIG_HAVE_FB_IMX=y
++# CONFIG_VGASTATE is not set
++# CONFIG_VIDEO_OUTPUT_CONTROL is not set
++CONFIG_FB=y
++# CONFIG_FIRMWARE_EDID is not set
++# CONFIG_FB_DDC is not set
++# CONFIG_FB_BOOT_VESA_SUPPORT is not set
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
++# CONFIG_FB_SYS_FILLRECT is not set
++# CONFIG_FB_SYS_COPYAREA is not set
++# CONFIG_FB_SYS_IMAGEBLIT is not set
++# CONFIG_FB_FOREIGN_ENDIAN is not set
++# CONFIG_FB_SYS_FOPS is not set
++# CONFIG_FB_SVGALIB is not set
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++# CONFIG_FB_TILEBLITTING is not set
++
++#
++# Frame buffer hardware drivers
++#
++CONFIG_FB_IMX=y
++# CONFIG_FB_UVESA is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB_METRONOME is not set
++# CONFIG_FB_MB862XX is not set
++# CONFIG_FB_BROADSHEET is not set
++CONFIG_BACKLIGHT_LCD_SUPPORT=y
++# CONFIG_LCD_CLASS_DEVICE is not set
++CONFIG_BACKLIGHT_CLASS_DEVICE=y
++# CONFIG_BACKLIGHT_GENERIC is not set
++CONFIG_BACKLIGHT_PWM=y
++# CONFIG_BACKLIGHT_ADP8860 is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# CONFIG_VGA_CONSOLE is not set
++CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
++CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
++CONFIG_FONTS=y
++CONFIG_FONT_8x8=y
++# CONFIG_FONT_8x16 is not set
++# CONFIG_FONT_6x11 is not set
++# CONFIG_FONT_7x14 is not set
++# CONFIG_FONT_PEARL_8x8 is not set
++# CONFIG_FONT_ACORN_8x8 is not set
++# CONFIG_FONT_MINI_4x6 is not set
++# CONFIG_FONT_SUN8x16 is not set
++# CONFIG_FONT_SUN12x22 is not set
++# CONFIG_FONT_10x18 is not set
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
++CONFIG_SOUND=y
++CONFIG_SOUND_OSS_CORE=y
++# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_JACK=y
++# CONFIG_SND_SEQUENCER is not set
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++CONFIG_SND_DYNAMIC_MINORS=y
++CONFIG_SND_SUPPORT_OLD_API=y
++# CONFIG_SND_VERBOSE_PROCFS is not set
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++# CONFIG_SND_RAWMIDI_SEQ is not set
++# CONFIG_SND_OPL3_LIB_SEQ is not set
++# CONFIG_SND_OPL4_LIB_SEQ is not set
++# CONFIG_SND_SBAWE_SEQ is not set
++# CONFIG_SND_EMU10K1_SEQ is not set
++# CONFIG_SND_DRIVERS is not set
++# CONFIG_SND_ARM is not set
++# CONFIG_SND_SPI is not set
++# CONFIG_SND_USB is not set
++CONFIG_SND_SOC=y
++CONFIG_SND_SOC_AC97_BUS=y
++CONFIG_SND_IMX_SOC=y
++CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y
++CONFIG_SND_SOC_I2C_AND_SPI=y
++# CONFIG_SND_SOC_ALL_CODECS is not set
++CONFIG_SND_SOC_SGTL5000=y
++# CONFIG_SOUND_PRIME is not set
++CONFIG_AC97_BUS=y
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=y
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_3M_PCT is not set
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_CANDO is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_PRODIKEYS is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DRAGONRISE is not set
++# CONFIG_HID_EGALAX is not set
++# CONFIG_HID_EZKEY is not set
++# CONFIG_HID_KYE is not set
++# CONFIG_HID_GYRATION is not set
++# CONFIG_HID_TWINHAN is not set
++# CONFIG_HID_KENSINGTON is not set
++# CONFIG_HID_LOGITECH is not set
++# CONFIG_HID_MICROSOFT is not set
++# CONFIG_HID_MOSART is not set
++# CONFIG_HID_MONTEREY is not set
++# CONFIG_HID_NTRIG is not set
++# CONFIG_HID_ORTEK is not set
++# CONFIG_HID_PANTHERLORD is not set
++# CONFIG_HID_PETALYNX is not set
++# CONFIG_HID_PICOLCD is not set
++# CONFIG_HID_QUANTA is not set
++# CONFIG_HID_ROCCAT is not set
++# CONFIG_HID_ROCCAT_KONE is not set
++# CONFIG_HID_SAMSUNG is not set
++# CONFIG_HID_SONY is not set
++# CONFIG_HID_STANTUM is not set
++# CONFIG_HID_SUNPLUS is not set
++# CONFIG_HID_GREENASIA is not set
++# CONFIG_HID_SMARTJOYPLUS is not set
++# CONFIG_HID_TOPSEED is not set
++# CONFIG_HID_THRUSTMASTER is not set
++# CONFIG_HID_ZEROPLUS is not set
++# CONFIG_HID_ZYDACRON is not set
++CONFIG_USB_SUPPORT=y
++CONFIG_USB_ARCH_HAS_HCD=y
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++CONFIG_USB_DEBUG=y
++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_DEVICE_CLASS=y
++CONFIG_USB_DYNAMIC_MINORS=y
++# CONFIG_USB_OTG_WHITELIST is not set
++# CONFIG_USB_OTG_BLACKLIST_HUB is not set
++# CONFIG_USB_MON is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++CONFIG_USB_EHCI_TT_NEWSCHED=y
++CONFIG_USB_EHCI_MXC=y
++# CONFIG_USB_OXU210HP_HCD is not set
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_ISP1760_HCD is not set
++# CONFIG_USB_ISP1362_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++# CONFIG_USB_MUSB_HDRC is not set
++# CONFIG_USB_GADGET_MUSB_HDRC is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_WDM is not set
++# CONFIG_USB_TMC is not set
++
++#
++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
++#
++
++#
++# also be needed; see USB_STORAGE Help for more info
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_STORAGE_ONETOUCH is not set
++# CONFIG_USB_STORAGE_KARMA is not set
++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_ADUTUX is not set
++# CONFIG_USB_SEVSEG is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_FTDI_ELAN is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TRANCEVIBRATOR is not set
++# CONFIG_USB_IOWARRIOR is not set
++# CONFIG_USB_TEST is not set
++# CONFIG_USB_ISIGHTFW is not set
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DEBUG_FILES=y
++CONFIG_USB_GADGET_VBUS_DRAW=300
++CONFIG_USB_GADGET_SELECTED=y
++# CONFIG_USB_GADGET_AT91 is not set
++# CONFIG_USB_GADGET_ATMEL_USBA is not set
++CONFIG_USB_GADGET_FSL_USB2=y
++CONFIG_USB_FSL_USB2=y
++# CONFIG_USB_GADGET_LH7A40X is not set
++# CONFIG_USB_GADGET_OMAP is not set
++# CONFIG_USB_GADGET_PXA25X is not set
++# CONFIG_USB_GADGET_R8A66597 is not set
++# CONFIG_USB_GADGET_PXA27X is not set
++# CONFIG_USB_GADGET_S3C_HSOTG is not set
++# CONFIG_USB_GADGET_IMX is not set
++# CONFIG_USB_GADGET_S3C2410 is not set
++# CONFIG_USB_GADGET_M66592 is not set
++# CONFIG_USB_GADGET_AMD5536UDC is not set
++# CONFIG_USB_GADGET_FSL_QE is not set
++# CONFIG_USB_GADGET_CI13XXX is not set
++# CONFIG_USB_GADGET_NET2280 is not set
++# CONFIG_USB_GADGET_GOKU is not set
++# CONFIG_USB_GADGET_LANGWELL is not set
++# CONFIG_USB_GADGET_DUMMY_HCD is not set
++CONFIG_USB_GADGET_DUALSPEED=y
++# CONFIG_USB_ZERO is not set
++# CONFIG_USB_AUDIO is not set
++CONFIG_USB_ETH=y
++CONFIG_USB_ETH_RNDIS=y
++# CONFIG_USB_ETH_EEM is not set
++# CONFIG_USB_GADGETFS is not set
++# CONFIG_USB_FUNCTIONFS is not set
++# CONFIG_USB_FILE_STORAGE is not set
++# CONFIG_USB_MASS_STORAGE is not set
++# CONFIG_USB_G_SERIAL is not set
++# CONFIG_USB_MIDI_GADGET is not set
++# CONFIG_USB_G_PRINTER is not set
++# CONFIG_USB_CDC_COMPOSITE is not set
++# CONFIG_USB_G_NOKIA is not set
++# CONFIG_USB_G_MULTI is not set
++# CONFIG_USB_G_HID is not set
++# CONFIG_USB_G_WEBCAM is not set
++
++#
++# OTG and related infrastructure
++#
++# CONFIG_USB_GPIO_VBUS is not set
++# CONFIG_USB_ULPI is not set
++# CONFIG_NOP_USB_XCEIV is not set
++CONFIG_MMC=y
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=y
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++CONFIG_MMC_SDHCI=y
++# CONFIG_MMC_SDHCI_PLTFM is not set
++# CONFIG_MMC_MXC is not set
++# CONFIG_MMC_SPI is not set
++CONFIG_MMC_SDHCI_MXC=y
++# CONFIG_MMC_SDHCI_MXC_SELECT2 is not set
++# CONFIG_MMC_SDHCI_MXC_PIO_MODE is not set
++# CONFIG_MEMSTICK is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_PCA9532 is not set
++CONFIG_LEDS_GPIO=y
++CONFIG_LEDS_GPIO_PLATFORM=y
++# CONFIG_LEDS_LP3944 is not set
++# CONFIG_LEDS_PCA955X is not set
++# CONFIG_LEDS_DAC124S085 is not set
++# CONFIG_LEDS_PWM is not set
++# CONFIG_LEDS_BD2802 is not set
++# CONFIG_LEDS_LT3593 is not set
++CONFIG_LEDS_TRIGGERS=y
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGER_TIMER=y
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++CONFIG_LEDS_TRIGGER_GPIO=y
++CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
++
++#
++# iptables trigger is under Netfilter config (LED target)
++#
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc1"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++CONFIG_RTC_DRV_DS1307=y
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# CONFIG_RTC_DRV_BQ32K is not set
++# CONFIG_RTC_DRV_S35390A is not set
++# CONFIG_RTC_DRV_FM3130 is not set
++# CONFIG_RTC_DRV_RX8581 is not set
++# CONFIG_RTC_DRV_RX8025 is not set
++
++#
++# SPI RTC drivers
++#
++# CONFIG_RTC_DRV_M41T94 is not set
++# CONFIG_RTC_DRV_DS1305 is not set
++# CONFIG_RTC_DRV_DS1390 is not set
++# CONFIG_RTC_DRV_MAX6902 is not set
++# CONFIG_RTC_DRV_R9701 is not set
++# CONFIG_RTC_DRV_RS5C348 is not set
++# CONFIG_RTC_DRV_DS3234 is not set
++# CONFIG_RTC_DRV_PCF2123 is not set
++
++#
++# Platform RTC drivers
++#
++# CONFIG_RTC_DRV_CMOS is not set
++# CONFIG_RTC_DRV_DS1286 is not set
++# CONFIG_RTC_DRV_DS1511 is not set
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
++# CONFIG_RTC_DRV_STK17TA8 is not set
++# CONFIG_RTC_DRV_M48T86 is not set
++# CONFIG_RTC_DRV_M48T35 is not set
++# CONFIG_RTC_DRV_M48T59 is not set
++# CONFIG_RTC_DRV_MSM6242 is not set
++# CONFIG_RTC_MXC is not set
++CONFIG_RTC_DRV_IMXDI=y
++# CONFIG_RTC_DRV_BQ4802 is not set
++# CONFIG_RTC_DRV_RP5C01 is not set
++# CONFIG_RTC_DRV_V3020 is not set
++
++#
++# on-CPU RTC drivers
++#
++# CONFIG_DMADEVICES is not set
++# CONFIG_AUXDISPLAY is not set
++# CONFIG_UIO is not set
++# CONFIG_STAGING is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=y
++# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
++# CONFIG_EXT3_FS_XATTR is not set
++CONFIG_EXT4_FS=y
++# CONFIG_EXT4_FS_XATTR is not set
++# CONFIG_EXT4_DEBUG is not set
++CONFIG_JBD=y
++CONFIG_JBD2=y
++# CONFIG_REISERFS_FS is not set
++# CONFIG_JFS_FS is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
++# CONFIG_OCFS2_FS is not set
++# CONFIG_BTRFS_FS is not set
++# CONFIG_NILFS2_FS is not set
++CONFIG_FILE_LOCKING=y
++CONFIG_FSNOTIFY=y
++# CONFIG_DNOTIFY is not set
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++# CONFIG_AUTOFS4_FS is not set
++# CONFIG_FUSE_FS is not set
++
++#
++# Caches
++#
++# CONFIG_FSCACHE is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++CONFIG_PROC_FS=y
++CONFIG_PROC_SYSCTL=y
++CONFIG_PROC_PAGE_MONITOR=y
++CONFIG_SYSFS=y
++CONFIG_TMPFS=y
++# CONFIG_TMPFS_POSIX_ACL is not set
++# CONFIG_HUGETLB_PAGE is not set
++CONFIG_CONFIGFS_FS=y
++CONFIG_MISC_FILESYSTEMS=y
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_JFFS2_FS is not set
++CONFIG_UBIFS_FS=y
++# CONFIG_UBIFS_FS_XATTR is not set
++# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
++CONFIG_UBIFS_FS_LZO=y
++CONFIG_UBIFS_FS_ZLIB=y
++# CONFIG_UBIFS_FS_DEBUG is not set
++# CONFIG_LOGFS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_SQUASHFS is not set
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CEPH_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++# CONFIG_PARTITION_ADVANCED is not set
++CONFIG_MSDOS_PARTITION=y
++CONFIG_NLS=y
++CONFIG_NLS_DEFAULT="iso8859-15"
++CONFIG_NLS_CODEPAGE_437=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=y
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++CONFIG_NLS_CODEPAGE_1250=y
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=y
++CONFIG_NLS_ISO8859_1=y
++CONFIG_NLS_ISO8859_2=y
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=y
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++CONFIG_ENABLE_WARN_DEPRECATED=y
++CONFIG_ENABLE_MUST_CHECK=y
++CONFIG_FRAME_WARN=1024
++# CONFIG_MAGIC_SYSRQ is not set
++# CONFIG_STRIP_ASM_SYMS is not set
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++# CONFIG_DEBUG_KERNEL is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_MEMORY_INIT is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_LATENCYTOP is not set
++# CONFIG_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++CONFIG_TRACING_SUPPORT=y
++# CONFIG_FTRACE is not set
++# CONFIG_ATOMIC64_SELFTEST is not set
++# CONFIG_SAMPLES is not set
++CONFIG_HAVE_ARCH_KGDB=y
++# CONFIG_ARM_UNWIND is not set
++CONFIG_DEBUG_USER=y
++# CONFIG_OC_ETM is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_DEFAULT_SECURITY_SELINUX is not set
++# CONFIG_DEFAULT_SECURITY_SMACK is not set
++# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
++CONFIG_DEFAULT_SECURITY_DAC=y
++CONFIG_DEFAULT_SECURITY=""
++CONFIG_CRYPTO=y
++
++#
++# Crypto core or helper
++#
++CONFIG_CRYPTO_ALGAPI=y
++CONFIG_CRYPTO_ALGAPI2=y
++# CONFIG_CRYPTO_MANAGER is not set
++# CONFIG_CRYPTO_MANAGER2 is not set
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++# CONFIG_CRYPTO_ECB is not set
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_XCBC is not set
++# CONFIG_CRYPTO_VMAC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_GHASH is not set
++# CONFIG_CRYPTO_MD4 is not set
++# CONFIG_CRYPTO_MD5 is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_ANUBIS is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++CONFIG_CRYPTO_DEFLATE=y
++# CONFIG_CRYPTO_ZLIB is not set
++CONFIG_CRYPTO_LZO=y
++
++#
++# Random Number Generation
++#
++# CONFIG_CRYPTO_ANSI_CPRNG is not set
++# CONFIG_CRYPTO_HW is not set
++# CONFIG_BINARY_PRINTF is not set
++
++#
++# Library routines
++#
++CONFIG_BITREVERSE=y
++CONFIG_RATIONAL=y
++CONFIG_GENERIC_FIND_LAST_BIT=y
++# CONFIG_CRC_CCITT is not set
++CONFIG_CRC16=y
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_LZO_COMPRESS=y
++CONFIG_LZO_DECOMPRESS=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
++CONFIG_NLATTR=y
++CONFIG_GENERIC_ATOMIC64=y
+diff -urN linux.35.old/arch/arm/mach-mx25/clock.c linux.35.new/arch/arm/mach-mx25/clock.c
+--- linux.35.old/arch/arm/mach-mx25/clock.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/clock.c 2010-12-03 09:51:55.345346913 +0100
+@@ -51,6 +51,7 @@
+ #define CCM_LTR1 0x44
+ #define CCM_LTR2 0x48
+ #define CCM_LTR3 0x4c
++#define CCM_MCR 0x64
+
+ static unsigned long get_rate_mpll(void)
+ {
+@@ -72,7 +73,7 @@
+ unsigned long rate = get_rate_mpll();
+
+ if (cctl & (1 << 14))
+- rate = (rate * 3) >> 1;
++ rate = (rate * 3) >> 2;
+
+ return rate / ((cctl >> 30) + 1);
+ }
+@@ -96,10 +97,10 @@
+ unsigned long val = (readl(CRM_BASE + CCM_PCDR0 + reg) >> ofs) & 0x3f;
+ unsigned long fref;
+
+- if (readl(CRM_BASE + 0x64) & (1 << per))
++ if (readl(CRM_BASE + CCM_MCR) & (1 << per))
+ fref = get_rate_upll();
+ else
+- fref = get_rate_ipg(NULL);
++ fref = get_rate_ahb(NULL);
+
+ return fref / (val + 1);
+ }
+@@ -109,11 +110,26 @@
+ return get_rate_per(15);
+ }
+
++static unsigned long get_rate_ssi2(struct clk *clk)
++{
++ return get_rate_per(14);
++}
++
++static unsigned long get_rate_ssi1(struct clk *clk)
++{
++ return get_rate_per(13);
++}
++
+ static unsigned long get_rate_i2c(struct clk *clk)
+ {
+ return get_rate_per(6);
+ }
+
++static unsigned long get_rate_owire(struct clk *clk)
++{
++ return get_rate_per(9);
++}
++
+ static unsigned long get_rate_nfc(struct clk *clk)
+ {
+ return get_rate_per(8);
+@@ -129,9 +145,41 @@
+ return get_rate_per(7);
+ }
+
++static unsigned long get_rate_esdhc1(struct clk *clk)
++{
++ return get_rate_per(3);
++}
++
++static unsigned long get_rate_esdhc2(struct clk *clk)
++{
++ return get_rate_per(4);
++}
++
++static unsigned long get_rate_csi(struct clk *clk)
++{
++ return get_rate_per(0);
++}
++
+ static unsigned long get_rate_otg(struct clk *clk)
+ {
+- return 48000000; /* FIXME */
++ unsigned long cctl = readl(CRM_BASE + CCM_CCTL);
++ unsigned long rate = get_rate_upll();
++
++ return (cctl & (1 << 23)) ? 0 : rate / ((0x3F & (cctl >> 16)) + 1);
++}
++
++static int set_rate_otg(struct clk *clk, unsigned long rate)
++{
++ u32 cctl = __raw_readl(CRM_BASE+CCM_CCTL) & ~(0x3f << 16);
++ unsigned long fref = get_rate_upll();
++ u32 usbdiv = (fref / rate) - 1;
++
++ if (usbdiv > 0x3f) {
++ return -1;
++ }
++ cctl |= usbdiv << 16;
++ __raw_writel(cctl, CRM_BASE+CCM_CCTL);
++ return 0;
+ }
+
+ static int clk_cgcr_enable(struct clk *clk)
+@@ -154,6 +202,10 @@
+ __raw_writel(reg, clk->enable_reg);
+ }
+
++static struct clk ahb_clk = {
++ .get_rate = get_rate_ahb,
++};
++
+ #define DEFINE_CLOCK(name, i, er, es, gr, sr, s) \
+ static struct clk name = { \
+ .id = i, \
+@@ -168,19 +220,23 @@
+
+ DEFINE_CLOCK(gpt_clk, 0, CCM_CGCR0, 5, get_rate_gpt, NULL, NULL);
+ DEFINE_CLOCK(uart_per_clk, 0, CCM_CGCR0, 15, get_rate_uart, NULL, NULL);
++DEFINE_CLOCK(ssi1_per_clk, 0, CCM_CGCR0, 13, get_rate_ipg, NULL, NULL);
++DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(cspi1_clk, 0, CCM_CGCR1, 5, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(cspi2_clk, 0, CCM_CGCR1, 6, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(cspi3_clk, 0, CCM_CGCR1, 7, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL, NULL, NULL);
+ DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL, NULL, NULL);
+ DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0, 7, NULL, NULL, &lcdc_ahb_clk);
++DEFINE_CLOCK(csi_ahb_clk, 0, CCM_CGCR0, 18, get_rate_csi, NULL, NULL);
++DEFINE_CLOCK(csi_per_clk, 0, CCM_CGCR0, 0, get_rate_csi, NULL, &csi_ahb_clk);
+ DEFINE_CLOCK(uart1_clk, 0, CCM_CGCR2, 14, get_rate_uart, NULL, &uart_per_clk);
+ DEFINE_CLOCK(uart2_clk, 0, CCM_CGCR2, 15, get_rate_uart, NULL, &uart_per_clk);
+ DEFINE_CLOCK(uart3_clk, 0, CCM_CGCR2, 16, get_rate_uart, NULL, &uart_per_clk);
+ DEFINE_CLOCK(uart4_clk, 0, CCM_CGCR2, 17, get_rate_uart, NULL, &uart_per_clk);
+ DEFINE_CLOCK(uart5_clk, 0, CCM_CGCR2, 18, get_rate_uart, NULL, &uart_per_clk);
+ DEFINE_CLOCK(nfc_clk, 0, CCM_CGCR0, 8, get_rate_nfc, NULL, NULL);
+-DEFINE_CLOCK(usbotg_clk, 0, CCM_CGCR0, 28, get_rate_otg, NULL, NULL);
++DEFINE_CLOCK(usbotg_clk, 0, CCM_CGCR0, 28, get_rate_otg, set_rate_otg, NULL);
+ DEFINE_CLOCK(pwm1_clk, 0, CCM_CGCR1, 31, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(pwm2_clk, 0, CCM_CGCR2, 0, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(pwm3_clk, 0, CCM_CGCR2, 1, get_rate_ipg, NULL, NULL);
+@@ -191,6 +247,23 @@
+ DEFINE_CLOCK(fec_clk, 0, CCM_CGCR1, 15, get_rate_ipg, NULL, &fec_ahb_clk);
+ DEFINE_CLOCK(dryice_clk, 0, CCM_CGCR1, 8, get_rate_ipg, NULL, NULL);
+ DEFINE_CLOCK(lcdc_clk, 0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk);
++DEFINE_CLOCK(wdt_clk, 0, CCM_CGCR2, 19, get_rate_ipg, NULL, NULL);
++DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, NULL, NULL, NULL);
++DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0, 3, NULL, NULL, &esdhc1_ahb_clk);
++DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGCR1, 13, get_rate_esdhc1, NULL, &esdhc1_per_clk);
++DEFINE_CLOCK(esdhc2_ahb_clk, 1, CCM_CGCR0, 22, NULL, NULL, NULL);
++DEFINE_CLOCK(esdhc2_per_clk, 1, CCM_CGCR0, 4, NULL, NULL, &esdhc2_ahb_clk);
++DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGCR1, 14, get_rate_esdhc2, NULL, &esdhc2_per_clk);
++DEFINE_CLOCK(sdma_ahb_clk, 0, CCM_CGCR0, 26, NULL, NULL, NULL);
++DEFINE_CLOCK(sdma_clk, 0, CCM_CGCR2, 6, get_rate_ipg, NULL, &sdma_ahb_clk);
++DEFINE_CLOCK(ssi1_clk, 0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk);
++DEFINE_CLOCK(ssi2_clk, 1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk);
++DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL);
++DEFINE_CLOCK(csi_clk, 0, CCM_CGCR1, 4, get_rate_csi, NULL, &csi_per_clk);
++DEFINE_CLOCK(can1_clk, 0, CCM_CGCR1, 2, get_rate_ipg, NULL, NULL);
++DEFINE_CLOCK(can2_clk, 0, CCM_CGCR1, 3, get_rate_ipg, NULL, NULL);
++DEFINE_CLOCK(owire_clk, 0, CCM_CGCR0, 9, get_rate_owire, NULL, NULL);
++
+
+ #define _REGISTER_CLOCK(d, n, c) \
+ { \
+@@ -200,6 +273,8 @@
+ },
+
+ static struct clk_lookup lookups[] = {
++ _REGISTER_CLOCK(NULL, "ahb", ahb_clk)
++ _REGISTER_CLOCK(NULL, "sdma", sdma_clk)
+ _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
+ _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
+ _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
+@@ -217,14 +292,25 @@
+ _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
+ _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)
+ _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk)
+- _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
+- _REGISTER_CLOCK("mx25-adc", NULL, tsc_clk)
++ _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk)
++ _REGISTER_CLOCK("imx_adc.0", "tsc_clk", tsc_clk)
++ _REGISTER_CLOCK("imx-tsc.0", NULL, tsc_clk)
+ _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
+ _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
+ _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk)
+ _REGISTER_CLOCK("fec.0", NULL, fec_clk)
+ _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk)
+ _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
++ _REGISTER_CLOCK("imx-wdt.0", NULL, wdt_clk)
++ _REGISTER_CLOCK("sdhci.0", NULL, esdhc1_clk)
++ _REGISTER_CLOCK("sdhci.1", NULL, esdhc2_clk)
++ _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
++ _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
++ _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk)
++ _REGISTER_CLOCK(NULL, "audmux", audmux_clk)
++ _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
++ _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
++ _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk)
+ };
+
+ int __init mx25_clocks_init(void)
+@@ -244,5 +330,25 @@
+
+ mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54);
+
++ /* Debug info */
++ pr_info("Fin: %3lu.%03luMHz\n", \
++ (unsigned long) (24000000 / 1000000),
++ (unsigned long) (24000000 / 1000 % 1000));
++ pr_info("MPLL: %3lu.%03luMHz\n", \
++ get_rate_mpll() / 1000000,
++ get_rate_mpll() / 1000 % 1000);
++ pr_info("UPLL: %3lu.%03luMHz\n", \
++ get_rate_upll() / 1000000,
++ get_rate_upll() / 1000 % 1000);
++ pr_info("CPU: %3lu.%03luMHz\n", \
++ get_rate_arm(NULL) / 1000000,
++ get_rate_arm(NULL) / 1000 % 1000);
++ pr_info("AHB: %3lu.%03luMHz\n", \
++ get_rate_ahb(NULL) / 1000000,
++ get_rate_ahb(NULL) / 1000 % 1000);
++ pr_info("IPG: %3lu.%03luMHz\n", \
++ get_rate_ipg(NULL) / 1000000,
++ get_rate_ipg(NULL) / 1000 % 1000);
++
+ return 0;
+ }
+diff -urN linux.35.old/arch/arm/mach-mx25/devices.c linux.35.new/arch/arm/mach-mx25/devices.c
+--- linux.35.old/arch/arm/mach-mx25/devices.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/devices.c 2010-12-03 09:51:55.345346913 +0100
+@@ -21,103 +21,59 @@
+ #include <linux/gpio.h>
+ #include <mach/mx25.h>
+ #include <mach/irqs.h>
++#include <mach/sdma.h>
+
+-static struct resource uart0[] = {
+- {
+- .start = 0x43f90000,
+- .end = 0x43f93fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 45,
+- .end = 45,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_uart_device0 = {
+- .name = "imx-uart",
+- .id = 0,
+- .resource = uart0,
+- .num_resources = ARRAY_SIZE(uart0),
+-};
+-
+-static struct resource uart1[] = {
+- {
+- .start = 0x43f94000,
+- .end = 0x43f97fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 32,
+- .end = 32,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_uart_device1 = {
+- .name = "imx-uart",
+- .id = 1,
+- .resource = uart1,
+- .num_resources = ARRAY_SIZE(uart1),
+-};
+-
+-static struct resource uart2[] = {
+- {
+- .start = 0x5000c000,
+- .end = 0x5000ffff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 18,
+- .end = 18,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_uart_device2 = {
+- .name = "imx-uart",
+- .id = 2,
+- .resource = uart2,
+- .num_resources = ARRAY_SIZE(uart2),
+-};
+-
+-static struct resource uart3[] = {
+- {
+- .start = 0x50008000,
+- .end = 0x5000bfff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 5,
+- .end = 5,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_uart_device3 = {
+- .name = "imx-uart",
+- .id = 3,
+- .resource = uart3,
+- .num_resources = ARRAY_SIZE(uart3),
+-};
++#include "sdma_script_code.h"
+
+-static struct resource uart4[] = {
+- {
+- .start = 0x5002c000,
+- .end = 0x5002ffff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 40,
+- .end = 40,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_uart_device4 = {
+- .name = "imx-uart",
+- .id = 4,
+- .resource = uart4,
+- .num_resources = ARRAY_SIZE(uart4),
+-};
+-
+-#define MX25_OTG_BASE_ADDR 0x53FF4000
++void mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr)
++{
++ sdma_script_addr->mxc_sdma_ap_2_ap_addr = ap_2_ap_ADDR;
++ sdma_script_addr->mxc_sdma_ap_2_bp_addr = -1;
++ sdma_script_addr->mxc_sdma_bp_2_ap_addr = -1;
++ sdma_script_addr->mxc_sdma_loopback_on_dsp_side_addr = -1;
++ sdma_script_addr->mxc_sdma_mcu_interrupt_only_addr = -1;
++
++ sdma_script_addr->mxc_sdma_firi_2_per_addr = -1;
++ sdma_script_addr->mxc_sdma_firi_2_mcu_addr = -1;
++ sdma_script_addr->mxc_sdma_per_2_firi_addr = -1;
++ sdma_script_addr->mxc_sdma_mcu_2_firi_addr = -1;
++
++ sdma_script_addr->mxc_sdma_uart_2_per_addr = uart_2_per_ADDR;
++ sdma_script_addr->mxc_sdma_uart_2_mcu_addr = uart_2_mcu_ADDR;
++ sdma_script_addr->mxc_sdma_per_2_app_addr = per_2_app_ADDR;
++ sdma_script_addr->mxc_sdma_mcu_2_app_addr = mcu_2_app_ADDR;
++
++ sdma_script_addr->mxc_sdma_per_2_per_addr = -1;
++
++ sdma_script_addr->mxc_sdma_uartsh_2_per_addr = uartsh_2_per_ADDR;
++ sdma_script_addr->mxc_sdma_uartsh_2_mcu_addr = uartsh_2_mcu_ADDR;
++ sdma_script_addr->mxc_sdma_per_2_shp_addr = per_2_shp_ADDR;
++ sdma_script_addr->mxc_sdma_mcu_2_shp_addr = mcu_2_shp_ADDR;
++
++ sdma_script_addr->mxc_sdma_ata_2_mcu_addr = ata_2_mcu_ADDR;
++ sdma_script_addr->mxc_sdma_mcu_2_ata_addr = mcu_2_ata_ADDR;
++
++ sdma_script_addr->mxc_sdma_app_2_per_addr = app_2_per_ADDR;
++ sdma_script_addr->mxc_sdma_app_2_mcu_addr = app_2_mcu_ADDR;
++ sdma_script_addr->mxc_sdma_shp_2_per_addr = shp_2_per_ADDR;
++ sdma_script_addr->mxc_sdma_shp_2_mcu_addr = shp_2_mcu_ADDR;
++
++ sdma_script_addr->mxc_sdma_mshc_2_mcu_addr = -1;
++ sdma_script_addr->mxc_sdma_mcu_2_mshc_addr = -1;
++
++ sdma_script_addr->mxc_sdma_spdif_2_mcu_addr = -1;
++ sdma_script_addr->mxc_sdma_mcu_2_spdif_addr = -1;
++
++ sdma_script_addr->mxc_sdma_asrc_2_mcu_addr = -1;
++
++ sdma_script_addr->mxc_sdma_dptc_dvfs_addr = -1;
++ sdma_script_addr->mxc_sdma_ext_mem_2_ipu_addr = ext_mem__ipu_ram_ADDR;
++ sdma_script_addr->mxc_sdma_descrambler_addr = -1;
++
++ sdma_script_addr->mxc_sdma_start_addr = (unsigned short *)sdma_code;
++ sdma_script_addr->mxc_sdma_ram_code_size = RAM_CODE_SIZE;
++ sdma_script_addr->mxc_sdma_ram_code_start_addr = RAM_CODE_START_ADDR;
++}
+
+ static u64 otg_dmamask = DMA_BIT_MASK(32);
+
+@@ -181,63 +137,6 @@
+ .num_resources = ARRAY_SIZE(mxc_usbh2_resources),
+ };
+
+-static struct resource mxc_spi_resources0[] = {
+- {
+- .start = 0x43fa4000,
+- .end = 0x43fa7fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 14,
+- .end = 14,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_spi_device0 = {
+- .name = "spi_imx",
+- .id = 0,
+- .num_resources = ARRAY_SIZE(mxc_spi_resources0),
+- .resource = mxc_spi_resources0,
+-};
+-
+-static struct resource mxc_spi_resources1[] = {
+- {
+- .start = 0x50010000,
+- .end = 0x50013fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 13,
+- .end = 13,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_spi_device1 = {
+- .name = "spi_imx",
+- .id = 1,
+- .num_resources = ARRAY_SIZE(mxc_spi_resources1),
+- .resource = mxc_spi_resources1,
+-};
+-
+-static struct resource mxc_spi_resources2[] = {
+- {
+- .start = 0x50004000,
+- .end = 0x50007fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 0,
+- .end = 0,
+- .flags = IORESOURCE_IRQ,
+- },
+-};
+-
+-struct platform_device mxc_spi_device2 = {
+- .name = "spi_imx",
+- .id = 2,
+- .num_resources = ARRAY_SIZE(mxc_spi_resources2),
+- .resource = mxc_spi_resources2,
+-};
+-
+ static struct resource mxc_pwm_resources0[] = {
+ {
+ .start = 0x53fe0000,
+@@ -308,7 +207,7 @@
+ };
+
+ struct platform_device mxc_keypad_device = {
+- .name = "mxc-keypad",
++ .name = "imx-keypad",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mxc_keypad_resources),
+ .resource = mxc_keypad_resources,
+@@ -333,63 +232,6 @@
+ .resource = mxc_pwm_resources3,
+ };
+
+-static struct resource mxc_i2c_1_resources[] = {
+- {
+- .start = 0x43f80000,
+- .end = 0x43f83fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 3,
+- .end = 3,
+- .flags = IORESOURCE_IRQ,
+- }
+-};
+-
+-struct platform_device mxc_i2c_device0 = {
+- .name = "imx-i2c",
+- .id = 0,
+- .num_resources = ARRAY_SIZE(mxc_i2c_1_resources),
+- .resource = mxc_i2c_1_resources,
+-};
+-
+-static struct resource mxc_i2c_2_resources[] = {
+- {
+- .start = 0x43f98000,
+- .end = 0x43f9bfff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 4,
+- .end = 4,
+- .flags = IORESOURCE_IRQ,
+- }
+-};
+-
+-struct platform_device mxc_i2c_device1 = {
+- .name = "imx-i2c",
+- .id = 1,
+- .num_resources = ARRAY_SIZE(mxc_i2c_2_resources),
+- .resource = mxc_i2c_2_resources,
+-};
+-
+-static struct resource mxc_i2c_3_resources[] = {
+- {
+- .start = 0x43f84000,
+- .end = 0x43f87fff,
+- .flags = IORESOURCE_MEM,
+- }, {
+- .start = 10,
+- .end = 10,
+- .flags = IORESOURCE_IRQ,
+- }
+-};
+-
+-struct platform_device mxc_i2c_device2 = {
+- .name = "imx-i2c",
+- .id = 2,
+- .num_resources = ARRAY_SIZE(mxc_i2c_3_resources),
+- .resource = mxc_i2c_3_resources,
+-};
+-
+ static struct mxc_gpio_port imx_gpio_ports[] = {
+ {
+ .chip.label = "gpio-0",
+@@ -461,12 +303,12 @@
+
+ static struct resource mx25_rtc_resources[] = {
+ {
+- .start = MX25_DRYICE_BASE_ADDR,
+- .end = MX25_DRYICE_BASE_ADDR + 0x40,
++ .start = DRYICE_BASE_ADDR,
++ .end = DRYICE_BASE_ADDR + 0x40,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+- .start = MX25_INT_DRYICE,
++ .start = MXC_INT_DRYICE_NORM,
+ .flags = IORESOURCE_IRQ
+ },
+ };
+@@ -515,3 +357,100 @@
+ .num_resources = ARRAY_SIZE(mxc_wdt_resources),
+ .resource = mxc_wdt_resources,
+ };
++
++/* imx adc driver */
++static struct resource imx_adc_resources[] = {
++ {
++ .start = TSC_BASE_ADDR,
++ .end = TSC_BASE_ADDR + PAGE_SIZE,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = MXC_INT_TSC,
++ .end = MXC_INT_TSC,
++ .flags = IORESOURCE_IRQ,
++ }
++};
++
++struct platform_device imx_adc_device = {
++ .name = "imx_adc",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(imx_adc_resources),
++ .resource = imx_adc_resources,
++ .dev = {
++ .release = NULL,
++ },
++};
++
++
++static struct resource mx25_tsc_resources[] = {
++ {
++ .start = TSC_BASE_ADDR,
++ .end = TSC_BASE_ADDR + PAGE_SIZE,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = MXC_INT_TSC,
++ .end = MXC_INT_TSC,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++struct platform_device mx25_tsc_device = {
++ .name = "imx-tsc",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mx25_tsc_resources),
++ .resource = mx25_tsc_resources,
++};
++
++static struct resource mxc_w1_master_resources[] = {
++ {
++ .start = MX25_OWIRE_BASE_ADDR,
++ .end = MX25_OWIRE_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++};
++
++struct platform_device mxc_w1_master_device = {
++ .name = "mxc_w1",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(mxc_w1_master_resources),
++ .resource = mxc_w1_master_resources,
++};
++
++static struct resource imx_ssi_resources0[] = {
++ {
++ .start = MX25_SSI1_BASE_ADDR,
++ .end = MX25_SSI1_BASE_ADDR + 0x3fff,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = MX25_INT_SSI1,
++ .end = MX25_INT_SSI1,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static struct resource imx_ssi_resources1[] = {
++ {
++ .start = MX25_SSI2_BASE_ADDR,
++ .end = MX25_SSI2_BASE_ADDR + 0x3fff,
++ .flags = IORESOURCE_MEM
++ }, {
++ .start = MX25_INT_SSI2,
++ .end = MX25_INT_SSI2,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++struct platform_device imx_ssi_device0 = {
++ .name = "imx-ssi",
++ .id = 0,
++ .num_resources = ARRAY_SIZE(imx_ssi_resources0),
++ .resource = imx_ssi_resources0,
++};
++
++struct platform_device imx_ssi_device1 = {
++ .name = "imx-ssi",
++ .id = 1,
++ .num_resources = ARRAY_SIZE(imx_ssi_resources1),
++ .resource = imx_ssi_resources1,
++};
+\ No newline at end of file
+diff -urN linux.35.old/arch/arm/mach-mx25/devices.h linux.35.new/arch/arm/mach-mx25/devices.h
+--- linux.35.old/arch/arm/mach-mx25/devices.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/devices.h 2010-12-03 09:51:55.349345851 +0100
+@@ -22,3 +22,8 @@
+ extern struct platform_device mx25_rtc_device;
+ extern struct platform_device mx25_fb_device;
+ extern struct platform_device mxc_wdt;
++extern struct platform_device imx_adc_device;
++extern struct platform_device mx25_tsc_device;
++extern struct platform_device mxc_w1_master_device;
++extern struct platform_device imx_ssi_device0;
++extern struct platform_device imx_ssi_device1;
+\ No newline at end of file
+diff -urN linux.35.old/arch/arm/mach-mx25/devices-imx25.h linux.35.new/arch/arm/mach-mx25/devices-imx25.h
+--- linux.35.old/arch/arm/mach-mx25/devices-imx25.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/mach-mx25/devices-imx25.h 2010-12-03 09:51:55.349345851 +0100
+@@ -0,0 +1,43 @@
++/*
++ * Copyright (C) 2010 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * 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 <mach/mx25.h>
++#include <mach/devices-common.h>
++
++#define imx25_add_flexcan0(pdata) \
++ imx_add_flexcan(0, MX25_CAN1_BASE_ADDR, SZ_16K, MX25_INT_CAN1, pdata)
++#define imx25_add_flexcan1(pdata) \
++ imx_add_flexcan(1, MX25_CAN2_BASE_ADDR, SZ_16K, MX25_INT_CAN2, pdata)
++
++#define imx25_add_imx_i2c0(pdata) \
++ imx_add_imx_i2c(0, MX25_I2C1_BASE_ADDR, SZ_16K, MX25_INT_I2C1, pdata)
++#define imx25_add_imx_i2c1(pdata) \
++ imx_add_imx_i2c(1, MX25_I2C2_BASE_ADDR, SZ_16K, MX25_INT_I2C2, pdata)
++#define imx25_add_imx_i2c2(pdata) \
++ imx_add_imx_i2c(2, MX25_I2C3_BASE_ADDR, SZ_16K, MX25_INT_I2C3, pdata)
++
++#define imx25_add_imx_uart0(pdata) \
++ imx_add_imx_uart_1irq(0, MX25_UART1_BASE_ADDR, SZ_16K, MX25_INT_UART1, pdata)
++#define imx25_add_imx_uart1(pdata) \
++ imx_add_imx_uart_1irq(1, MX25_UART2_BASE_ADDR, SZ_16K, MX25_INT_UART2, pdata)
++#define imx25_add_imx_uart2(pdata) \
++ imx_add_imx_uart_1irq(2, MX25_UART3_BASE_ADDR, SZ_16K, MX25_INT_UART3, pdata)
++#define imx25_add_imx_uart3(pdata) \
++ imx_add_imx_uart_1irq(3, MX25_UART4_BASE_ADDR, SZ_16K, MX25_INT_UART4, pdata)
++#define imx25_add_imx_uart4(pdata) \
++ imx_add_imx_uart_1irq(4, MX25_UART5_BASE_ADDR, SZ_16K, MX25_INT_UART5, pdata)
++
++#define imx25_add_mxc_nand(pdata) \
++ imx_add_mxc_nand_v21(MX25_NFC_BASE_ADDR, MX25_INT_NANDFC, pdata)
++
++#define imx25_add_spi_imx0(pdata) \
++ imx_add_spi_imx(0, MX25_CSPI1_BASE_ADDR, SZ_16K, MX25_INT_CSPI1, pdata)
++#define imx25_add_spi_imx1(pdata) \
++ imx_add_spi_imx(1, MX25_CSPI2_BASE_ADDR, SZ_16K, MX25_INT_CSPI2, pdata)
++#define imx25_add_spi_imx2(pdata) \
++ imx_add_spi_imx(2, MX25_CSPI3_BASE_ADDR, SZ_16K, MX25_INT_CSPI3, pdata)
+diff -urN linux.35.old/arch/arm/mach-mx25/dma.c linux.35.new/arch/arm/mach-mx25/dma.c
+--- linux.35.old/arch/arm/mach-mx25/dma.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/mach-mx25/dma.c 2010-12-03 09:51:55.351854203 +0100
+@@ -0,0 +1,666 @@
++/*
++ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/scatterlist.h>
++#include <mach/hardware.h>
++#include <mach/dma.h>
++
++//#include "serial.h"
++
++#ifdef CONFIG_SND_MXC_SOC_IRAM
++#define soc_trans_type int_2_per
++#else
++#define soc_trans_type emi_2_per
++#endif
++
++#define MXC_SSI_TX0_REG 0x0
++#define MXC_SSI_TX1_REG 0x4
++#define MXC_SSI_RX0_REG 0x8
++#define MXC_SSI_RX1_REG 0xC
++#define MXC_SSI_TXFIFO_WML 0x4
++#define MXC_SSI_RXFIFO_WML 0x6
++
++#define MXC_ESAI_TX_REG 0x00
++#define MXC_ESAI_RX_REG 0x04
++#define MXC_ESAI_FIFO_WML 0x40
++
++struct mxc_sdma_info_entry_s {
++ mxc_dma_device_t device;
++ mxc_sdma_channel_params_t *chnl_info;
++};
++
++#if 0
++static mxc_sdma_channel_params_t mxc_sdma_uart1_rx_params = {
++ .chnl_params = {
++ .watermark_level = UART1_UFCR_RXTL,
++ .per_address = UART1_BASE_ADDR,
++ .peripheral_type = UART,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_UART1_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART1_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart1_tx_params = {
++ .chnl_params = {
++ .watermark_level = UART1_UFCR_TXTL,
++ .per_address = UART1_BASE_ADDR + MXC_UARTUTXD,
++ .peripheral_type = UART,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_UART1_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART1_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart2_rx_params = {
++ .chnl_params = {
++ .watermark_level = UART2_UFCR_RXTL,
++ .per_address = UART2_BASE_ADDR,
++ .peripheral_type = UART,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_UART2_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART2_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart2_tx_params = {
++ .chnl_params = {
++ .watermark_level = UART2_UFCR_TXTL,
++ .per_address = UART2_BASE_ADDR + MXC_UARTUTXD,
++ .peripheral_type = UART,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_UART2_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART2_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart3_rx_params = {
++ .chnl_params = {
++ .watermark_level = UART3_UFCR_RXTL,
++ .per_address = UART3_BASE_ADDR,
++ .peripheral_type = UART_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_UART3_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART3_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart3_tx_params = {
++ .chnl_params = {
++ .watermark_level = UART3_UFCR_TXTL,
++ .per_address = UART3_BASE_ADDR + MXC_UARTUTXD,
++ .peripheral_type = UART_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_UART3_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART3_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart4_rx_params = {
++ .chnl_params = {
++ .watermark_level = UART4_UFCR_RXTL,
++ .per_address = UART4_BASE_ADDR,
++ .peripheral_type = UART_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_UART4_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART4_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart4_tx_params = {
++ .chnl_params = {
++ .watermark_level = UART4_UFCR_TXTL,
++ .per_address = UART4_BASE_ADDR + MXC_UARTUTXD,
++ .peripheral_type = UART_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_UART4_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART4_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart5_rx_params = {
++ .chnl_params = {
++ .watermark_level = UART5_UFCR_RXTL,
++ .per_address = UART5_BASE_ADDR,
++ .peripheral_type = UART_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_UART5_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART5_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_uart5_tx_params = {
++ .chnl_params = {
++ .watermark_level = UART5_UFCR_TXTL,
++ .per_address = UART5_BASE_ADDR + MXC_UARTUTXD,
++ .peripheral_type = UART_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_UART5_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_UART5_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++#endif
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_8bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_16bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI1_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi1_24bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI1_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_SSI1_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI1_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_rx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_tx0_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX0_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX0,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_8bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_8BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_16bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_rx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_RXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_RX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_SSI2_RX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_RX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_ssi2_24bit_tx1_params = {
++ .chnl_params = {
++ .watermark_level = MXC_SSI_TXFIFO_WML,
++ .per_address = SSI2_BASE_ADDR + MXC_SSI_TX1_REG,
++ .peripheral_type = SSI_SP,
++ .transfer_type = emi_2_per,
++ .event_id = DMA_REQ_SSI2_TX1,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_SSI2_TX,
++ .chnl_priority = 2,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_memory_params = {
++ .chnl_params = {
++ .peripheral_type = MEMORY,
++ .transfer_type = emi_2_emi,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_MEMORY,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_esai_16bit_rx_params = {
++ .chnl_params = {
++ .watermark_level = MXC_ESAI_FIFO_WML,
++ .per_address = ESAI_BASE_ADDR + MXC_ESAI_RX_REG,
++ .peripheral_type = ESAI,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_ESAI_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_ESAI_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_esai_16bit_tx_params = {
++ .chnl_params = {
++ .watermark_level = MXC_ESAI_FIFO_WML,
++ .per_address = ESAI_BASE_ADDR + MXC_ESAI_TX_REG,
++ .peripheral_type = ESAI,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_ESAI_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_16BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_ESAI_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_esai_24bit_rx_params = {
++ .chnl_params = {
++ .watermark_level = MXC_ESAI_FIFO_WML,
++ .per_address = ESAI_BASE_ADDR + MXC_ESAI_RX_REG,
++ .peripheral_type = ESAI,
++ .transfer_type = per_2_emi,
++ .event_id = DMA_REQ_ESAI_RX,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_ESAI_RX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static mxc_sdma_channel_params_t mxc_sdma_esai_24bit_tx_params = {
++ .chnl_params = {
++ .watermark_level = MXC_ESAI_FIFO_WML,
++ .per_address = ESAI_BASE_ADDR + MXC_ESAI_TX_REG,
++ .peripheral_type = ESAI,
++ .transfer_type = soc_trans_type,
++ .event_id = DMA_REQ_ESAI_TX,
++ .bd_number = 32,
++ .word_size = TRANSFER_32BIT,
++ },
++ .channel_num = MXC_DMA_CHANNEL_ESAI_TX,
++ .chnl_priority = MXC_SDMA_DEFAULT_PRIORITY,
++};
++
++static struct mxc_sdma_info_entry_s mxc_sdma_active_dma_info[] = {
++#if 0
++ { MXC_DMA_UART1_RX, &mxc_sdma_uart1_rx_params, },
++ { MXC_DMA_UART1_TX, &mxc_sdma_uart1_tx_params, },
++ { MXC_DMA_UART2_RX, &mxc_sdma_uart2_rx_params, },
++ { MXC_DMA_UART2_TX, &mxc_sdma_uart2_tx_params, },
++ { MXC_DMA_UART3_RX, &mxc_sdma_uart3_rx_params, },
++ { MXC_DMA_UART3_TX, &mxc_sdma_uart3_tx_params, },
++ { MXC_DMA_UART4_RX, &mxc_sdma_uart4_rx_params, },
++ { MXC_DMA_UART4_TX, &mxc_sdma_uart4_tx_params, },
++ { MXC_DMA_UART5_RX, &mxc_sdma_uart5_rx_params, },
++ { MXC_DMA_UART5_TX, &mxc_sdma_uart5_tx_params, },
++#endif
++ { MXC_DMA_SSI1_8BIT_RX0, &mxc_sdma_ssi1_8bit_rx0_params, },
++ { MXC_DMA_SSI1_8BIT_TX0, &mxc_sdma_ssi1_8bit_tx0_params, },
++ { MXC_DMA_SSI1_16BIT_RX0, &mxc_sdma_ssi1_16bit_rx0_params, },
++ { MXC_DMA_SSI1_16BIT_TX0, &mxc_sdma_ssi1_16bit_tx0_params, },
++ { MXC_DMA_SSI1_24BIT_RX0, &mxc_sdma_ssi1_24bit_rx0_params, },
++ { MXC_DMA_SSI1_24BIT_TX0, &mxc_sdma_ssi1_24bit_tx0_params, },
++ { MXC_DMA_SSI1_8BIT_RX1, &mxc_sdma_ssi1_8bit_rx1_params, },
++ { MXC_DMA_SSI1_8BIT_TX1, &mxc_sdma_ssi1_8bit_tx1_params, },
++ { MXC_DMA_SSI1_16BIT_RX1, &mxc_sdma_ssi1_16bit_rx1_params, },
++ { MXC_DMA_SSI1_16BIT_TX1, &mxc_sdma_ssi1_16bit_tx1_params, },
++ { MXC_DMA_SSI1_24BIT_RX1, &mxc_sdma_ssi1_24bit_rx1_params, },
++ { MXC_DMA_SSI1_24BIT_TX1, &mxc_sdma_ssi1_24bit_tx1_params, },
++ { MXC_DMA_SSI2_8BIT_RX0, &mxc_sdma_ssi2_8bit_rx0_params, },
++ { MXC_DMA_SSI2_8BIT_TX0, &mxc_sdma_ssi2_8bit_tx0_params, },
++ { MXC_DMA_SSI2_16BIT_RX0, &mxc_sdma_ssi2_16bit_rx0_params, },
++ { MXC_DMA_SSI2_16BIT_TX0, &mxc_sdma_ssi2_16bit_tx0_params, },
++ { MXC_DMA_SSI2_24BIT_RX0, &mxc_sdma_ssi2_24bit_rx0_params, },
++ { MXC_DMA_SSI2_24BIT_TX0, &mxc_sdma_ssi2_24bit_tx0_params, },
++ { MXC_DMA_SSI2_8BIT_RX1, &mxc_sdma_ssi2_8bit_rx1_params, },
++ { MXC_DMA_SSI2_8BIT_TX1, &mxc_sdma_ssi2_8bit_tx1_params, },
++ { MXC_DMA_SSI2_16BIT_RX1, &mxc_sdma_ssi2_16bit_rx1_params, },
++ { MXC_DMA_SSI2_16BIT_TX1, &mxc_sdma_ssi2_16bit_tx1_params, },
++ { MXC_DMA_SSI2_24BIT_RX1, &mxc_sdma_ssi2_24bit_rx1_params, },
++ { MXC_DMA_SSI2_24BIT_TX1, &mxc_sdma_ssi2_24bit_tx1_params, },
++ { MXC_DMA_ESAI_16BIT_RX, &mxc_sdma_esai_16bit_rx_params, },
++ { MXC_DMA_ESAI_16BIT_TX, &mxc_sdma_esai_16bit_tx_params, },
++ { MXC_DMA_ESAI_24BIT_RX, &mxc_sdma_esai_24bit_rx_params, },
++ { MXC_DMA_ESAI_24BIT_TX, &mxc_sdma_esai_24bit_tx_params, },
++ { MXC_DMA_MEMORY, &mxc_sdma_memory_params, },
++};
++
++/*
++ * This functions Returns the SDMA paramaters associated for a module
++ *
++ * channel_id: the ID of the module requesting DMA
++ * returns the sdma parameters structure for the device
++ */
++mxc_sdma_channel_params_t *mxc_sdma_get_channel_params(mxc_dma_device_t
++ channel_id)
++{
++ struct mxc_sdma_info_entry_s *p = mxc_sdma_active_dma_info;
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(mxc_sdma_active_dma_info); i++, p++) {
++ if (p->device == channel_id)
++ return p->chnl_info;
++ }
++ return NULL;
++}
++EXPORT_SYMBOL(mxc_sdma_get_channel_params);
++
++/*
++ * This functions marks the SDMA channels that are statically allocated
++ *
++ * chnl: the channel array used to store channel information
++ */
++void mxc_get_static_channels(mxc_dma_channel_t *chnl)
++{
++#ifdef CONFIG_SDMA_IRAM
++ int i;
++ for (i = MXC_DMA_CHANNEL_IRAM; i < MAX_DMA_CHANNELS; i++)
++ chnl[i].dynamic = 0;
++#endif
++}
++EXPORT_SYMBOL(mxc_get_static_channels);
+diff -urN linux.35.old/arch/arm/mach-mx25/Kconfig linux.35.new/arch/arm/mach-mx25/Kconfig
+--- linux.35.old/arch/arm/mach-mx25/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/Kconfig 2010-12-03 09:51:55.351854203 +0100
+@@ -4,5 +4,57 @@
+
+ config MACH_MX25_3DS
+ bool "Support MX25PDK (3DS) Platform"
++ select IMX_HAVE_PLATFORM_IMX_UART
++ select IMX_HAVE_PLATFORM_MXC_NAND
++
++config MACH_VMX25
++ bool "Support Voipac VMX25 module"
++ select IMX_HAVE_PLATFORM_IMX_I2C
++ select IMX_HAVE_PLATFORM_IMX_UART
++ select IMX_HAVE_PLATFORM_MXC_NAND
++ select IMX_HAVE_PLATFORM_SPI_IMX
++ select IMX_HAVE_PLATFORM_FLEXCAN
++ depends on ARCH_MX25
++ help
++ Include support for Voipac VMX25 processor module
++
++choice
++ prompt "Baseboard"
++ depends on MACH_VMX25
++ default MACH_VMX_BASEBOARD
++
++config MACH_VMX_BASEBOARD
++ bool "Voipac development baseboard"
++ help
++ This adds board specific devices that can be found on Voipac's
++ development baseboard.
++
++endchoice
++
++choice
++ prompt "SD slot selection"
++ depends on MACH_VMX25
++ default VMX_SD_ON_BOARD if MACH_VMX_BASEBOARD
++
++config VMX_SD_ON_MODULE
++ bool "Use integrated SD slot"
++ depends on MACH_VMX25
++ help
++ Provide SD CLK signal to vmx25 on module SD slot.
++
++config VMX_SD_ON_BOARD
++ bool "Use external SD slot"
++ depends on MACH_VMX25
++ help
++ Provide SD CLK signal to vmx25 baseboard SD slot.
++
++endchoice
++
++config MXC_SDMA_API
++ bool "Use SDMA API"
++ default y
++ help
++ This selects the Freescale MXC SDMA API.
++ If unsure, say N.
+
+ endif
+diff -urN linux.35.old/arch/arm/mach-mx25/mach-mx25pdk.c linux.35.new/arch/arm/mach-mx25/mach-mx25pdk.c
+--- linux.35.old/arch/arm/mach-mx25/mach-mx25pdk.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/mach-mx25pdk.c 2010-12-03 09:51:55.351854203 +0100
+@@ -36,10 +36,12 @@
+ #include <mach/mx25.h>
+ #include <mach/mxc_nand.h>
+ #include <mach/imxfb.h>
+-#include "devices.h"
+ #include <mach/iomux-mx25.h>
+
+-static struct imxuart_platform_data uart_pdata = {
++#include "devices-imx25.h"
++#include "devices.h"
++
++static const struct imxuart_platform_data uart_pdata __initconst = {
+ .flags = IMXUART_HAVE_RTSCTS,
+ };
+
+@@ -142,7 +144,7 @@
+ mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
+ ARRAY_SIZE(mx25pdk_pads));
+
+- mxc_register_device(&mxc_uart_device0, &uart_pdata);
++ imx25_add_imx_uart0(&uart_pdata);
+ mxc_register_device(&mxc_usbh2, NULL);
+ mxc_register_device(&mxc_nand_device, &mx25pdk_nand_board_info);
+ mxc_register_device(&mx25_rtc_device, NULL);
+diff -urN linux.35.old/arch/arm/mach-mx25/mach-vmx25.c linux.35.new/arch/arm/mach-mx25/mach-vmx25.c
+--- linux.35.old/arch/arm/mach-mx25/mach-vmx25.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/mach-mx25/mach-vmx25.c 2011-01-12 14:54:30.832513858 +0100
+@@ -0,0 +1,467 @@
++/*
++ * arch/arm/mach-mx25/mach-vmx25.c
++ *
++ * Copyright (C) 2010 Voipac <support@voipac.com>
++ *
++ * Based on arch/arm/mach-mx25/karo-tx25.c
++ * Copyright (C) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ *
++ * 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
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ *
++ * This file adds support for the Voipac VMX25 processor modules
++ */
++
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/serial_8250.h>
++#include <linux/fec.h>
++#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE)
++#include <mtd/mtd-abi.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <asm/mach/flash.h>
++#endif
++
++#include <linux/serial.h>
++#include <linux/fsl_devices.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/leds.h>
++#include <linux/if_ether.h>
++
++#include <asm/setup.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++#include <mach/common.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++#include <mach/iomux-v1.h>
++#include <mach/iomux-v3.h>
++#include <mach/iomux-mx25.h>
++#include <mach/irqs.h>
++#include <mach/clock.h>
++#include <mach/imxfb.h>
++#include <mach/mmc.h>
++#include <mach/mxc_nand.h>
++#if defined(CONFIG_TOUCHSCREEN_MXC_TSC) || defined(CONFIG_TOUCHSCREEN_MXC_TSC_MODULE)
++#include <mach/mxc_tsc.h>
++#endif
++
++#include "devices.h"
++
++int vmx_mod_type = -1;
++
++static void vmx25_gpio_config(struct pad_desc *pd, int num)
++{
++ int i;
++
++ for (i = 0; i < num; i++) {
++ if (mxc_iomux_v3_setup_pad(&pd[i]) == 0) {
++ mxc_iomux_v3_release_pad(&pd[i]);
++ }
++ }
++}
++
++/* MTD NAND flash */
++#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE)
++static struct pad_desc vmx25_nand_pads[] = {
++ MX25_PAD_NF_CE0__NF_CE0,
++ MX25_PAD_NFWE_B__NFWE_B,
++ MX25_PAD_NFRE_B__NFRE_B,
++ MX25_PAD_NFALE__NFALE,
++ MX25_PAD_NFCLE__NFCLE,
++ MX25_PAD_NFWP_B__NFWP_B,
++ MX25_PAD_NFRB__NFRB,
++ MX25_PAD_D7__D7,
++ MX25_PAD_D6__D6,
++ MX25_PAD_D5__D5,
++ MX25_PAD_D4__D4,
++ MX25_PAD_D3__D3,
++ MX25_PAD_D2__D2,
++ MX25_PAD_D1__D1,
++ MX25_PAD_D0__D0,
++};
++
++static struct mtd_partition mxc_nand_partitions[] = {
++ {
++ .name = "nand.barebox",
++ .offset = 0,
++ .size = 256 * 1024},
++ {
++ .name = "nand.bareboxenv",
++ .offset = MTDPART_OFS_APPEND,
++ .size = 128 * 1024},
++ {
++ .name = "nand.kernel",
++ .offset = MTDPART_OFS_APPEND,
++ .size = 2688 * 1024},
++ {
++ .name = "nand.rootfs",
++ .offset = MTDPART_OFS_APPEND,
++ .size = MTDPART_SIZ_FULL},
++};
++
++static struct mxc_nand_platform_data vmx25_nand_pdata = {
++ .parts = mxc_nand_partitions,
++ .nr_parts = ARRAY_SIZE(mxc_nand_partitions),
++ .hw_ecc = 1,
++ .width = 1,
++ .flash_bbt = 1,
++};
++
++static int vmx25_nand_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "%s: Configuring NAND pins\n", __FUNCTION__);
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx25_nand_pads,
++ ARRAY_SIZE(vmx25_nand_pads));
++
++ return ret;
++}
++arch_initcall(vmx25_nand_init);
++#endif // CONFIG_MTD_NAND_MXC CONFIG_MTD_NAND_MXC_MODULE
++
++#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
++
++static struct fec_platform_data vmx25_fec_pdata = {
++ .phy = PHY_INTERFACE_MODE_RMII,
++};
++
++/*
++ * Setup GPIO for FEC device
++ *
++ */
++
++static struct pad_desc vmx25_fec_pwr_gpios[] = {
++ MX25_PAD_D11__GPIO_4_9, /* FEC PHY power on pin */
++ MX25_PAD_D13__GPIO_4_7, /* FEC reset */
++};
++
++#define VMX25_FEC_PWR_GPIO (GPIO_PORTD | 9)
++#define VMX25_FEC_RST_GPIO (GPIO_PORTD | 7)
++
++static struct pad_desc vmx25_fec_gpios[] = {
++ MX25_PAD_FEC_MDC__FEC_MDC,
++ MX25_PAD_FEC_MDIO__FEC_MDIO,
++ MX25_PAD_FEC_TDATA0__FEC_TDATA0,
++ MX25_PAD_FEC_TDATA1__FEC_TDATA1,
++ MX25_PAD_FEC_TX_EN__FEC_TX_EN,
++ MX25_PAD_FEC_RDATA0__FEC_RDATA0,
++ MX25_PAD_FEC_RDATA1__FEC_RDATA1,
++ MX25_PAD_FEC_RX_DV__FEC_RX_DV,
++ MX25_PAD_FEC_TX_CLK__FEC_TX_CLK,
++};
++
++static int vmx25_fec_init(void)
++{
++ int ret;
++
++ printk(KERN_INFO "%s: Configuring FEC pins\n", __FUNCTION__);
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx25_fec_pwr_gpios,
++ ARRAY_SIZE(vmx25_fec_pwr_gpios));
++ if (ret) {
++ return ret;
++ }
++
++ gpio_request(VMX25_FEC_PWR_GPIO, "FEC PHY enable");
++ gpio_request(VMX25_FEC_RST_GPIO, "FEC PHY reset");
++
++
++ /* turn off PHY power and lift reset */
++ gpio_direction_output(VMX25_FEC_PWR_GPIO, 0); /* drop PHY power */
++ gpio_direction_output(VMX25_FEC_RST_GPIO, 0); /* assert reset */
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx25_fec_gpios,
++ ARRAY_SIZE(vmx25_fec_gpios));
++
++ udelay(100);
++
++ /* turn on PHY power and lift reset */
++ gpio_set_value(VMX25_FEC_PWR_GPIO, 1);
++ gpio_set_value(VMX25_FEC_RST_GPIO, 1);
++
++ return ret;
++}
++arch_initcall(vmx25_fec_init);
++
++#endif // CONFIG_FEC CONFIG_FEC_MODULE
++
++#if defined(CONFIG_TOUCHSCREEN_MXC_TSC) || defined(CONFIG_TOUCHSCREEN_MXC_TSC_MODULE)
++static struct mxc_tsc_pdata vmx25_tsc_pdata = {
++ .pen_debounce_time = 32,
++ .intref = 1,
++ .adc_clk = 1666667,
++ .tsc_mode = MXC_TSC_4WIRE,
++ .r_xplate = 660,
++ .hsyncen = 1,
++ .hsyncpol = 0,
++};
++#endif
++
++static struct platform_dev_list {
++ struct platform_device *pdev;
++ void *pdata;
++} vmx25_devices[] __initdata = {
++#if defined(CONFIG_IMX2_WDT) || defined(CONFIG_IMX2_WDT_MODULE)
++ { .pdev = &mxc_wdt, },
++#endif
++#if defined(CONFIG_RTC_DRV_IMXDI) || defined(CONFIG_RTC_DRV_IMXDI_MODULE)
++ { .pdev = &mx25_rtc_device, },
++#endif
++#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE)
++ { .pdev = &mxc_nand_device, &vmx25_nand_pdata},
++#endif
++#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
++ { .pdev = &mx25_fec_device, &vmx25_fec_pdata},
++#endif
++#if defined(CONFIG_IMX_ADC) || defined(CONFIG_IMX_ADC_MODULE)
++ { .pdev = &imx_adc_device, },
++#endif
++#if defined(CONFIG_TOUCHSCREEN_MXC_TSC) || defined(CONFIG_TOUCHSCREEN_MXC_TSC_MODULE)
++ { .pdev = &mx25_tsc_device, &vmx25_tsc_pdata, },
++#endif
++#if defined(CONFIG_W1_MASTER_MXC) || defined(CONFIG_W1_MASTER_MXC_MODULE)
++ { .pdev = &mxc_w1_master_device, },
++#endif
++};
++#define VMX25_NUM_DEVICES ARRAY_SIZE(vmx25_devices)
++
++static __init void vmx25_board_init(void)
++{
++ int i;
++
++ printk(KERN_INFO "%s: \n", __FUNCTION__);
++
++ for (i = 0; i < VMX25_NUM_DEVICES; i++) {
++ int ret;
++
++ if (vmx25_devices[i].pdev == NULL) continue;
++
++ printk(KERN_INFO "%s: Registering platform device[%d] @ %p dev %p: %s\n",
++ __FUNCTION__, i, vmx25_devices[i].pdev, &vmx25_devices[i].pdev->dev,
++ vmx25_devices[i].pdev->name);
++ if (vmx25_devices[i].pdata) {
++ ret = mxc_register_device(vmx25_devices[i].pdev,
++ vmx25_devices[i].pdata);
++ } else {
++ ret = platform_device_register(vmx25_devices[i].pdev);
++ }
++ if (ret) {
++ printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n",
++ __FUNCTION__, i, vmx25_devices[i].pdev->name, ret);
++ }
++ }
++#if defined(CONFIG_RTC_DRV_IMXDI) || defined(CONFIG_RTC_DRV_IMXDI_MODULE)
++ device_init_wakeup(&mx25_rtc_device.dev, 1);
++#endif
++
++ printk(KERN_INFO "%s: Done\n", __FUNCTION__);
++}
++
++static struct pad_desc vmx25_gpios[] __refdata = {
++ MX25_PAD_GPIO_A__GPIO_A,
++ MX25_PAD_GPIO_B__GPIO_B,
++ MX25_PAD_GPIO_C__GPIO_C,
++ MX25_PAD_GPIO_D__GPIO_D,
++ MX25_PAD_GPIO_E__GPIO_E,
++ MX25_PAD_GPIO_F__GPIO_F,
++ MX25_PAD_CSI_D7__GPIO_1_6,
++ MX25_PAD_CSI_D8__GPIO_1_7,
++ MX25_PAD_CSI_MCLK__GPIO_1_8,
++ MX25_PAD_CSI_VSYNC__GPIO_1_9,
++ MX25_PAD_CSI_HSYNC__GPIO_1_10,
++ MX25_PAD_CSI_PIXCLK__GPIO_1_11,
++ MX25_PAD_I2C1_CLK__GPIO_1_12,
++ MX25_PAD_I2C1_DAT__GPIO_1_13,
++ MX25_PAD_CSPI1_MOSI__GPIO_1_14,
++ MX25_PAD_CSPI1_MISO__GPIO_1_15,
++ MX25_PAD_CSPI1_SS0__GPIO_1_16,
++ MX25_PAD_CSPI1_SS1__GPIO_1_17,
++ MX25_PAD_CSPI1_SCLK__GPIO_1_18,
++ MX25_PAD_LD5__GPIO_1_19,
++ MX25_PAD_LD6__GPIO_1_20,
++ MX25_PAD_LD7__GPIO_1_21,
++ MX25_PAD_HSYNC__GPIO_1_22,
++ MX25_PAD_VSYNC__GPIO_1_23,
++ MX25_PAD_LSCLK__GPIO_1_24,
++ MX25_PAD_OE_ACD__GPIO_1_25,
++ MX25_PAD_PWM__GPIO_1_26,
++ MX25_PAD_CSI_D2__GPIO_1_27,
++ MX25_PAD_CSI_D3__GPIO_1_28,
++ MX25_PAD_CSI_D4__GPIO_1_29,
++ MX25_PAD_CSI_D5__GPIO_1_30,
++ MX25_PAD_CSI_D6__GPIO_1_31,
++
++ MX25_PAD_A14__GPIO_2_0,
++ MX25_PAD_A15__GPIO_2_1,
++ MX25_PAD_A16__GPIO_2_2,
++ MX25_PAD_A17__GPIO_2_3,
++ MX25_PAD_A18__GPIO_2_4,
++ MX25_PAD_A19__GPIO_2_5,
++ MX25_PAD_A20__GPIO_2_6,
++ MX25_PAD_A21__GPIO_2_7,
++ MX25_PAD_A22__GPIO_2_8,
++ MX25_PAD_A23__GPIO_2_9,
++ MX25_PAD_A24__GPIO_2_10,
++ MX25_PAD_A25__GPIO_2_11,
++ MX25_PAD_EB0__GPIO_2_12,
++ MX25_PAD_EB1__GPIO_2_13,
++ MX25_PAD_OE__GPIO_2_14,
++ MX25_PAD_LD0__GPIO_2_15,
++ MX25_PAD_LD1__GPIO_2_16,
++ MX25_PAD_LD2__GPIO_2_17,
++ MX25_PAD_LD3__GPIO_2_18,
++ MX25_PAD_LD4__GPIO_2_19,
++ MX25_PAD_DE_B__GPIO_2_20,
++ MX25_PAD_CLKO__GPIO_2_21,
++ MX25_PAD_CSPI1_RDY__GPIO_2_22,
++ MX25_PAD_SD1_CMD__GPIO_2_23,
++ MX25_PAD_SD1_CLK__GPIO_2_24,
++ MX25_PAD_SD1_DATA0__GPIO_2_25,
++ MX25_PAD_SD1_DATA1__GPIO_2_26,
++ MX25_PAD_SD1_DATA2__GPIO_2_27,
++ MX25_PAD_SD1_DATA3__GPIO_2_28,
++// MX25_PAD_KPP_ROW0__GPIO_2_29,
++// MX25_PAD_KPP_ROW1__GPIO_2_30,
++// MX25_PAD_KPP_ROW2__GPIO_2_31,
++// MX25_PAD_KPP_ROW3__GPIO_3_0,
++// MX25_PAD_KPP_COL0__GPIO_3_1,
++// MX25_PAD_KPP_COL1__GPIO_3_2,
++// MX25_PAD_KPP_COL2__GPIO_3_3,
++// MX25_PAD_KPP_COL3__GPIO_3_4,
++ MX25_PAD_FEC_MDC__GPIO_3_5,
++ MX25_PAD_FEC_MDIO__GPIO_3_6,
++ MX25_PAD_FEC_TDATA0__GPIO_3_7,
++ MX25_PAD_FEC_TDATA1__GPIO_3_8,
++ MX25_PAD_FEC_TX_EN__GPIO_3_9,
++ MX25_PAD_FEC_RDATA0__GPIO_3_10,
++ MX25_PAD_FEC_RDATA1__GPIO_3_11,
++ MX25_PAD_FEC_RX_DV__GPIO_3_12,
++ MX25_PAD_FEC_TX_CLK__GPIO_3_13,
++#if defined(CONFIG_W1_MASTER_MXC) || defined(CONFIG_W1_MASTER_MXC_MODULE)
++ MX25_PAD_RTCK__OWIRE,
++#else
++ MX25_PAD_RTCK__GPIO_3_14,
++#endif
++ MX25_PAD_EXT_ARMCLK__GPIO_3_15,
++ MX25_PAD_UPLL_BYPCLK__GPIO_3_16,
++ MX25_PAD_VSTBY_REQ__GPIO_3_17,
++ MX25_PAD_VSTBY_ACK__GPIO_3_18,
++ MX25_PAD_POWER_FAIL__GPIO_3_19,
++ MX25_PAD_CS4__GPIO_3_20,
++ MX25_PAD_CS5__GPIO_3_21,
++#if 0 /* do not mess with these */
++ MX25_PAD_NF_CE0__GPIO_3_22,
++#endif
++ MX25_PAD_ECB__GPIO_3_23,
++ MX25_PAD_LBA__GPIO_3_24,
++ MX25_PAD_RW__GPIO_3_25,
++#if 0 /* do not mess with these */
++ MX25_PAD_NFWE_B__GPIO_3_26,
++ MX25_PAD_NFRE_B__GPIO_3_27,
++ MX25_PAD_NFALE__GPIO_3_28,
++ MX25_PAD_NFCLE__GPIO_3_29,
++ MX25_PAD_NFWP_B__GPIO_3_30,
++ MX25_PAD_NFRB__GPIO_3_31,
++#endif
++ MX25_PAD_A10__GPIO_4_0,
++ MX25_PAD_A13__GPIO_4_1,
++ MX25_PAD_CS0__GPIO_4_2,
++ MX25_PAD_CS1__GPIO_4_3,
++ MX25_PAD_BCLK__GPIO_4_4,
++ MX25_PAD_D15__GPIO_4_5,
++ MX25_PAD_D14__GPIO_4_6,
++ MX25_PAD_D13__GPIO_4_7,
++ MX25_PAD_D12__GPIO_4_8,
++ MX25_PAD_D11__GPIO_4_9,
++ MX25_PAD_D10__GPIO_4_10,
++ MX25_PAD_D9__GPIO_4_11,
++ MX25_PAD_D8__GPIO_4_12,
++#if 0 /* do not mess with these */
++ MX25_PAD_D7__GPIO_4_13,
++ MX25_PAD_D6__GPIO_4_14,
++ MX25_PAD_D5__GPIO_4_15,
++ MX25_PAD_D4__GPIO_4_16,
++ MX25_PAD_D3__GPIO_4_17,
++ MX25_PAD_D2__GPIO_4_18,
++ MX25_PAD_D1__GPIO_4_19,
++ MX25_PAD_D0__GPIO_4_20,
++#endif
++ MX25_PAD_CSI_D9__GPIO_4_21,
++ MX25_PAD_UART1_RXD__GPIO_4_22,
++ MX25_PAD_UART1_TXD__GPIO_4_23,
++ MX25_PAD_UART1_RTS__GPIO_4_24,
++ MX25_PAD_UART1_CTS__GPIO_4_25,
++ MX25_PAD_UART2_RXD__GPIO_4_26,
++ MX25_PAD_UART2_TXD__GPIO_4_27,
++ MX25_PAD_UART2_RTS__GPIO_4_28,
++ MX25_PAD_UART2_CTS__GPIO_4_29,
++ MX25_PAD_BOOT_MODE0__GPIO_4_30,
++ MX25_PAD_BOOT_MODE1__GPIO_4_31,
++};
++
++static int __init vmx25_setup_gpios(void)
++{
++ vmx25_gpio_config(vmx25_gpios, ARRAY_SIZE(vmx25_gpios));
++ return 0;
++}
++late_initcall(vmx25_setup_gpios);
++
++static void __init vmx25_fixup(struct machine_desc *desc, struct tag *tags,
++ char **cmdline, struct meminfo *mi)
++{
++}
++
++static void __init vmx25_timer_init(void)
++{
++ mx25_clocks_init();
++}
++
++static struct sys_timer vmx25_timer = {
++ .init = vmx25_timer_init,
++};
++
++static int __init vmx_mod_type_setup(char *line)
++{
++ get_option(&line, &vmx_mod_type);
++ printk(KERN_INFO "%s: Module type set to 0x%02x by kernel cmd line\n",
++ __FUNCTION__, vmx_mod_type);
++ return 1;
++}
++__setup("module_type=", vmx_mod_type_setup);
++
++MACHINE_START(VMX25, "Voipac VMX25 module (Freescale i.MX25)")
++ /* Maintainer: <support@voipac.com> */
++ .phys_io = MX25_AIPS1_BASE_ADDR,
++ .io_pg_offst = ((MX25_AIPS1_BASE_ADDR_VIRT) >> 18) & 0xfffc,
++ .fixup = vmx25_fixup,
++ .boot_params = MX25_PHYS_OFFSET + 0x100,
++ .map_io = mx25_map_io,
++ .init_irq = mx25_init_irq,
++ .init_machine = vmx25_board_init,
++ .timer = &vmx25_timer,
++MACHINE_END
++
+diff -urN linux.35.old/arch/arm/mach-mx25/Makefile linux.35.new/arch/arm/mach-mx25/Makefile
+--- linux.35.old/arch/arm/mach-mx25/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/Makefile 2010-12-03 09:51:55.351854203 +0100
+@@ -1,3 +1,7 @@
+ obj-y := mm.o devices.o
+ obj-$(CONFIG_ARCH_MX25) += clock.o
+ obj-$(CONFIG_MACH_MX25_3DS) += mach-mx25pdk.o
++obj-$(CONFIG_MACH_VMX25) += mach-vmx25.o
++obj-$(CONFIG_MACH_VMX_BASEBOARD) += vmx-baseboard.o
++
++obj-$(CONFIG_MXC_SDMA_API) += dma.o
+\ No newline at end of file
+diff -urN linux.35.old/arch/arm/mach-mx25/mm.c linux.35.new/arch/arm/mach-mx25/mm.c
+--- linux.35.old/arch/arm/mach-mx25/mm.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/mach-mx25/mm.c 2010-12-03 09:51:55.356349597 +0100
+@@ -14,10 +14,6 @@
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+ #include <linux/mm.h>
+diff -urN linux.35.old/arch/arm/mach-mx25/sdma_script_code.h linux.35.new/arch/arm/mach-mx25/sdma_script_code.h
+--- linux.35.old/arch/arm/mach-mx25/sdma_script_code.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/mach-mx25/sdma_script_code.h 2010-12-03 09:51:55.356349597 +0100
+@@ -0,0 +1,159 @@
++
++/*
++ * Copyright 2008 Freescale Semiconductor, 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 program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++/*!
++ * @file sdma_script_code.h
++ * @brief This file contains functions of SDMA scripts code initialization
++ *
++ * The file was generated automatically. Based on sdma scripts library.
++ *
++ * @ingroup SDMA
++ */
++/************************************************************************
++
++ SDMA RELEASE LABEL: "SS15_SENNA"
++
++************************************************************************/
++
++#ifndef SDMA_SCRIPT_CODE_H
++#define SDMA_SCRIPT_CODE_H
++
++/*!
++ * SDMA ROM scripts start addresses and sizes
++ */
++#define start_ADDR 0
++#define start_SIZE 22
++
++#define core_ADDR 80
++#define core_SIZE 233
++
++#define common_ADDR 313
++#define common_SIZE 416
++
++#define ap_2_ap_ADDR 729
++#define ap_2_ap_SIZE 41
++
++#define app_2_mcu_ADDR 770
++#define app_2_mcu_SIZE 64
++
++#define mcu_2_app_ADDR 834
++#define mcu_2_app_SIZE 70
++
++#define uart_2_mcu_ADDR 904
++#define uart_2_mcu_SIZE 75
++
++#define shp_2_mcu_ADDR 979
++#define shp_2_mcu_SIZE 69
++
++#define mcu_2_shp_ADDR 1048
++#define mcu_2_shp_SIZE 72
++
++#define uartsh_2_mcu_ADDR 1120
++#define uartsh_2_mcu_SIZE 69
++
++#define app_2_per_ADDR 1189
++#define app_2_per_SIZE 66
++
++#define per_2_app_ADDR 1255
++#define per_2_app_SIZE 74
++
++#define per_2_shp_ADDR 1329
++#define per_2_shp_SIZE 78
++
++#define shp_2_per_ADDR 1407
++#define shp_2_per_SIZE 72
++
++#define mcu_2_ata_ADDR 1479
++#define mcu_2_ata_SIZE 81
++
++#define ata_2_mcu_ADDR 1560
++#define ata_2_mcu_SIZE 96
++
++#define loop_DMAs_routines_ADDR 1656
++#define loop_DMAs_routines_SIZE 227
++
++#define test_ADDR 1883
++#define test_SIZE 63
++
++#define signature_ADDR 1022
++#define signature_SIZE 1
++
++/*!
++ * SDMA RAM scripts start addresses and sizes
++ */
++#define ext_mem__ipu_ram_ADDR 6144
++#define ext_mem__ipu_ram_SIZE 123
++
++#define uart_2_per_ADDR 6267
++#define uart_2_per_SIZE 73
++
++#define uartsh_2_per_ADDR 6340
++#define uartsh_2_per_SIZE 67
++
++/*!
++ * SDMA RAM image start address and size
++ */
++#define RAM_CODE_START_ADDR 6144
++#define RAM_CODE_SIZE ARRAY_SIZE(sdma_code)
++
++/*!
++ * Buffer that holds the SDMA RAM image
++ */
++__attribute__ ((__aligned__(4)))
++#ifndef CONFIG_XIP_KERNEL
++const
++#endif
++static const short sdma_code[] = {
++ 0x0e70, 0x0611, 0x5616, 0xc18a, 0x7d2a, 0x5ade, 0x008e, 0xc19c,
++ 0x7c26, 0x5be0, 0x5ef0, 0x5ce8, 0x0688, 0x08ff, 0x0011, 0x28ff,
++ 0x00bc, 0x53f6, 0x05df, 0x7d0b, 0x6dc5, 0x03df, 0x7d03, 0x6bd5,
++ 0xd84f, 0x982b, 0x6b05, 0xc6d8, 0x7e27, 0x7f29, 0x982b, 0x6d01,
++ 0x03df, 0x7d05, 0x6bd5, 0xc702, 0x7e18, 0x7f1a, 0x982b, 0x6b05,
++ 0xc678, 0x7e07, 0x7f06, 0x52de, 0x53e6, 0xc1a8, 0x7dd7, 0x0200,
++ 0x9803, 0x0007, 0x6004, 0x680c, 0x53f6, 0x028e, 0x00a3, 0xc2ad,
++ 0x048b, 0x0498, 0x0454, 0x068a, 0x982b, 0x0207, 0x680c, 0x6ddf,
++ 0x0107, 0x68ff, 0x60d0, 0x9834, 0x0207, 0x68ff, 0x6d28, 0x0107,
++ 0x6004, 0x680c, 0x9834, 0x0007, 0x68ff, 0x60d0, 0x9834, 0x0288,
++ 0x03a5, 0x3b03, 0x3d03, 0x4d00, 0x7d0a, 0x0804, 0x00a5, 0x00da,
++ 0x7d1a, 0x02a0, 0x7b01, 0x65d8, 0x7eee, 0x65ff, 0x7eec, 0x0804,
++ 0x02d0, 0x7d11, 0x4b00, 0x7c0f, 0x008a, 0x3003, 0x6dcf, 0x6bdf,
++ 0x0015, 0x0015, 0x7b02, 0x65d8, 0x0000, 0x7edd, 0x63ff, 0x7edb,
++ 0x3a03, 0x6dcd, 0x6bdd, 0x008a, 0x7b02, 0x65d8, 0x0000, 0x7ed3,
++ 0x65ff, 0x7ed1, 0x0006, 0xc23a, 0x57db, 0x52f3, 0x6ad5, 0x56fb,
++ 0x028e, 0x1a94, 0x6ac3, 0x62c8, 0x0269, 0x7d1e, 0x1e94, 0x6ee3,
++ 0x62d0, 0x5aeb, 0x62c8, 0x0248, 0x6ed3, 0x6ac8, 0x2694, 0x52eb,
++ 0x6ad5, 0x6ee3, 0x62c8, 0x026e, 0x7d27, 0x6ac8, 0x7f23, 0x2501,
++ 0x4d00, 0x7d26, 0x028e, 0x1a98, 0x6ac3, 0x62c8, 0x6ec3, 0x0260,
++ 0x7df1, 0x62d0, 0xc2d1, 0x98c0, 0x6ee3, 0x008f, 0x2001, 0x00d5,
++ 0x7d01, 0x008d, 0x05a0, 0x62c8, 0x026e, 0x7d0e, 0x6ac8, 0x7f0a,
++ 0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d09, 0xc251,
++ 0x57db, 0x987f, 0x0007, 0x6aff, 0x62d0, 0xc2d1, 0x0458, 0x0454,
++ 0x6add, 0x7ff8, 0xc261, 0x987c, 0xc230, 0xc23a, 0x57db, 0x52f3,
++ 0x6ad5, 0x56fb, 0x028e, 0x1a94, 0x5202, 0x0269, 0x7d17, 0x1e94,
++ 0x5206, 0x0248, 0x5a06, 0x2694, 0x5206, 0x026e, 0x7d26, 0x6ac8,
++ 0x7f22, 0x2501, 0x4d00, 0x7d27, 0x028e, 0x1a98, 0x5202, 0x0260,
++ 0x7df3, 0x6add, 0x7f18, 0x62d0, 0xc2d1, 0x9903, 0x008f, 0x2001,
++ 0x00d5, 0x7d01, 0x008d, 0x05a0, 0x5206, 0x026e, 0x7d0e, 0x6ac8,
++ 0x7f0a, 0x2001, 0x7cf9, 0x6add, 0x7f06, 0x0000, 0x4d00, 0x7d0b,
++ 0xc251, 0x57db, 0x98c9, 0x0007, 0x6aff, 0x6add, 0x7ffc, 0x62d0,
++ 0xc2d1, 0x0458, 0x0454, 0x6add, 0x7ff6, 0xc261, 0x98c6,
++};
++#endif
+diff -urN linux.35.old/arch/arm/mach-mx25/vmx-baseboard.c linux.35.new/arch/arm/mach-mx25/vmx-baseboard.c
+--- linux.35.old/arch/arm/mach-mx25/vmx-baseboard.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/mach-mx25/vmx-baseboard.c 2011-01-12 14:24:20.076493613 +0100
+@@ -0,0 +1,1559 @@
++/*
++ * arch/arm/mach-mx25/vmx-baseboard.c
++ *
++ * Copyright (C) 2010 Voipac <support@voipac.com>
++ *
++ * Based on arch/arm/mach-mx25/stk5-baseboard.c
++ * Copyright (C) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ *
++ * 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
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ *
++ * This file adds support for devices found on Voipac baseboard
++ */
++
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/serial.h>
++#include <linux/fsl_devices.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/leds.h>
++#include <linux/dma-mapping.h>
++#include <linux/pwm_backlight.h>
++#include <linux/i2c.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/eeprom.h>
++#include <linux/spi/ads7846.h>
++#include <linux/can/platform/mcp251x.h>
++
++#include <asm/setup.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++
++#include <mach/common.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++#include <mach/iomux.h>
++#include <mach/iomux-v1.h>
++#include <mach/iomux-mx25.h>
++#include <mach/irqs.h>
++#include <mach/clock.h>
++#include <mach/imxfb.h>
++#include <mach/mmc.h>
++#include <mach/mxc_ehci.h>
++#include <mach/board-vmx25.h>
++#include <mach/sdhci.h>
++#include <mach/i2c.h>
++
++#include <linux/input/matrix_keypad.h>
++
++#include <mach/ssi.h>
++#include <mach/audmux.h>
++
++#include "devices.h"
++#include "devices-imx25.h"
++
++/*
++ * 1.uart
++ * 2.usb
++ * 3.i2c
++ * 5.flexcan
++ * 6.spican
++ * 4.spi
++ * 7.keypad
++ * 8.leds
++ * 9.audio
++ * 10.radio
++ */
++
++#define UART1_ENABLED 1
++#define UART2_ENABLED 1
++#define UART3_ENABLED 0 /* conflicts with SPI */
++#define UART4_ENABLED 0 /* conflicts with SSI */
++#define UART5_ENABLED 1
++
++//#define USE_SPI_GPIO_B5_CS 1 /* spi flash not work with intergrated cs */ - conflict with LCD
++
++#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
++static struct pad_desc vmx_uart_pads[][4] = {
++ {
++ MX25_PAD_UART1_TXD__UART1_TXD,
++ MX25_PAD_UART1_RXD__UART1_RXD,
++ MX25_PAD_UART1_CTS__UART1_CTS,
++ MX25_PAD_UART1_RTS__UART1_RTS,
++ },
++ {
++ MX25_PAD_UART2_TXD__UART2_TXD,
++ MX25_PAD_UART2_RXD__UART2_RXD,
++ MX25_PAD_UART2_CTS__UART2_CTS,
++ MX25_PAD_UART2_RTS__UART2_RTS,
++ },
++ {
++ /* UART 3 not useable on VMX25 */
++ },
++ {
++ /* UART 4 not useable on VMX25 */
++ },
++ {
++ MX25_PAD_ECB__UART5_TXD_MUX,
++ MX25_PAD_LBA__UART5_RXD_MUX,
++ MX25_PAD_CS4__UART5_CTS,
++ MX25_PAD_CS5__UART5_RTS,
++ },
++};
++
++static int vmx_uart_init(struct platform_device *pdev)
++{
++ if (pdev->id >= ARRAY_SIZE(vmx_uart_pads)) {
++ return -ENODEV;
++ }
++ return mxc_iomux_v3_setup_multiple_pads(vmx_uart_pads[pdev->id],
++ ARRAY_SIZE(vmx_uart_pads[pdev->id]));
++}
++
++static void vmx_uart_exit(struct platform_device *pdev)
++{
++ BUG_ON(pdev->id >= ARRAY_SIZE(vmx_uart_pads));
++ mxc_iomux_v3_release_multiple_pads(vmx_uart_pads[pdev->id],
++ ARRAY_SIZE(vmx_uart_pads[pdev->id]));
++}
++
++static const struct imxuart_platform_data vmx_uart_pdata[] __initconst = {
++ {
++ .init = vmx_uart_init,
++ .exit = vmx_uart_exit,
++ .flags = IMXUART_HAVE_RTSCTS,
++ }, {
++ .init = vmx_uart_init,
++ .exit = vmx_uart_exit,
++ .flags = IMXUART_HAVE_RTSCTS,
++ }, {
++ .init = vmx_uart_init,
++ .exit = vmx_uart_exit,
++ .flags = IMXUART_HAVE_RTSCTS,
++ }, {
++ .init = vmx_uart_init,
++ .exit = vmx_uart_exit,
++ .flags = IMXUART_HAVE_RTSCTS,
++ }, {
++ .init = vmx_uart_init,
++ .exit = vmx_uart_exit,
++ .flags = IMXUART_HAVE_RTSCTS,
++ }, {
++
++ },
++};
++#endif // CONFIG_SERIAL_IMX
++
++#if defined(CONFIG_USB_EHCI_MXC) || defined(CONFIG_USB_EHCI_MXC_MODULE) || \
++ defined(CONFIG_USB_FSL_USB2) || defined(CONFIG_USB_FSL_USB2_MODULE)
++/*
++ * The USB power switch (MAX893L) used on the STK5 base board
++ * produces a pulse (~100us) on the OC output whenever
++ * the ON input is activated. This disturbs the USB controller.
++ * As a workaround don't use USB power switching.
++ * If you have a hardware that works cleanly you may
++ * #define USE_USB_PWR to enable port power control for
++ * the EHCI controller.
++ */
++static struct pad_desc vmx_usbh2_pads[] = {
++#ifdef USE_USB_PWR
++ MX25_PAD_D9__USBH2_PWR,
++ MX25_PAD_D8__USBH2_OC,
++#else
++ MX25_PAD_D9__GPIO_4_11,
++ MX25_PAD_D8__GPIO_4_12,
++#endif
++};
++
++static int vmx_usbh2_init(struct platform_device *pdev)
++{
++ int ret;
++#ifndef USE_USB_PWR
++ const int pwr_gpio = 3 * 32 + 11;
++#endif
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_usbh2_pads,
++ ARRAY_SIZE(vmx_usbh2_pads));
++#ifdef USE_USB_PWR
++ if (ret) {
++ return ret;
++ }
++#else
++ ret = gpio_request(pwr_gpio, "USBH2_PWR");
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ pwr_gpio);
++ mxc_iomux_v3_release_multiple_pads(vmx_usbh2_pads,
++ ARRAY_SIZE(vmx_usbh2_pads));
++ return ret;
++ }
++
++ gpio_direction_output(pwr_gpio, 1);
++#endif
++ if (ret != 0) {
++ mxc_iomux_v3_release_multiple_pads(vmx_usbh2_pads,
++ ARRAY_SIZE(vmx_usbh2_pads));
++ goto exit;
++ }
++
++exit:
++#ifndef USE_USB_PWR
++ gpio_free(pwr_gpio);
++#endif
++ return ret;
++}
++
++static int vmx_usbh2_exit(struct platform_device *pdev)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx_usbh2_pads,
++ ARRAY_SIZE(vmx_usbh2_pads));
++ return 0;
++}
++
++static struct pad_desc vmx_usbotg_pads[] = {
++#ifdef USE_USB_PWR
++ MX25_PAD_GPIO_A__USBOTG_PWR,
++ MX25_PAD_GPIO_B__USBOTG_OC,
++#else
++ MX25_PAD_GPIO_A__GPIO_A,
++ MX25_PAD_GPIO_B__GPIO_B,
++#endif
++};
++
++static int vmx_usbotg_init(struct platform_device *pdev)
++{
++ int ret;
++#ifndef USE_USB_PWR
++ const int pwr_gpio = 0 * 32 + 0;
++#endif
++ printk(KERN_INFO "%s: \n", __FUNCTION__);
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_usbotg_pads,
++ ARRAY_SIZE(vmx_usbotg_pads));
++#ifdef USE_USB_PWR
++ if (ret) {
++ return ret;
++ }
++#else
++
++ ret = gpio_request(pwr_gpio, "USBOTG_PWR");
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ pwr_gpio);
++ mxc_iomux_v3_release_multiple_pads(vmx_usbh2_pads,
++ ARRAY_SIZE(vmx_usbh2_pads));
++ return ret;
++ }
++
++ gpio_direction_output(pwr_gpio, 1);
++#endif
++ if (ret != 0) {
++ mxc_iomux_v3_release_multiple_pads(vmx_usbotg_pads,
++ ARRAY_SIZE(vmx_usbotg_pads));
++ goto exit;
++ }
++
++exit:
++#ifndef USE_USB_PWR
++ gpio_free(pwr_gpio);
++#endif
++
++ return ret;
++}
++
++static int vmx_usbotg_exit(struct platform_device *pdev)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx_usbotg_pads,
++ ARRAY_SIZE(vmx_usbotg_pads));
++ return 0;
++}
++#endif // CONFIG_USB_EHCI_MXC || CONFIG_USB_FSL_USB2
++
++static int otg_mode_host = 1;
++
++static int __init vmx_otg_mode(char *options)
++{
++ if (!strcmp(options, "host"))
++ otg_mode_host = 1;
++ else if (!strcmp(options, "device"))
++ otg_mode_host = 0;
++ else
++ pr_info("otg_mode neither \"host\" nor \"device\". "
++ "Defaulting to host\n");
++ return 0;
++}
++__setup("otg_mode=", vmx_otg_mode);
++
++#if defined(CONFIG_USB_EHCI_MXC) || defined(CONFIG_USB_EHCI_MXC_MODULE)
++static struct mxc_usbh_platform_data vmx_usbotg_pdata = {
++ .init = vmx_usbotg_init,
++ .exit = vmx_usbotg_exit,
++ .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_UTMI_16BIT,
++ .flags = MXC_EHCI_INTERFACE_DIFF_UNI /* Differential/unidirectional (6-wire) */
++// MXC_EHCI_INTERNAL_PHY /* USB transceiver enable */ | \
++// MXC_EHCI_POWER_PINS_ENABLED /* assertion of the OC input is reported to the OTG core */
++};
++
++static struct mxc_usbh_platform_data vmx_usbh2_pdata = {
++ .init = vmx_usbh2_init,
++ .exit = vmx_usbh2_exit,
++ .portsc = MXC_EHCI_MODE_SERIAL,
++ .flags = MXC_EHCI_INTERFACE_SINGLE_UNI /* Single-ended/unidirectional (6-wire) */ | \
++ MXC_EHCI_INTERNAL_PHY /* USB transceiver enable */ | \
++ MXC_EHCI_IPPUE_DOWN /* Software has control over ipp_pue_pulldwn_dpdm */
++// MXC_EHCI_POWER_PINS_ENABLED /* the assertion of the OC input is reported to the host core */
++
++};
++#endif // CONFIG_USB_EHCI_MXC
++
++#if defined(CONFIG_USB_FSL_USB2) || defined(CONFIG_USB_FSL_USB2_MODULE)
++static struct fsl_usb2_platform_data vmx_usb_pdata = {
++ .operating_mode = FSL_USB2_DR_DEVICE,
++ .phy_mode = FSL_USB2_PHY_UTMI,
++};
++#endif // CONFIG_USB_FSL_USB2
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++#include <linux/i2c/at24.h>
++#if defined(CONFIG_I2C_IMX) || defined(CONFIG_I2C_IMX_MODULE)
++static struct pad_desc mxc_i2c1_pads[] = {
++ MX25_PAD_I2C1_CLK__I2C1_CLK,
++ MX25_PAD_I2C1_DAT__I2C1_DAT,
++};
++#elif defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
++static struct pad_desc mxc_i2c1_pads[] = {
++ MX25_PAD_I2C1_CLK__GPIO_1_12,
++ MX25_PAD_I2C1_DAT__GPIO_1_13,
++};
++#else
++#error No suitable I2C bus driver configured
++#endif
++
++static int vmx_i2c1_init(struct device *dev)
++{
++ return mxc_iomux_v3_setup_multiple_pads(mxc_i2c1_pads,
++ ARRAY_SIZE(mxc_i2c1_pads));
++}
++
++static void vmx_i2c1_exit(struct device *dev)
++{
++ mxc_iomux_v3_release_multiple_pads(mxc_i2c1_pads,
++ ARRAY_SIZE(mxc_i2c1_pads));
++}
++
++static struct imxi2c_platform_data vmx_i2c1_data = {
++ .init = vmx_i2c1_init,
++ .exit = vmx_i2c1_exit,
++ .bitrate = 100000,
++};
++
++static struct at24_platform_data vmx_eeprom = {
++ .byte_len = SZ_512K / 8,
++ .page_size = 128,
++ .flags = AT24_FLAG_ADDR16,
++};
++
++#define RADIO_SI4705_IRQ (GPIO_PORTC | 16)
++
++static struct i2c_board_info vmx_i2c1_boardinfo[] __initdata = {
++ {
++ I2C_BOARD_INFO("sgtl5000-i2c", 0x0a),
++ },
++ {
++ I2C_BOARD_INFO("radio-si4705", 0x63),
++ .irq = gpio_to_irq(RADIO_SI4705_IRQ),
++ },
++ {
++ I2C_BOARD_INFO("24c512", 0x56),
++ .platform_data = &vmx_eeprom,
++ },
++ {
++ I2C_BOARD_INFO("rtc-ds1307", 0x68),
++ .type = "ds1339",
++ },
++};
++#endif /* CONFIG_I2C */
++
++#if defined(CONFIG_CAN_FLEXCAN) || defined(CONFIG_CAN_FLEXCAN_MODULE)
++static struct pad_desc vmx_can2_pads[] = {
++ MX25_PAD_GPIO_C__CAN2_TX,
++ MX25_PAD_GPIO_D__CAN2_RX,
++};
++
++static int vmx_can2_init(struct device *dev)
++{
++ return mxc_iomux_v3_setup_multiple_pads(vmx_can2_pads,
++ ARRAY_SIZE(vmx_can2_pads));
++}
++
++static void vmx_can2_exit(struct device *dev)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx_can2_pads,
++ ARRAY_SIZE(vmx_can2_pads));
++}
++#endif // CONFIG_CAN_FLEXCAN
++
++#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
++#define CAN_MCP251X_IRQ (GPIO_PORTB | 6)
++//#define CAN_MCP251X_RESET TODO
++
++static struct pad_desc vmx_can_mcp251x_pads[] = {
++ MX25_PAD_A20__GPIO_2_6,
++};
++
++int mcp251x_setup(struct spi_device *spi)
++{
++ int ret;
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_can_mcp251x_pads,
++ ARRAY_SIZE(vmx_can_mcp251x_pads));
++ if (ret)
++ return ret;
++
++ ret = gpio_request(CAN_MCP251X_IRQ, "MCP251X CS");
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ CAN_MCP251X_IRQ);
++ mxc_iomux_v3_release_multiple_pads(vmx_can_mcp251x_pads,
++ ARRAY_SIZE(vmx_can_mcp251x_pads));
++ return ret;
++ }
++
++ gpio_direction_input(CAN_MCP251X_IRQ);
++ gpio_free(CAN_MCP251X_IRQ);
++
++ return ret;
++}
++
++static struct mcp251x_platform_data mcp251x_info = {
++ .oscillator_frequency = 16000000,
++ .model = CAN_MCP251X_MCP2515,
++ .board_specific_setup = &mcp251x_setup,
++ .power_enable = NULL,
++ .transceiver_enable = NULL,
++};
++#endif // CONFIG_CAN_MCP251X
++
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++#define TSC2046_PENDOWN (GPIO_PORTB | 7)
++
++static struct pad_desc vmx_touch_tsc2046_pads[] = {
++ MX25_PAD_A21__GPIO_2_7,
++};
++
++int tsc2046_setup(void)
++{
++ int ret;
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_touch_tsc2046_pads,
++ ARRAY_SIZE(vmx_touch_tsc2046_pads));
++ if (ret)
++ return ret;
++
++ ret = gpio_request(TSC2046_PENDOWN, "TSC2046 pendown");
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ TSC2046_PENDOWN);
++ mxc_iomux_v3_release_multiple_pads(vmx_touch_tsc2046_pads,
++ ARRAY_SIZE(vmx_touch_tsc2046_pads));
++ return ret;
++ }
++
++ gpio_direction_input(TSC2046_PENDOWN);
++
++ return ret;
++}
++
++static int ads7846_get_pendown_state(void)
++{
++ return !gpio_get_value(TSC2046_PENDOWN);
++}
++
++static struct ads7846_platform_data ads7846_config __initdata = {
++ .get_pendown_state = ads7846_get_pendown_state,
++ .keep_vref_on = 1,
++ .x_min = 270,
++ .y_min = 650,
++ .x_max = 3915,
++ .y_max = 3660,
++ .swap_xy = 1,
++};
++#endif // CONFIG_TOUCHSCREEN_ADS7846
++
++#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
++#define VMX_SPI_FLASH_CS_GPIO (GPIO_PORTB | 5)
++#define VMX_SPI_CAN_CS_GPIO (GPIO_PORTB | 10)
++#define VMX_SPI_TOUCH_CS_GPIO (GPIO_PORTB | 11)
++static struct pad_desc vmx_cspi1_pads[] = {
++ MX25_PAD_CSPI1_MOSI__CSPI1_MOSI,
++ MX25_PAD_CSPI1_MISO__CSPI1_MISO,
++ MX25_PAD_CSPI1_SS0__CSPI1_SS0,
++ MX25_PAD_CSPI1_SS1__CSPI1_SS1,
++ MX25_PAD_CSPI1_SCLK__CSPI1_SCLK,
++ MX25_PAD_CSPI1_RDY__CSPI1_RDY,
++#if defined(USE_SPI_GPIO_B5_CS)
++ MX25_PAD_A19__GPIO_2_5,
++#endif // USE_SPI_GPIO_B5_CS
++#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
++ MX25_PAD_A24__GPIO_2_10,
++#endif // CONFIG_CAN_MCP251X
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++ MX25_PAD_A25__GPIO_2_11,
++#endif // CONFIG_TOUCHSCREEN_ADS7846
++};
++
++static int vmx_spi_chipselect[] = {
++#if defined(USE_SPI_GPIO_B5_CS)
++ VMX_SPI_FLASH_CS_GPIO,
++#else
++ MXC_SPI_CS(0),
++#endif // USE_SPI_GPIO_B5_CS
++ MXC_SPI_CS(1),
++ VMX_SPI_CAN_CS_GPIO,
++ VMX_SPI_TOUCH_CS_GPIO,
++};
++
++static int vmx_cspi1_init(struct device *dev)
++{
++ int ret;
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_cspi1_pads,
++ ARRAY_SIZE(vmx_cspi1_pads));
++
++ if (ret)
++ return ret;
++
++#if defined(USE_SPI_GPIO_B5_CS)
++ ret = gpio_request(VMX_SPI_FLASH_CS_GPIO, "SPI FLASH CS");
++
++ if (ret == 0) {
++ gpio_direction_output(VMX_SPI_FLASH_CS_GPIO, 1);
++ /* Free the CS GPIO, to allow SPI driver to register it again */
++ gpio_free(VMX_SPI_FLASH_CS_GPIO);
++ } else {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ VMX_SPI_FLASH_CS_GPIO);
++ }
++#endif // USE_SPI_GPIO_B5_CS
++#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
++ ret = gpio_request(VMX_SPI_CAN_CS_GPIO, "MCP251X CS");
++
++ if (ret == 0) {
++ gpio_direction_output(VMX_SPI_CAN_CS_GPIO, 1);
++ /* Free the CS GPIO, to allow SPI driver to register it again */
++ gpio_free(VMX_SPI_CAN_CS_GPIO);
++ } else {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ VMX_SPI_CAN_CS_GPIO);
++ }
++
++#endif // CONFIG_CAN_MCP251X
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++ ret = gpio_request(VMX_SPI_TOUCH_CS_GPIO, "TSC2046 CS");
++
++ if (ret == 0) {
++ gpio_direction_output(VMX_SPI_TOUCH_CS_GPIO, 1);
++ /* Free the CS GPIO, to allow SPI driver to register it again */
++ gpio_free(VMX_SPI_TOUCH_CS_GPIO);
++ } else {
++ printk(KERN_INFO "%s: Failed to request GPIO %d\n", __FUNCTION__,
++ VMX_SPI_TOUCH_CS_GPIO);
++ }
++
++ tsc2046_setup();
++#endif
++
++ return 0;
++}
++
++static void vmx_cspi1_exit(struct device *dev)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx_cspi1_pads,
++ ARRAY_SIZE(vmx_cspi1_pads));
++}
++
++static struct spi_imx_master vmx_spi1_data = {
++ .chipselect = vmx_spi_chipselect,
++ .num_chipselect = ARRAY_SIZE(vmx_spi_chipselect),
++};
++
++#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
++#include <linux/mtd/partitions.h>
++#include <mtd/mtd-abi.h>
++#include <linux/spi/flash.h>
++static struct mtd_partition spi_flash_partitions[] = {
++ {
++ .name = "vmx_rom(spi)",
++ .size = 0x00040000,
++ .offset = 0,
++ .mask_flags = MTD_CAP_ROM
++ }, {
++ .name = "vmx_rwm(spi)",
++ .size = MTDPART_SIZ_FULL,
++ .offset = MTDPART_OFS_APPEND,
++ }
++};
++
++static struct flash_platform_data spi_flash_data = {
++ .name = "m25p80",
++ .parts = spi_flash_partitions,
++ .nr_parts = ARRAY_SIZE(spi_flash_partitions),
++ .type = "sst25vf016b"
++};
++#endif // CONFIG_MTD_M25P80
++
++static struct spi_board_info vmx_spi_info[] __initdata = {
++#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE)
++ {
++ /* the modalias must be the same as spi device driver name */
++ .modalias = "m25p80", /* Name of spi_driver for this device */
++ .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
++ .bus_num = 0, /* Framework bus number */
++ .chip_select = 0, /* On vmx it's SPI0_SS0 */
++ .platform_data = &spi_flash_data,
++ .mode = SPI_MODE_3,
++ },
++#endif // CONFIG_MTD_M25P80
++#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 2000000,
++ .bus_num = 0,
++ .chip_select = 1,
++ },
++#endif // CONFIG_SPI_SPIDEV
++#if defined(CONFIG_CAN_MCP251X) || defined(CONFIG_CAN_MCP251X_MODULE)
++ {
++ .modalias = "mcp251x",
++ .irq = gpio_to_irq(CAN_MCP251X_IRQ),
++ .max_speed_hz = 2000000,
++ .chip_select = 2,
++ .platform_data = &mcp251x_info,
++ .mode = SPI_MODE_0,
++ },
++#endif // CONFIG_CAN_MCP251X
++#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
++ {
++ .modalias = "ads7846",
++ .irq = gpio_to_irq(TSC2046_PENDOWN),
++ .max_speed_hz = 1500000,
++ .chip_select = 3,
++ .platform_data = &ads7846_config,
++ .mode = SPI_MODE_2,
++ },
++#endif // CONFIG_TOUCHSCREEN_ADS7846
++};
++#endif // CONFIG_SPI_IMX
++
++#if defined(CONFIG_KEYBOARD_IMX) || defined(CONFIG_KEYBOARD_IMX_MODULE)
++/*
++ * This array is used for mapping keypad scancodes to keyboard keycodes.
++ */
++static const uint32_t vmx25_kpd_keycodes[] = {
++ /* specify your keymap with KEY(row, col, keycode), */
++// KEY(0, 0, KEY_POWER),
++ KEY(0, 1, KEY_HOME),
++ KEY(0, 3, KEY_BACK),
++ KEY(2, 1, KEY_MENU),
++ KEY(2, 3, KEY_ZOOM),
++};
++
++static struct matrix_keymap_data vmx25_keypad_data = {
++ .keymap = vmx25_kpd_keycodes,
++ .keymap_size = ARRAY_SIZE(vmx25_kpd_keycodes),
++};
++
++static struct pad_desc vmx25_keypad_pads[] __initdata = {
++ MX25_PAD_KPP_ROW0__KPP_ROW0,
++ MX25_PAD_KPP_ROW1__KPP_ROW1,
++ MX25_PAD_KPP_ROW2__KPP_ROW2,
++ MX25_PAD_KPP_ROW3__KPP_ROW3,
++
++ MX25_PAD_KPP_COL0__KPP_COL0,
++ MX25_PAD_KPP_COL1__KPP_COL1,
++ MX25_PAD_KPP_COL2__KPP_COL2,
++ MX25_PAD_KPP_COL3__KPP_COL3,
++};
++
++static int vmx25_keypad_init(struct device *dev)
++{
++ return mxc_iomux_v3_setup_multiple_pads(vmx25_keypad_pads,
++ ARRAY_SIZE(vmx25_keypad_pads));
++}
++
++static void vmx25_keypad_exit(struct device *dev)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx25_keypad_pads,
++ ARRAY_SIZE(vmx25_keypad_pads));
++}
++#endif // CONFIG_KEYBOARD_IMX
++
++#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
++#define VMX_GPIO_LED0 (GPIO_PORTB | 4)
++#define VMX_GPIO_LED1 (GPIO_PORTB | 5)
++
++static struct pad_desc vmx_led_pads[] = {
++ MX25_PAD_A18__GPIO_2_4,
++ MX25_PAD_A19__GPIO_2_5,
++};
++
++static struct gpio_led vmx_leds[] = {
++ {
++ .name = "red",
++ .default_trigger = "heartbeat",
++ .gpio = VMX_GPIO_LED0,
++ },
++ {
++ .name = "orange",
++ .default_trigger = "none",
++ .gpio = VMX_GPIO_LED1,
++ }
++};
++
++static struct gpio_led_platform_data vmx_led_data = {
++ .leds = vmx_leds,
++ .num_leds = ARRAY_SIZE(vmx_leds),
++};
++
++static struct platform_device vmx_led_device = {
++ .name = "leds-gpio",
++ .id = -1,
++ .dev = {
++ .platform_data = &vmx_led_data,
++ },
++};
++
++static int __init vmx_led_init(void)
++{
++ int ret;
++
++ ret = mxc_iomux_v3_setup_multiple_pads(vmx_led_pads,
++ ARRAY_SIZE(vmx_led_pads));
++ if (ret)
++ printk(KERN_INFO "%s: Failed to setup PADS for LED: %d\n",
++ __FUNCTION__, ret);
++
++ ret = gpio_request(VMX_GPIO_LED0, "LED0");
++ if (ret)
++ printk(KERN_INFO "%s: Failed to request GPIO%d_%d for LED: %d\n",
++ __FUNCTION__, VMX_GPIO_LED0 / 32,
++ VMX_GPIO_LED0 % 32, ret);
++
++ ret = gpio_request(VMX_GPIO_LED1, "LED1");
++ if (ret)
++ printk(KERN_INFO "%s: Failed to request GPIO%d_%d for LED: %d\n",
++ __FUNCTION__, VMX_GPIO_LED1 / 32,
++ VMX_GPIO_LED1 % 32, ret);
++
++
++ gpio_direction_output(VMX_GPIO_LED0, 0);
++ gpio_direction_output(VMX_GPIO_LED1, 0);
++
++ /* free the GPIO, so that the LED driver can grab it */
++ gpio_free(VMX_GPIO_LED0);
++ gpio_free(VMX_GPIO_LED1);
++
++ return ret;
++}
++arch_initcall(vmx_led_init);
++#endif
++
++#if defined(CONFIG_SND_IMX_SOC) || defined(CONFIG_SND_IMX_SOC_MODULE)
++struct imx_ssi_platform_data vmx_ssi_pdata = {
++ .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE,
++};
++#endif // CONFIG_SND_IMX_SOC
++
++#if defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) || defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000_MODULE)
++static struct pad_desc vmx_aud4_pads[] = {
++ MX25_PAD_EB0__AUD4_TXD,
++ MX25_PAD_EB1__AUD4_RXD,
++ MX25_PAD_RW__AUD4_TXFS,
++ MX25_PAD_OE__AUD4_TXC,
++};
++
++/*!
++ * This function activates DAM port 4 to enable
++ * audio I/O.
++ */
++static int sgtl5000_plat_init(void)
++{
++ return mxc_iomux_v3_setup_multiple_pads(vmx_aud4_pads,
++ ARRAY_SIZE(vmx_aud4_pads));
++}
++
++/*!
++ * This function inactivates DAM port 4 for
++ * audio I/O
++ */
++static int sgtl5000_plat_exit(void)
++{
++ mxc_iomux_v3_release_multiple_pads(vmx_aud4_pads,
++ ARRAY_SIZE(vmx_aud4_pads));
++ return 0;
++}
++
++static struct mxc_audio_platform_data stk5_sgtl5000_data = {
++ .ssi_num = 0, // MASU fixme
++ .src_port = 1,
++ .ext_port = 4,
++ .init = sgtl5000_plat_init, /* board specific init */
++ .finit = sgtl5000_plat_exit, /* board specific finit */
++ .hp_irq = 0,
++ .hp_status = NULL,
++ .amp_enable = NULL,
++ .sysclk = 12288000,
++};
++
++static struct platform_device vmx_sgtl5000_device = {
++ .name = "imx-3stack-sgtl5000",
++ .dev = {
++ .platform_data = &stk5_sgtl5000_data,
++ },
++};
++#endif // CONFIG_SND_SOC_IMX_3STACK_SGTL5000
++
++#if defined(CONFIG_RADIO_SI4705) || defined(CONFIG_RADIO_SI4705_MODULE)
++static struct pad_desc vmx_radio_pads[] = {
++ MX25_PAD_VSTBY_ACK__GPIO_3_18, /* RESET_OUT_3V3 */
++ MX25_PAD_UPLL_BYPCLK__GPIO_3_16, /* SSI2_INT */
++};
++
++#define RADIO_GPIO82 (GPIO_PORTC | 18) // Reset
++#define RADIO_GPIO80 RADIO_SI4705_IRQ // IRQ
++
++static int radio_si4705_reset(void) {
++ int err = 0;
++
++ err |= mxc_iomux_v3_setup_multiple_pads(vmx_radio_pads,
++ ARRAY_SIZE(vmx_radio_pads));
++
++ err |= gpio_request(RADIO_GPIO82, "GPIO82");
++ err |= gpio_request(RADIO_GPIO80, "GPIO80");
++ if (err) {
++ return err;
++ }
++
++ gpio_direction_output(RADIO_GPIO82, 0);
++ gpio_direction_output(RADIO_GPIO80, 0);
++
++ gpio_set_value(RADIO_GPIO82, 0);
++ gpio_set_value(RADIO_GPIO80, 0);
++
++ err = 0; // FIXME active delay
++ while (--err) ;
++
++ gpio_set_value(RADIO_GPIO82, 1);
++ gpio_direction_input(RADIO_GPIO80);
++
++ gpio_free(RADIO_GPIO80);
++
++ return 0;
++}
++#endif // CONFIG_RADIO_SI4705
++
++#if defined(CONFIG_FB_IMX) || defined(CONFIG_FB_IMX_MODULE)
++#define VMX_LCD_BACKLIGHT_GPIO (GPIO_PORTA | 26)
++//#define VMX_LCD_RESET_GPIO (GPIO_PORTB | 4)
++//#define VMX_LCD_POWER_GPIO (GPIO_PORTB | 5)
++
++/*
++ * Setup GPIO for LCDC device to be active
++ *
++ */
++static struct pad_desc mx25_lcdc_gpios[] = {
++#ifdef VMX_LCD_BACKLIGHT_GPIO
++// MX25_PAD_A18__GPIO_2_4, /* LCD Reset (active LOW) */
++#if !defined(CONFIG_MXC_PWM) && !defined(CONFIG_MXC_PWM_MODULE)
++ MX25_PAD_PWM__GPIO_1_26, /* LCD Backlight brightness 0: full 1: off */
++#endif
++// MX25_PAD_A19__GPIO_2_5, /* LCD Power Enable 0: off 1: on */
++#endif
++ MX25_PAD_LSCLK__LSCLK,
++ MX25_PAD_LD0__LD0,
++ MX25_PAD_LD1__LD1,
++ MX25_PAD_LD2__LD2,
++ MX25_PAD_LD3__LD3,
++ MX25_PAD_LD4__LD4,
++ MX25_PAD_LD5__LD5,
++ MX25_PAD_LD6__LD6,
++ MX25_PAD_LD7__LD7,
++ MX25_PAD_LD8__LD8,
++ MX25_PAD_LD9__LD9,
++ MX25_PAD_LD10__LD10,
++ MX25_PAD_LD11__LD11,
++ MX25_PAD_LD12__LD12,
++ MX25_PAD_LD13__LD13,
++ MX25_PAD_LD14__LD14,
++ MX25_PAD_LD15__LD15,
++ MX25_PAD_D15__LD16,
++ MX25_PAD_D14__LD17,
++ MX25_PAD_HSYNC__HSYNC,
++ MX25_PAD_VSYNC__VSYNC,
++ MX25_PAD_OE_ACD__OE_ACD,
++};
++
++static int vmx_gpio_lcdc_active(struct platform_device *dev)
++{
++ int ret;
++
++ printk(KERN_INFO "%s: Setting up GPIO pins for LCD\n", __FUNCTION__);
++ ret = mxc_iomux_v3_setup_multiple_pads(mx25_lcdc_gpios,
++ ARRAY_SIZE(mx25_lcdc_gpios));
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to setup GPIO pins for LCD: %d\n",
++ __FUNCTION__, ret);
++ return ret;
++ }
++#ifdef VMX_LCD_BACKLIGHT_GPIO
++// ret = gpio_request(VMX_LCD_POWER_GPIO, "LCD POWER");
++// if (ret) {
++// printk(KERN_INFO "%s: Failed to request GPIO for LCD POWER: %d\n",
++// __FUNCTION__, ret);
++// goto release_pins;
++// }
++#if !defined(CONFIG_MXC_PWM) && !defined(CONFIG_MXC_PWM_MODULE)
++ ret = gpio_request(VMX_LCD_BACKLIGHT_GPIO, "LCD Backlight");
++ if (ret) {
++ printk(KERN_INFO "%s: Failed to request GPIO for backlight control: %d\n",
++ __FUNCTION__, ret);
++ goto free_gpio1;
++ }
++#endif
++// ret = gpio_request(VMX_LCD_RESET_GPIO, "LCD RESET");
++// if (ret) {
++// printk(KERN_INFO "%s: Failed to request GPIO for LCD RESET: %d\n",
++// __FUNCTION__, ret);
++// goto free_gpio2;
++// }
++
++// gpio_direction_output(VMX_LCD_POWER_GPIO, 1);
++#if !defined(CONFIG_MXC_PWM) && !defined(CONFIG_MXC_PWM_MODULE)
++ gpio_direction_output(VMX_LCD_BACKLIGHT_GPIO, 1);
++#endif
++// gpio_direction_output(VMX_LCD_RESET_GPIO, 0);
++#endif
++ return 0;
++
++//free_gpio2:
++#if !defined(CONFIG_MXC_PWM) && !defined(CONFIG_MXC_PWM_MODULE)
++ gpio_free(VMX_LCD_BACKLIGHT_GPIO);
++free_gpio1:
++#endif
++// gpio_free(VMX_LCD_POWER_GPIO);
++//release_pins:
++ mxc_iomux_v3_release_multiple_pads(mx25_lcdc_gpios,
++ ARRAY_SIZE(mx25_lcdc_gpios));
++ return ret;
++}
++
++/*
++ * Setup GPIO for LCDC device to be inactive
++ *
++ */
++static void vmx_gpio_lcdc_inactive(struct platform_device *dev)
++{
++ mxc_iomux_v3_release_multiple_pads(mx25_lcdc_gpios,
++ ARRAY_SIZE(mx25_lcdc_gpios));
++}
++
++#ifdef VMX_LCD_BACKLIGHT_GPIO
++#if !defined(CONFIG_MXC_PWM) && !defined(CONFIG_MXC_PWM_MODULE)
++static void vmx_lcdc_backlight(int on)
++{
++ printk(KERN_INFO "%s: Switching LCD backlight %s\n", __FUNCTION__, on ? "on" : "off");
++ if (on) {
++ gpio_set_value(VMX_LCD_BACKLIGHT_GPIO, 0);
++ } else {
++ gpio_set_value(VMX_LCD_BACKLIGHT_GPIO, 1);
++ }
++}
++#else
++#define vmx_lcdc_backlight NULL
++#endif
++
++static void vmx_lcdc_power(int on)
++{
++ printk(KERN_INFO "%s: Switching LCD reset %s\n", __FUNCTION__, on ? "off" : "on");
++// if (on) {
++// gpio_set_value(VMX_LCD_RESET_GPIO, 1);
++// } else {
++// gpio_set_value(VMX_LCD_RESET_GPIO, 0);
++// }
++}
++#else
++#define vmx_lcdc_backlight NULL
++#define vmx_lcdc_power NULL
++#endif
++
++static struct imx_fb_videomode vmx_fb_modes[] = {
++ {
++ .bpp = 16,
++ .mode = {
++ .name = "VGA-16@60",
++
++ .pixclock = KHZ2PICOS(24000),
++ .xres = 640,
++ .yres = 480,
++
++ .hsync_len = 44,
++ .left_margin = 66+8, /* Back porch */
++ .right_margin = 2, /* Front porch */
++
++ .vsync_len = 2,
++ .upper_margin = 25+8, /* Back porch */
++ .lower_margin = 2+8, /* Front porch */
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_BPIX_16 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++ },
++ {
++ .bpp = 32,
++ .mode = {
++ .name = "VGA-32@60",
++
++ .pixclock = KHZ2PICOS(24000),
++ .xres = 640,
++ .yres = 480,
++
++ .hsync_len = 44,
++ .left_margin = 66+8, /* Back porch */
++ .right_margin = 2, /* Front porch */
++
++ .vsync_len = 2,
++ .upper_margin = 25+8, /* Back porch */
++ .lower_margin = 2+8, /* Front porch */
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_BPIX_18 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL | PCR_END_SEL,
++ },
++ {
++ /* fH=30KHz HSYNC=1000px, fV=60Hz VSYNC=500lines, fCLK=30000*/
++ .bpp = 16,
++ .mode = {
++ .name = "WVGA-LCD",
++ .pixclock = KHZ2PICOS(30000),
++
++ .xres = 800,
++ .yres = 480,
++
++ .hsync_len = 64,
++ .left_margin = 120, /* Back porch */
++ .right_margin = 16, /* Front porch */
++
++ .vsync_len = 2,
++ .upper_margin = 16, /* Back porch */
++ .lower_margin = 2, /* Front porch */
++
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | PCR_BPIX_16 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL, // -PCR_CLKPOL, +PCR_OEPOL
++ },
++ {
++ .bpp = 16,
++ .mode = {
++ .name = "WVGA-16@60",
++ .pixclock = KHZ2PICOS(30000),
++
++ .xres = 800,
++ .yres = 480,
++
++ .hsync_len = 54,
++ .left_margin = 100, /* Back porch */
++ .right_margin = 16, /* Front porch */
++
++ .vsync_len = 4,
++ .upper_margin = 28, /* Back porch */
++ .lower_margin = 4, /* Front porch */
++
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | PCR_BPIX_16 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++ },
++ {
++ .bpp = 32,
++ .mode = {
++ .name = "WVGA-32@60",
++ .pixclock = KHZ2PICOS(30000),
++
++ .xres = 800,
++ .yres = 480,
++
++ .hsync_len = 54,
++ .left_margin = 100, /* Back porch */
++ .right_margin = 16, /* Front porch */
++
++ .vsync_len = 4,
++ .upper_margin = 28, /* Back porch */
++ .lower_margin = 4, /* Front porch */
++
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | PCR_BPIX_18 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL | PCR_END_SEL,
++
++ },
++ {
++ .bpp = 16,
++ .mode = {
++ .name = "SVGA-16@60",
++ .pixclock = KHZ2PICOS(40000),
++
++ .xres = 800,
++ .yres = 600,
++
++ .hsync_len = 64,
++ .left_margin = 170, /* Back porch */
++ .right_margin = 24, /* Front porch */
++
++ .vsync_len = 5,
++ .upper_margin = 23, /* Back porch */
++ .lower_margin = 2, /* Front porch */
++
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | PCR_BPIX_16 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++ },
++ {
++ .bpp = 32,
++ .mode = {
++ .name = "SVGA-32@60",
++ .pixclock = KHZ2PICOS(40000),
++
++ .xres = 800,
++ .yres = 600,
++
++ .hsync_len = 64,
++ .left_margin = 170, /* Back porch */
++ .right_margin = 24, /* Front porch */
++
++ .vsync_len = 5,
++ .upper_margin = 23, /* Back porch */
++ .lower_margin = 2, /* Front porch */
++
++ },
++
++ .pcr = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 | PCR_BPIX_18 |
++ PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL | PCR_END_SEL,
++
++ },
++};
++
++static struct imx_fb_platform_data vmx_fb_data = {
++ .init = vmx_gpio_lcdc_active,
++ .exit = vmx_gpio_lcdc_inactive,
++ .lcd_power = vmx_lcdc_power,
++ .backlight_power = vmx_lcdc_backlight,
++
++ .mode = vmx_fb_modes,
++ .num_modes = ARRAY_SIZE(vmx_fb_modes),
++
++ .dmacr = 0x00040060,
++
++ .cmap_greyscale = 0,
++ .cmap_inverse = 0,
++ .cmap_static = 0,
++
++ .fixed_screen_cpu = NULL,
++};
++#endif
++
++#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
++static struct pad_desc vmx_pwm_pads[] = {
++ MX25_PAD_PWM__PWM,
++};
++
++static int vmx_backlight_init(struct device *dev)
++{
++ int ret;
++ ret = mxc_iomux_v3_setup_pad(&vmx_pwm_pads[0]);
++ return ret;
++}
++
++static int vmx_backlight_notify(struct device *dev, int brightness)
++{
++ printk(KERN_INFO "%s: brightness=%d\n", __FUNCTION__, brightness);
++ return brightness;
++}
++
++static void vmx_backlight_exit(struct device *dev)
++{
++ mxc_iomux_v3_release_pad(&vmx_pwm_pads[0]);
++}
++
++static struct platform_pwm_backlight_data vmx_backlight_data = {
++ .pwm_id = 0,
++ .max_brightness = 100,
++ .dft_brightness = 50,
++ .pwm_period_ns = KHZ2PICOS(20000), /* kHz -> ps is the same as Hz -> ns */
++ .init = vmx_backlight_init,
++ .notify = vmx_backlight_notify,
++ .exit = vmx_backlight_exit,
++};
++
++static struct platform_device vmx_backlight_pwm_device = {
++ .name = "pwm-backlight",
++ .dev = {
++ .platform_data = &vmx_backlight_data,
++ },
++};
++#endif /* CONFIG_BACKLIGHT_PWM || CONFIG_BACKLIGHT_PWM_MODULE */
++
++#if defined(CONFIG_MMC_SDHCI_MXC) || defined(CONFIG_MMC_SDHCI_MXC_MODULE)
++#define SDHC1_CD_GPIO (GPIO_PORTD | 4)
++#define SDHC1_SEL_SLOT (GPIO_PORTD | 10)
++
++/*
++ * Resource definition for the SDHC1
++ */
++static struct resource vmx_sdhc1_resources[] = {
++ {
++ .start = MMC_SDHC1_BASE_ADDR,
++ .end = MMC_SDHC1_BASE_ADDR + SZ_4K - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = MXC_INT_SDHC1,
++ .end = MXC_INT_SDHC1,
++ .flags = IORESOURCE_IRQ,
++ }, {
++ .start = gpio_to_irq(SDHC1_CD_GPIO),
++ .end = gpio_to_irq(SDHC1_CD_GPIO),
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static inline int vmx_esdhci_get_irq(int id)
++{
++ int irq;
++
++ switch (id) {
++ case 0:
++ irq = vmx_sdhc1_resources[2].start;
++ break;
++ default:
++ BUG();
++ }
++ return irq;
++}
++
++static const char *vmx_esdhci_irqdesc[] = {
++ "ESDHCI card 0 detect",
++};
++
++static struct pad_desc vmx_sdhc_pads[] = {
++ MX25_PAD_SD1_CMD__SD1_CMD,
++ MX25_PAD_SD1_CLK__SD1_CLK,
++ MX25_PAD_SD1_DATA0__SD1_DATA0,
++ MX25_PAD_SD1_DATA2__SD1_DATA2,
++ MX25_PAD_SD1_DATA3__SD1_DATA3,
++ /* card detect GPIO */
++ MX25_PAD_BCLK__GPIO_4_4,
++ /* SD CLK switch GPIO */
++ MX25_PAD_D10__GPIO_4_10,
++};
++
++static int vmx_esdhci_status(struct device *dev)
++{
++ return !!gpio_get_value(SDHC1_CD_GPIO);
++}
++
++static int vmx_esdhci_init(struct device *dev, irqreturn_t (*esdhci_detect_irq)(int, void *),
++ void *data)
++{
++ int err;
++ struct mmc_host *host = data;
++ int id = to_platform_device(dev)->id;
++ int irq = vmx_esdhci_get_irq(id);
++
++ err = mxc_iomux_v3_setup_multiple_pads(vmx_sdhc_pads,
++ ARRAY_SIZE(vmx_sdhc_pads));
++ if (err) {
++ return err;
++ }
++
++ err = gpio_request(SDHC1_SEL_SLOT, "SD card slot select");
++// if (err) {
++// return err;
++// }
++ gpio_direction_output(SDHC1_SEL_SLOT, 0);
++
++#if defined(CONFIG_VMX_SD_ON_MODULE)
++ gpio_set_value(SDHC1_SEL_SLOT, 1);
++#elif defined(CONFIG_VMX_SD_ON_BOARD)
++ gpio_set_value(SDHC1_SEL_SLOT, 0);
++#else
++#error "Choice active SD slot internal/external"
++#endif
++
++ host->caps |= MMC_CAP_4_BIT_DATA;
++
++ printk(KERN_INFO "%s: Requesting IRQ %d\n", __FUNCTION__, irq);
++ err = request_irq(irq, esdhci_detect_irq,
++ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
++ vmx_esdhci_irqdesc[id], data);
++ if (err) {
++ dev_err(dev, "Error %d requesting ESDHCI card detect IRQ %d\n",
++ err, irq);
++ return err;
++ }
++ device_set_wakeup_capable(dev, 1);
++
++ return 0;
++}
++
++static void vmx_esdhci_exit(struct device *dev, void *data)
++{
++ int id = to_platform_device(dev)->id;
++ int irq = vmx_esdhci_get_irq(id);
++
++ printk(KERN_INFO "%s: Freeing IRQ %d\n", __FUNCTION__, irq);
++ free_irq(irq, data);
++ gpio_free(SDHC1_SEL_SLOT);
++ mxc_iomux_v3_release_multiple_pads(vmx_sdhc_pads,
++ ARRAY_SIZE(vmx_sdhc_pads));
++}
++
++static int vmx_esdhci_suspend(struct device *dev)
++{
++ int id = to_platform_device(dev)->id;
++ int irq = vmx_esdhci_get_irq(id);
++
++ if (device_may_wakeup(dev)) {
++ printk(KERN_INFO "%s: Enabling IRQ %d wakeup\n", __FUNCTION__, irq);
++ return enable_irq_wake(irq);
++ }
++ return 0;
++}
++
++static int vmx_esdhci_resume(struct device *dev)
++{
++ int id = to_platform_device(dev)->id;
++ int irq = vmx_esdhci_get_irq(id);
++
++ if (device_may_wakeup(dev)) {
++ printk(KERN_INFO "%s: Disabling IRQ %d wakeup\n", __FUNCTION__, irq);
++ return disable_irq_wake(irq);
++ }
++ return 0;
++}
++
++static struct mxc_sdhci_platform_data vmx_sdhc1_data = {
++ .ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34,
++ .init = vmx_esdhci_init,
++ .exit = vmx_esdhci_exit,
++ .suspend = vmx_esdhci_suspend,
++ .resume = vmx_esdhci_resume,
++ .status = vmx_esdhci_status,
++ .min_clk = 150000,
++ .max_clk = 25000000,
++ .detect_delay = 100,
++#if defined(CONFIG_VMX_SD_ON_MODULE)
++ .force_sd_detect=1
++#else
++ .force_sd_detect=0
++#endif
++};
++
++static struct platform_device vmx_sdhc1_device = {
++ .name = "sdhci",
++ .id = 0,
++ .dev = {
++ .coherent_dma_mask = DMA_BIT_MASK(32),
++ .platform_data = &vmx_sdhc1_data,
++ },
++ .num_resources = ARRAY_SIZE(vmx_sdhc1_resources),
++ .resource = vmx_sdhc1_resources,
++};
++#endif
++
++static struct platform_dev_list {
++ struct platform_device *pdev;
++ void *pdata;
++} vmx_devices[] __initdata = {
++#if defined(CONFIG_FB_IMX) || defined(CONFIG_FB_IMX_MODULE)
++ { .pdev = &mx25_fb_device, .pdata = &vmx_fb_data, },
++#endif
++#if defined(CONFIG_MXC_PWM) || defined(CONFIG_MXC_PWM_MODULE)
++ { .pdev = &mxc_pwm_device0, },
++#endif
++#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
++ { .pdev = &vmx_backlight_pwm_device, .pdata = &vmx_backlight_data, },
++#endif
++#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
++ { .pdev = &vmx_led_device, },
++#endif
++#if defined(CONFIG_MMC_SDHCI_MXC) || defined(CONFIG_MMC_SDHCI_MXC_MODULE)
++ { .pdev = &vmx_sdhc1_device, },
++#endif
++#if defined(CONFIG_SND_IMX_SOC) || defined(CONFIG_SND_IMX_SOC_MODULE)
++ { .pdev = &imx_ssi_device0, .pdata = &vmx_ssi_pdata, },
++#endif
++#if defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) || defined(CONFIG_SND_SOC_IMX_3STACK_SGTL5000_MODULE)
++ { .pdev = &vmx_sgtl5000_device, },
++#endif
++};
++#define VMX_NUM_DEVICES ARRAY_SIZE(vmx_devices)
++
++static __init int vmx_board_init(void)
++{
++ int ret;
++ int i;
++
++ /* Do UART init */
++#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
++#if UART1_ENABLED
++ imx25_add_imx_uart0(&vmx_uart_pdata[0]);
++#endif
++#if UART2_ENABLED
++ imx25_add_imx_uart1(&vmx_uart_pdata[1]);
++#endif
++#if UART3_ENABLED
++ imx25_add_imx_uart2(&vmx_uart_pdata[2]);
++#endif
++#if UART4_ENABLED
++ imx25_add_imx_uart3(&vmx_uart_pdata[3]);
++#endif
++#if UART5_ENABLED
++ imx25_add_imx_uart4(&vmx_uart_pdata[4]);
++#endif
++#endif // CONFIG_SERIAL_IMX
++
++
++ // Do USB init
++#if defined(CONFIG_USB_EHCI_MXC) || defined(CONFIG_USB_EHCI_MXC_MODULE)
++ if (otg_mode_host) { // HOST
++ mxc_register_device(&mxc_otg, &vmx_usbotg_pdata);
++ } else { // OTG
++ #if defined(CONFIG_USB_FSL_USB2) || defined(CONFIG_USB_FSL_USB2_MODULE)
++ mxc_register_device(&otg_udc_device, &vmx_usb_pdata);
++ #endif // CONFIG_USB_FSL_USB2
++ }
++
++ mxc_register_device(&mxc_usbh2, &vmx_usbh2_pdata);
++#endif // CONFIG_USB_EHCI_MXC
++
++
++ // Do I2C init
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++ imx25_add_imx_i2c0(&vmx_i2c1_data);
++ ret = i2c_register_board_info(0, vmx_i2c1_boardinfo,
++ ARRAY_SIZE(vmx_i2c1_boardinfo));
++ if (ret)
++ printk(KERN_ERR "Failed to register I2C board info: %d\n", ret);
++#endif // CONFIG_I2C
++
++ // Do SPI init
++#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
++ ret = vmx_cspi1_init(NULL);
++ if (ret) {
++ printk(KERN_ERR "Failed to configure CSPI1 pads\n");
++ } else {
++ imx25_add_spi_imx0(&vmx_spi1_data);
++ ret = spi_register_board_info(vmx_spi_info,
++ ARRAY_SIZE(vmx_spi_info));
++ if (ret) {
++ printk(KERN_ERR "Failed to register SPI board info: %d\n", ret);
++ } else {
++// vmx_cspi1_exit(NULL);
++ }
++ }
++#endif // CONFIG_SPI_IMX
++
++
++ // Do CAN1 init
++#if defined(CONFIG_CAN_FLEXCAN) || defined(CONFIG_CAN_FLEXCAN_MODULE)
++ ret = vmx_can2_init(NULL);
++ if (ret) {
++ printk(KERN_ERR "Failed to configure FLEXCAN2 pads\n");
++// vmx_can2_exit(NULL);
++ } else {
++ imx25_add_flexcan1(NULL);
++ }
++#endif // CONFIG_CAN_FLEXCAN
++
++ // Do KEYPAD init
++#if defined(CONFIG_KEYBOARD_IMX) || defined(CONFIG_KEYBOARD_IMX_MODULE)
++ ret = vmx25_keypad_init(NULL);
++ if (ret) {
++ printk(KERN_ERR "Failed to configure Keypad pads\n");
++ } else {
++ ret = mxc_register_device(&mxc_keypad_device, &vmx25_keypad_data);
++ if (ret) {
++ printk(KERN_WARNING "%s: Failed to register platform_device: %s\n",
++ __FUNCTION__, mxc_keypad_device.name);
++ vmx25_keypad_exit(NULL);
++ }
++ }
++#endif // CONFIG_KEYBOARD_IMX
++
++ // Do audmux interconnection
++#if defined(CONFIG_SND_IMX_SOC) || defined(CONFIG_SND_IMX_SOC_MODULE)
++ /* SSI unit master I2S codec connected to SSI_AUD4*/
++ mxc_audmux_v2_configure_port(0, 0, 0); // reset the ports
++ mxc_audmux_v2_configure_port(3, 0, 0);
++ mxc_audmux_v2_configure_port(0,
++ MXC_AUDMUX_V2_PTCR_SYN |
++ MXC_AUDMUX_V2_PTCR_TFSDIR |
++ MXC_AUDMUX_V2_PTCR_TFSEL(3) |
++ MXC_AUDMUX_V2_PTCR_TCLKDIR |
++ MXC_AUDMUX_V2_PTCR_TCSEL(3),
++ MXC_AUDMUX_V2_PDCR_RXDSEL(3)
++ );
++ mxc_audmux_v2_configure_port(3,
++ MXC_AUDMUX_V2_PTCR_SYN,
++ MXC_AUDMUX_V2_PDCR_RXDSEL(0)
++ );
++#endif // CONFIG_SND_IMX_SOC
++
++#if defined(CONFIG_RADIO_SI4705) || defined(CONFIG_RADIO_SI4705_MODULE)
++ radio_si4705_reset();
++#endif // CONFIG_RADIO_SI4705
++
++ for (i = 0; i < VMX_NUM_DEVICES; i++) {
++ if (vmx_devices[i].pdev == NULL) continue;
++ printk(KERN_INFO "%s: Registering platform device[%d] @ %p dev %p: %s\n",
++ __FUNCTION__, i, vmx_devices[i].pdev, &vmx_devices[i].pdev->dev,
++ vmx_devices[i].pdev->name);
++ if (vmx_devices[i].pdata) {
++ ret = mxc_register_device(vmx_devices[i].pdev,
++ vmx_devices[i].pdata);
++ } else {
++ ret = platform_device_register(vmx_devices[i].pdev);
++ }
++ if (ret) {
++ printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n",
++ __FUNCTION__, i, vmx_devices[i].pdev->name, ret);
++ }
++ }
++ printk(KERN_INFO "%s: Done\n", __FUNCTION__);
++
++ return 0;
++}
++subsys_initcall(vmx_board_init);
+diff -urN linux.35.old/arch/arm/plat-mxc/audmux-v2.c linux.35.new/arch/arm/plat-mxc/audmux-v2.c
+--- linux.35.old/arch/arm/plat-mxc/audmux-v2.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/audmux-v2.c 2010-12-03 09:51:55.360347257 +0100
+@@ -13,10 +13,6 @@
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ #include <linux/module.h>
+@@ -191,6 +187,7 @@
+ {
+ int ret;
+
++#if defined(CONFIG_ARCH_MX3)
+ if (cpu_is_mx31())
+ audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
+
+@@ -204,7 +201,19 @@
+ }
+ audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR);
+ }
+-
++#endif
++#if defined(CONFIG_ARCH_MX25)
++ if (cpu_is_mx25()) {
++ audmux_clk = clk_get(NULL, "audmux");
++ if (IS_ERR(audmux_clk)) {
++ ret = PTR_ERR(audmux_clk);
++ printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
++ ret);
++ return ret;
++ }
++ audmux_base = MX25_IO_ADDRESS(MX25_AUDMUX_BASE_ADDR);
++ }
++#endif
+ audmux_debugfs_init();
+
+ return 0;
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/Kconfig linux.35.new/arch/arm/plat-mxc/devices/Kconfig
+--- linux.35.old/arch/arm/plat-mxc/devices/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/Kconfig 2010-12-03 09:51:55.360347257 +0100
+@@ -0,0 +1,15 @@
++config IMX_HAVE_PLATFORM_FLEXCAN
++ select HAVE_CAN_FLEXCAN
++ bool
++
++config IMX_HAVE_PLATFORM_IMX_I2C
++ bool
++
++config IMX_HAVE_PLATFORM_IMX_UART
++ bool
++
++config IMX_HAVE_PLATFORM_MXC_NAND
++ bool
++
++config IMX_HAVE_PLATFORM_SPI_IMX
++ bool
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/Makefile linux.35.new/arch/arm/plat-mxc/devices/Makefile
+--- linux.35.old/arch/arm/plat-mxc/devices/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/Makefile 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,8 @@
++ifdef CONFIG_CAN_FLEXCAN
++# the ifdef can be removed once the flexcan driver has been merged
++obj-$(CONFIG_IMX_HAVE_PLATFORM_FLEXCAN) += platform-flexcan.o
++endif
++obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_I2C) += platform-imx-i2c.o
++obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
++#obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_NAND) += platform-mxc_nand.o
++obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) += platform-spi_imx.o
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/platform-flexcan.c linux.35.new/arch/arm/plat-mxc/devices/platform-flexcan.c
+--- linux.35.old/arch/arm/plat-mxc/devices/platform-flexcan.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/platform-flexcan.c 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2010 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de>
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation.
++ */
++
++#include <mach/devices-common.h>
++
++struct platform_device *__init imx_add_flexcan(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irq,
++ const struct flexcan_platform_data *pdata)
++{
++ struct resource res[] = {
++ {
++ .start = iobase,
++ .end = iobase + iosize - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = irq,
++ .end = irq,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++
++ return imx_add_platform_device("flexcan", id, res, ARRAY_SIZE(res),
++ pdata, sizeof(*pdata));
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/platform-imx-i2c.c linux.35.new/arch/arm/plat-mxc/devices/platform-imx-i2c.c
+--- linux.35.old/arch/arm/plat-mxc/devices/platform-imx-i2c.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/platform-imx-i2c.c 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,29 @@
++/*
++ * Copyright (C) 2009-2010 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * 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 <mach/devices-common.h>
++
++struct platform_device *__init imx_add_imx_i2c(int id,
++ resource_size_t iobase, resource_size_t iosize, int irq,
++ const struct imxi2c_platform_data *pdata)
++{
++ struct resource res[] = {
++ {
++ .start = iobase,
++ .end = iobase + iosize - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = irq,
++ .end = irq,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++
++ return imx_add_platform_device("imx-i2c", id, res, ARRAY_SIZE(res),
++ pdata, sizeof(*pdata));
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/platform-imx-uart.c linux.35.new/arch/arm/plat-mxc/devices/platform-imx-uart.c
+--- linux.35.old/arch/arm/plat-mxc/devices/platform-imx-uart.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/platform-imx-uart.c 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) 2009-2010 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * 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 <mach/devices-common.h>
++
++struct platform_device *__init imx_add_imx_uart_3irq(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irqrx, resource_size_t irqtx,
++ resource_size_t irqrts,
++ const struct imxuart_platform_data *pdata)
++{
++ struct resource res[] = {
++ {
++ .start = iobase,
++ .end = iobase + iosize - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = irqrx,
++ .end = irqrx,
++ .flags = IORESOURCE_IRQ,
++ }, {
++ .start = irqtx,
++ .end = irqtx,
++ .flags = IORESOURCE_IRQ,
++ }, {
++ .start = irqrts,
++ .end = irqrx,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++
++ return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
++ pdata, sizeof(*pdata));
++}
++
++struct platform_device *__init imx_add_imx_uart_1irq(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irq,
++ const struct imxuart_platform_data *pdata)
++{
++ struct resource res[] = {
++ {
++ .start = iobase,
++ .end = iobase + iosize - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = irq,
++ .end = irq,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++
++ return imx_add_platform_device("imx-uart", id, res, ARRAY_SIZE(res),
++ pdata, sizeof(*pdata));
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/devices/platform-spi_imx.c linux.35.new/arch/arm/plat-mxc/devices/platform-spi_imx.c
+--- linux.35.old/arch/arm/plat-mxc/devices/platform-spi_imx.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/devices/platform-spi_imx.c 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2009-2010 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * 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 <asm/sizes.h>
++#include <mach/devices-common.h>
++
++struct platform_device *__init imx_add_spi_imx(int id,
++ resource_size_t iobase, resource_size_t iosize, int irq,
++ const struct spi_imx_master *pdata)
++{
++ struct resource res[] = {
++ {
++ .start = iobase,
++ .end = iobase + iosize - 1,
++ .flags = IORESOURCE_MEM,
++ }, {
++ .start = irq,
++ .end = irq,
++ .flags = IORESOURCE_IRQ,
++ },
++ };
++
++ return imx_add_platform_device("spi_imx", id, res, ARRAY_SIZE(res),
++ pdata, sizeof(*pdata));
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/devices.c linux.35.new/arch/arm/plat-mxc/devices.c
+--- linux.35.old/arch/arm/plat-mxc/devices.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/devices.c 2010-12-03 09:51:55.364349489 +0100
+@@ -18,6 +18,7 @@
+
+ #include <linux/kernel.h>
+ #include <linux/init.h>
++#include <linux/err.h>
+ #include <linux/platform_device.h>
+ #include <mach/common.h>
+
+@@ -35,3 +36,35 @@
+ return ret;
+ }
+
++struct platform_device *__init imx_add_platform_device(const char *name, int id,
++ const struct resource *res, unsigned int num_resources,
++ const void *data, size_t size_data)
++{
++ int ret = -ENOMEM;
++ struct platform_device *pdev;
++
++ pdev = platform_device_alloc(name, id);
++ if (!pdev)
++ goto err;
++
++ if (res) {
++ ret = platform_device_add_resources(pdev, res, num_resources);
++ if (ret)
++ goto err;
++ }
++
++ if (data) {
++ ret = platform_device_add_data(pdev, data, size_data);
++ if (ret)
++ goto err;
++ }
++
++ ret = platform_device_add(pdev);
++ if (ret) {
++err:
++ platform_device_put(pdev);
++ return ERR_PTR(ret);
++ }
++
++ return pdev;
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/ehci.c linux.35.new/arch/arm/plat-mxc/ehci.c
+--- linux.35.old/arch/arm/plat-mxc/ehci.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/ehci.c 2010-12-03 09:51:55.364349489 +0100
+@@ -11,10 +11,6 @@
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+ #include <linux/platform_device.h>
+@@ -25,6 +21,19 @@
+
+ #define USBCTRL_OTGBASE_OFFSET 0x600
+
++
++#define MX25_OTG_SIC_SHIFT 29
++#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT)
++#define MX25_OTG_PM_BIT (1 << 24)
++
++#define MX25_H1_SIC_SHIFT 21
++#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
++#define MX25_H1_PM_BIT (1 << 16)
++#define MX25_H1_IPPUE_UP_BIT (1 << 7)
++#define MX25_H1_IPPUE_DOWN_BIT (1 << 6)
++#define MX25_H1_TLL_BIT (1 << 5)
++#define MX25_H1_USBTE_BIT (1 << 4)
++
+ #define MX31_OTG_SIC_SHIFT 29
+ #define MX31_OTG_SIC_MASK (0x3 << MX31_OTG_SIC_SHIFT)
+ #define MX31_OTG_PM_BIT (1 << 24)
+@@ -73,7 +82,51 @@
+ int mxc_initialize_usb_hw(int port, unsigned int flags)
+ {
+ unsigned int v;
+-#ifdef CONFIG_ARCH_MX3
++#if defined(CONFIG_ARCH_MX25)
++ if (cpu_is_mx25()) {
++ v = readl(MX25_IO_ADDRESS(MX25_OTG_BASE_ADDR +
++ USBCTRL_OTGBASE_OFFSET));
++
++ switch (port) {
++ case 0: /* OTG port */
++ v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT);
++ v |= (flags & MXC_EHCI_INTERFACE_MASK)
++ << MX25_OTG_SIC_SHIFT;
++ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
++ v |= MX25_OTG_PM_BIT;
++
++ break;
++ case 1: /* H1 port */
++ v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_TLL_BIT |
++ MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT | MX25_H1_IPPUE_UP_BIT);
++ v |= (flags & MXC_EHCI_INTERFACE_MASK)
++ << MX35_H1_SIC_SHIFT;
++ if (!(flags & MXC_EHCI_POWER_PINS_ENABLED))
++ v |= MX25_H1_PM_BIT;
++
++ if (!(flags & MXC_EHCI_TTL_ENABLED))
++ v |= MX25_H1_TLL_BIT;
++
++ if (flags & MXC_EHCI_INTERNAL_PHY)
++ v |= MX25_H1_USBTE_BIT;
++
++ if (flags & MXC_EHCI_IPPUE_DOWN)
++ v |= MX25_H1_IPPUE_DOWN_BIT;
++
++ if (flags & MXC_EHCI_IPPUE_UP)
++ v |= MX25_H1_IPPUE_UP_BIT;
++
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ writel(v, MX25_IO_ADDRESS(MX25_OTG_BASE_ADDR +
++ USBCTRL_OTGBASE_OFFSET));
++ return 0;
++ }
++#endif /* CONFIG_ARCH_MX25 */
++#if defined(CONFIG_ARCH_MX3)
+ if (cpu_is_mx31()) {
+ v = readl(MX31_IO_ADDRESS(MX31_OTG_BASE_ADDR +
+ USBCTRL_OTGBASE_OFFSET));
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/board-vmx25.h linux.35.new/arch/arm/plat-mxc/include/mach/board-vmx25.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/board-vmx25.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/board-vmx25.h 2010-12-03 09:51:55.364349489 +0100
+@@ -0,0 +1,15 @@
++/*
++ * Copyright 2010 <support@voipac.com>
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __ASM_ARCH_MXC_BOARD_VMX25_H__
++#define __ASM_ARCH_MXC_BOARD_VMX25_H__
++
++#endif /* __ASM_ARCH_MXC_BOARD_VMX25_H__ */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/devices-common.h linux.35.new/arch/arm/plat-mxc/include/mach/devices-common.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/devices-common.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/devices-common.h 2010-12-03 09:51:55.368349274 +0100
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) 2009-2010 Pengutronix
++ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
++ *
++ * This program is free software; you can redistribute it and/or modify it under
++ * the terms of the GNU General Public License version 2 as published by the
++ * Free Software Foundation.
++ */
++#include <linux/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++
++struct platform_device *imx_add_platform_device(const char *name, int id,
++ const struct resource *res, unsigned int num_resources,
++ const void *data, size_t size_data);
++
++#if defined (CONFIG_CAN_FLEXCAN) || defined (CONFIG_CAN_FLEXCAN_MODULE)
++#include <linux/can/platform/flexcan.h>
++struct platform_device *__init imx_add_flexcan(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irq,
++ const struct flexcan_platform_data *pdata);
++#else
++/* the ifdef can be removed once the flexcan driver has been merged */
++struct flexcan_platform_data;
++static inline struct platform_device *__init imx_add_flexcan(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irq,
++ const struct flexcan_platform_data *pdata)
++{
++ return NULL;
++}
++#endif
++
++#include <mach/i2c.h>
++struct platform_device *__init imx_add_imx_i2c(int id,
++ resource_size_t iobase, resource_size_t iosize, int irq,
++ const struct imxi2c_platform_data *pdata);
++
++#include <mach/imx-uart.h>
++struct platform_device *__init imx_add_imx_uart_3irq(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irqrx, resource_size_t irqtx,
++ resource_size_t irqrts,
++ const struct imxuart_platform_data *pdata);
++struct platform_device *__init imx_add_imx_uart_1irq(int id,
++ resource_size_t iobase, resource_size_t iosize,
++ resource_size_t irq,
++ const struct imxuart_platform_data *pdata);
++
++#include <mach/mxc_nand.h>
++struct platform_device *__init imx_add_mxc_nand_v1(resource_size_t iobase,
++ int irq, const struct mxc_nand_platform_data *pdata);
++struct platform_device *__init imx_add_mxc_nand_v21(resource_size_t iobase,
++ int irq, const struct mxc_nand_platform_data *pdata);
++
++#include <mach/spi.h>
++struct platform_device *__init imx_add_spi_imx(int id,
++ resource_size_t iobase, resource_size_t iosize, int irq,
++ const struct spi_imx_master *pdata);
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/dma.h linux.35.new/arch/arm/plat-mxc/include/mach/dma.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/dma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/dma.h 2010-12-03 09:51:55.368349274 +0100
+@@ -0,0 +1,293 @@
++/*
++ * Copyright 2004-2009 Freescale Semiconductor, 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __ASM_ARCH_MXC_DMA_H__
++#define __ASM_ARCH_MXC_DMA_H__
++
++#define MXC_DMA_DYNAMIC_CHANNEL 255
++
++#define MXC_DMA_DONE 0x0
++#define MXC_DMA_REQUEST_TIMEOUT 0x1
++#define MXC_DMA_TRANSFER_ERROR 0x2
++
++/*! This defines the list of device ID's for DMA */
++typedef enum mxc_dma_device {
++ MXC_DMA_UART1_RX,
++ MXC_DMA_UART1_TX,
++ MXC_DMA_UART2_RX,
++ MXC_DMA_UART2_TX,
++ MXC_DMA_UART3_RX,
++ MXC_DMA_UART3_TX,
++ MXC_DMA_UART4_RX,
++ MXC_DMA_UART4_TX,
++ MXC_DMA_UART5_RX,
++ MXC_DMA_UART5_TX,
++ MXC_DMA_UART6_RX,
++ MXC_DMA_UART6_TX,
++ MXC_DMA_MMC1_WIDTH_1,
++ MXC_DMA_MMC1_WIDTH_4,
++ MXC_DMA_MMC2_WIDTH_1,
++ MXC_DMA_MMC2_WIDTH_4,
++ MXC_DMA_SSI1_8BIT_RX0,
++ MXC_DMA_SSI1_8BIT_TX0,
++ MXC_DMA_SSI1_16BIT_RX0,
++ MXC_DMA_SSI1_16BIT_TX0,
++ MXC_DMA_SSI1_24BIT_RX0,
++ MXC_DMA_SSI1_24BIT_TX0,
++ MXC_DMA_SSI1_8BIT_RX1,
++ MXC_DMA_SSI1_8BIT_TX1,
++ MXC_DMA_SSI1_16BIT_RX1,
++ MXC_DMA_SSI1_16BIT_TX1,
++ MXC_DMA_SSI1_24BIT_RX1,
++ MXC_DMA_SSI1_24BIT_TX1,
++ MXC_DMA_SSI2_8BIT_RX0,
++ MXC_DMA_SSI2_8BIT_TX0,
++ MXC_DMA_SSI2_16BIT_RX0,
++ MXC_DMA_SSI2_16BIT_TX0,
++ MXC_DMA_SSI2_24BIT_RX0,
++ MXC_DMA_SSI2_24BIT_TX0,
++ MXC_DMA_SSI2_8BIT_RX1,
++ MXC_DMA_SSI2_8BIT_TX1,
++ MXC_DMA_SSI2_16BIT_RX1,
++ MXC_DMA_SSI2_16BIT_TX1,
++ MXC_DMA_SSI2_24BIT_RX1,
++ MXC_DMA_SSI2_24BIT_TX1,
++ MXC_DMA_FIR_RX,
++ MXC_DMA_FIR_TX,
++ MXC_DMA_CSPI1_RX,
++ MXC_DMA_CSPI1_TX,
++ MXC_DMA_CSPI2_RX,
++ MXC_DMA_CSPI2_TX,
++ MXC_DMA_CSPI3_RX,
++ MXC_DMA_CSPI3_TX,
++ MXC_DMA_ATA_RX,
++ MXC_DMA_ATA_TX,
++ MXC_DMA_MEMORY,
++ MXC_DMA_FIFO_MEMORY,
++ MXC_DMA_DSP_PACKET_DATA0_RD,
++ MXC_DMA_DSP_PACKET_DATA0_WR,
++ MXC_DMA_DSP_PACKET_DATA1_RD,
++ MXC_DMA_DSP_PACKET_DATA1_WR,
++ MXC_DMA_DSP_LOG0_CHNL,
++ MXC_DMA_DSP_LOG1_CHNL,
++ MXC_DMA_DSP_LOG2_CHNL,
++ MXC_DMA_DSP_LOG3_CHNL,
++ MXC_DMA_CSI_RX,
++ MXC_DMA_SPDIF_16BIT_TX,
++ MXC_DMA_SPDIF_16BIT_RX,
++ MXC_DMA_SPDIF_32BIT_TX,
++ MXC_DMA_SPDIF_32BIT_RX,
++ MXC_DMA_ASRC_A_RX,
++ MXC_DMA_ASRC_A_TX,
++ MXC_DMA_ASRC_B_RX,
++ MXC_DMA_ASRC_B_TX,
++ MXC_DMA_ASRC_C_RX,
++ MXC_DMA_ASRC_C_TX,
++ MXC_DMA_ASRCA_ESAI,
++ MXC_DMA_ASRCB_ESAI,
++ MXC_DMA_ASRCC_ESAI,
++ MXC_DMA_ASRCA_SSI1_TX0,
++ MXC_DMA_ASRCA_SSI1_TX1,
++ MXC_DMA_ASRCA_SSI2_TX0,
++ MXC_DMA_ASRCA_SSI2_TX1,
++ MXC_DMA_ASRCB_SSI1_TX0,
++ MXC_DMA_ASRCB_SSI1_TX1,
++ MXC_DMA_ASRCB_SSI2_TX0,
++ MXC_DMA_ASRCB_SSI2_TX1,
++ MXC_DMA_ESAI_16BIT_RX,
++ MXC_DMA_ESAI_16BIT_TX,
++ MXC_DMA_ESAI_24BIT_RX,
++ MXC_DMA_ESAI_24BIT_TX,
++ MXC_DMA_TEST_RAM2D2RAM,
++ MXC_DMA_TEST_RAM2RAM2D,
++ MXC_DMA_TEST_RAM2D2RAM2D,
++ MXC_DMA_TEST_RAM2RAM,
++ MXC_DMA_TEST_HW_CHAINING,
++ MXC_DMA_TEST_SW_CHAINING
++} mxc_dma_device_t;
++
++/*! This defines the prototype of callback funtion registered by the drivers */
++typedef void (*mxc_dma_callback_t) (void *arg, int error_status,
++ unsigned int count);
++
++/*! This defines the type of DMA transfer requested */
++typedef enum mxc_dma_mode {
++ MXC_DMA_MODE_READ,
++ MXC_DMA_MODE_WRITE,
++} mxc_dma_mode_t;
++
++/*! This defines the DMA channel parameters */
++typedef struct mxc_dma_channel {
++ unsigned int active:1; /* When there has a active tranfer, it is set to 1 */
++ unsigned int lock; /* Defines the channel is allocated or not */
++ int curr_buf; /* Current buffer */
++ mxc_dma_mode_t mode; /* Read or Write */
++ unsigned int channel; /* Channel number */
++ unsigned int dynamic:1; /* Channel not statically allocated when 1 */
++ char *dev_name; /* Device name */
++ void *private; /* Private structure for platform */
++ mxc_dma_callback_t cb_fn; /*!< The callback function */
++ void *cb_args; /* The argument of callback function */
++} mxc_dma_channel_t;
++
++/*! This structure contains the information about a dma transfer */
++typedef struct mxc_dma_requestbuf {
++ dma_addr_t src_addr; /* source address */
++ dma_addr_t dst_addr; /* destination address */
++ int num_of_bytes; /* the length of this transfer : bytes */
++} mxc_dma_requestbuf_t;
++
++/*! This struct contains the information for asrc special*/
++struct dma_channel_asrc_info {
++ u32 channs; /* data channels in asrc */
++};
++
++/*! This struct contains the information for device special*/
++struct dma_channel_info {
++ struct dma_channel_asrc_info asrc; /* asrc special information */
++};
++
++#if defined(CONFIG_ARCH_MX27) || defined(CONFIG_ARCH_MX21)
++#include <mach/mx2_dma.h>
++#else
++#include <mach/sdma.h>
++#endif
++
++struct scatterlist;
++
++/*!
++ * This function is generally called by the driver at open time.
++ * The DMA driver would do any initialization steps that is required
++ * to get the channel ready for data transfer.
++ *
++ * @param channel_id a pre-defined id. The peripheral driver would specify
++ * the id associated with its peripheral. This would be
++ * used by the DMA driver to identify the peripheral
++ * requesting DMA and do the necessary setup on the
++ * channel associated with the particular peripheral.
++ * The DMA driver could use static or dynamic DMA channel
++ * allocation.
++ * @param dev_name module name or device name
++ * @param data the customized parameter for special channel.
++ * @return returns a negative number on error if request for a DMA channel did not
++ * succeed, returns the channel number to be used on success.
++ */
++extern int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name,
++ struct dma_channel_info *info);
++
++static inline int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name)
++{
++ return mxc_dma_request_ext(channel_id, dev_name, NULL);
++}
++
++/*!
++ * This function is generally called by the driver at close time. The DMA
++ * driver would do any cleanup associated with this channel.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++extern int mxc_dma_free(int channel_num);
++
++/*!
++ * This function would just configure the buffers specified by the user into
++ * dma channel. The caller must call mxc_dma_enable to start this transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param dma_buf an array of physical addresses to the user defined
++ * buffers. The caller must guarantee the dma_buf is
++ * available until the transfer is completed.
++ * @param num_buf number of buffers in the array
++ * @param mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer could not be
++ * added with DMA for transfer. On Success, it returns 0
++ */
++extern int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf,
++ int num_buf, mxc_dma_mode_t mode);
++
++/*!
++ * This function would just configure the scatterlist specified by the
++ * user into dma channel. This is a slight variation of mxc_dma_config(),
++ * it is provided for the convenience of drivers that have a scatterlist
++ * passed into them. It is the calling driver's responsibility to have the
++ * correct physical address filled in the "dma_address" field of the
++ * scatterlist.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param sg a scatterlist of buffers. The caller must guarantee
++ * the dma_buf is available until the transfer is
++ * completed.
++ * @param num_buf number of buffers in the array
++ * @param num_of_bytes total number of bytes to transfer. If set to 0, this
++ * would imply to use the length field of the scatterlist
++ * for each DMA transfer. Else it would calculate the size
++ * for each DMA transfer.
++ * @param mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer could not
++ * be added with DMA for transfer. On Success, it returns 0
++ */
++extern int mxc_dma_sg_config(int channel_num, struct scatterlist *sg,
++ int num_buf, int num_of_bytes,
++ mxc_dma_mode_t mode);
++
++/*!
++ * This function is provided if the driver would like to set/change its
++ * callback function.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param callback a callback function to provide notification on transfer
++ * completion, user could specify NULL if he does not wish
++ * to be notified
++ * @param arg an argument that gets passed in to the callback
++ * function, used by the user to do any driver specific
++ * operations.
++ * @return this function returns a negative number on error if the callback
++ * could not be set for the channel or 0 on success
++ */
++extern int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback,
++ void *arg);
++
++/*!
++ * This stops the DMA channel and any ongoing transfers. Subsequent use of
++ * mxc_dma_enable() will restart the channel and restart the transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++extern int mxc_dma_disable(int channel_num);
++
++/*!
++ * This starts DMA transfer. Or it restarts DMA on a stopped channel
++ * previously stopped with mxc_dma_disable().
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++extern int mxc_dma_enable(int channel_num);
++
++#endif
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/imxfb.h linux.35.new/arch/arm/plat-mxc/include/mach/imxfb.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/imxfb.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/imxfb.h 2010-12-03 09:51:55.368349274 +0100
+@@ -17,6 +17,7 @@
+ #define PCR_BPIX_12 (4 << 25)
+ #define PCR_BPIX_16 (5 << 25)
+ #define PCR_BPIX_18 (6 << 25)
++#define PCR_BPIX_24 (7 << 25)
+ #define PCR_PIXPOL (1 << 24)
+ #define PCR_FLMPOL (1 << 23)
+ #define PCR_LPPOL (1 << 22)
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/iomux-mx25.h linux.35.new/arch/arm/plat-mxc/include/mach/iomux-mx25.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/iomux-mx25.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/iomux-mx25.h 2010-12-03 09:51:55.368349274 +0100
+@@ -155,7 +155,7 @@
+
+ #define MX25_PAD_D10__D10 IOMUX_PAD(0x294, 0x09c, 0x00, 0, 0, NO_PAD_CTRL)
+ #define MX25_PAD_D10__GPIO_4_10 IOMUX_PAD(0x294, 0x09c, 0x05, 0, 0, NO_PAD_CTRL)
+-#define MX25_PAD_D10__USBOTG_OC IOMUX_PAD(0x294, 0x09c, 0x06, 0x57c, 0, PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_D10__USBOTG_OC IOMUX_PAD(0x294, 0x09c, 0x06, 0x57c, 0, PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_22K_UP)
+
+ #define MX25_PAD_D9__D9 IOMUX_PAD(0x298, 0x0a0, 0x00, 0, 0, NO_PAD_CTRL)
+ #define MX25_PAD_D9__GPIO_4_11 IOMUX_PAD(0x298, 0x0a0, 0x05, 0, 0, NO_PAD_CTRL)
+@@ -163,7 +163,7 @@
+
+ #define MX25_PAD_D8__D8 IOMUX_PAD(0x29c, 0x0a4, 0x00, 0, 0, NO_PAD_CTRL)
+ #define MX25_PAD_D8__GPIO_4_12 IOMUX_PAD(0x29c, 0x0a4, 0x05, 0, 0, NO_PAD_CTRL)
+-#define MX25_PAD_D8__USBH2_OC IOMUX_PAD(0x29c, 0x0a4, 0x06, 0x580, 0, PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_D8__USBH2_OC IOMUX_PAD(0x29c, 0x0a4, 0x06, 0x580, 0, PAD_CTL_HYS | PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_22K_UP)
+
+ #define MX25_PAD_D7__D7 IOMUX_PAD(0x2a0, 0x0a8, 0x00, 0, 0, NO_PAD_CTRL)
+ #define MX25_PAD_D7__GPIO_4_13 IOMUX_PAD(0x2a0, 0x0a8, 0x05, 0, 0, NO_PAD_CTRL)
+@@ -371,31 +371,31 @@
+ #define MX25_PAD_SD1_DATA3__FEC_CRS IOMUX_PAD(0x39c, 0x1a4, 0x10, 0x508, 2, NO_PAD_CTRL)
+ #define MX25_PAD_SD1_DATA3__GPIO_2_28 IOMUX_PAD(0x39c, 0x1a4, 0x15, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, PAD_CTL_PKE)
+-#define MX25_PAD_KPP_ROW0__GPIO_2_29 IOMUX_PAD(0x3a0, 0x1a8, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(0x3a0, 0x1a8, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_KPP_ROW0__GPIO_2_29 IOMUX_PAD(0x3a0, 0x1a8, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_ROW1__KPP_ROW1 IOMUX_PAD(0x3a4, 0x1ac, 0x10, 0, 0, PAD_CTL_PKE)
+-#define MX25_PAD_KPP_ROW1__GPIO_2_30 IOMUX_PAD(0x3a4, 0x1ac, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW1__KPP_ROW1 IOMUX_PAD(0x3a4, 0x1ac, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_KPP_ROW1__GPIO_2_30 IOMUX_PAD(0x3a4, 0x1ac, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_ROW2__KPP_ROW2 IOMUX_PAD(0x3a8, 0x1b0, 0x10, 0, 0, PAD_CTL_PKE)
+-#define MX25_PAD_KPP_ROW2__CSI_D0 IOMUX_PAD(0x3a8, 0x1b0, 0x13, 0x488, 2, NO_PAD_CTRL)
+-#define MX25_PAD_KPP_ROW2__GPIO_2_31 IOMUX_PAD(0x3a8, 0x1b0, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW2__KPP_ROW2 IOMUX_PAD(0x3a8, 0x1b0, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_KPP_ROW2__CSI_D0 IOMUX_PAD(0x3a8, 0x1b0, 0x03, 0x488, 2, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW2__GPIO_2_31 IOMUX_PAD(0x3a8, 0x1b0, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_ROW3__KPP_ROW3 IOMUX_PAD(0x3ac, 0x1b4, 0x10, 0, 0, PAD_CTL_PKE)
+-#define MX25_PAD_KPP_ROW3__CSI_LD1 IOMUX_PAD(0x3ac, 0x1b4, 0x13, 0x48c, 2, NO_PAD_CTRL)
+-#define MX25_PAD_KPP_ROW3__GPIO_3_0 IOMUX_PAD(0x3ac, 0x1b4, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW3__KPP_ROW3 IOMUX_PAD(0x3ac, 0x1b4, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
++#define MX25_PAD_KPP_ROW3__CSI_LD1 IOMUX_PAD(0x3ac, 0x1b4, 0x03, 0x48c, 2, NO_PAD_CTRL)
++#define MX25_PAD_KPP_ROW3__GPIO_3_0 IOMUX_PAD(0x3ac, 0x1b4, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_COL0__KPP_COL0 IOMUX_PAD(0x3b0, 0x1b8, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+-#define MX25_PAD_KPP_COL0__GPIO_3_1 IOMUX_PAD(0x3b0, 0x1b8, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_COL0__KPP_COL0 IOMUX_PAD(0x3b0, 0x1b8, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
++#define MX25_PAD_KPP_COL0__GPIO_3_1 IOMUX_PAD(0x3b0, 0x1b8, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_COL1__KPP_COL1 IOMUX_PAD(0x3b4, 0x1bc, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+-#define MX25_PAD_KPP_COL1__GPIO_3_2 IOMUX_PAD(0x3b4, 0x1bc, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_COL1__KPP_COL1 IOMUX_PAD(0x3b4, 0x1bc, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
++#define MX25_PAD_KPP_COL1__GPIO_3_2 IOMUX_PAD(0x3b4, 0x1bc, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_COL2__KPP_COL2 IOMUX_PAD(0x3b8, 0x1c0, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+-#define MX25_PAD_KPP_COL2__GPIO_3_3 IOMUX_PAD(0x3b8, 0x1c0, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_COL2__KPP_COL2 IOMUX_PAD(0x3b8, 0x1c0, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
++#define MX25_PAD_KPP_COL2__GPIO_3_3 IOMUX_PAD(0x3b8, 0x1c0, 0x05, 0, 0, NO_PAD_CTRL)
+
+-#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+-#define MX25_PAD_KPP_COL3__GPIO_3_4 IOMUX_PAD(0x3bc, 0x1c4, 0x15, 0, 0, NO_PAD_CTRL)
++#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(0x3bc, 0x1c4, 0x00, 0, 0, PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
++#define MX25_PAD_KPP_COL3__GPIO_3_4 IOMUX_PAD(0x3bc, 0x1c4, 0x05, 0, 0, NO_PAD_CTRL)
+
+ #define MX25_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(0x3c0, 0x1c8, 0x10, 0, 0, NO_PAD_CTRL)
+ #define MX25_PAD_FEC_MDC__AUD4_TXD IOMUX_PAD(0x3c0, 0x1c8, 0x12, 0x464, 1, NO_PAD_CTRL)
+@@ -442,7 +442,7 @@
+ #define MX25_PAD_GPIO_A__USBOTG_PWR IOMUX_PAD(0x3f0, 0x1f4, 0x12, 0, 0, PAD_CTL_PKE)
+
+ #define MX25_PAD_GPIO_B__GPIO_B IOMUX_PAD(0x3f4, 0x1f8, 0x10, 0, 0, NO_PAD_CTRL)
+-#define MX25_PAD_GPIO_B__CAN1_RX IOMUX_PAD(0x3f4, 0x1f8, 0x16, 0x480, 1, PAD_CTL_PUS_22K)
++#define MX25_PAD_GPIO_B__CAN1_RX IOMUX_PAD(0x3f4, 0x1f8, 0x16, 0x480, 1, PAD_CTL_PUS_22K_UP)
+ #define MX25_PAD_GPIO_B__USBOTG_OC IOMUX_PAD(0x3f4, 0x1f8, 0x12, 0x57c, 1, PAD_CTL_PUS_100K_UP)
+
+ #define MX25_PAD_GPIO_C__GPIO_C IOMUX_PAD(0x3f8, 0x1fc, 0x10, 0, 0, NO_PAD_CTRL)
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/iomux-v3.h linux.35.new/arch/arm/plat-mxc/include/mach/iomux-v3.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/iomux-v3.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/iomux-v3.h 2010-12-03 09:51:55.372348122 +0100
+@@ -101,6 +101,19 @@
+ int mxc_iomux_v3_setup_multiple_pads(struct pad_desc *pad_list, unsigned count);
+
+ /*
++ * releases a single pad:
++ * - make it available for a future use by another driver
++ * - DOES NOT reconfigure the IOMUX in its reset state
++ */
++void mxc_iomux_v3_release_pad(struct pad_desc *pad);
++
++/*
++ * releases multiple pads
++ * convenvient way to call the above function with tables
++ */
++void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count);
++
++/*
+ * Initialise the iomux controller
+ */
+ void mxc_iomux_v3_init(void __iomem *iomux_v3_base);
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/memory.h linux.35.new/arch/arm/plat-mxc/include/mach/memory.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/memory.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/memory.h 2011-01-12 14:23:34.124489511 +0100
+@@ -50,6 +50,13 @@
+ * This is required for i.MX camera driver to capture at least four VGA frames.
+ */
+ #define CONSISTENT_DMA_SIZE SZ_4M
++
++#elif defined(CONFIG_ARCH_MX25)
++/*
++ * Increase size of DMA-consistent memory region.
++ * This is required for i.MX fb driver to support android on VGA screens at 32 bit.
++ */
++#define CONSISTENT_DMA_SIZE SZ_4M
+ #endif /* CONFIG_MX1_VIDEO */
+
+ #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/mx25.h linux.35.new/arch/arm/plat-mxc/include/mach/mx25.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/mx25.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/mx25.h 2010-12-03 09:51:55.372348122 +0100
+@@ -1,6 +1,10 @@
+ #ifndef __MACH_MX25_H__
+ #define __MACH_MX25_H__
+
++#define SDMA_V2
++
++#define CSD0_BASE_ADDR 0x80000000
++
+ #define MX25_AIPS1_BASE_ADDR 0x43f00000
+ #define MX25_AIPS1_BASE_ADDR_VIRT 0xfc000000
+ #define MX25_AIPS1_SIZE SZ_1M
+@@ -10,9 +14,19 @@
+ #define MX25_AVIC_BASE_ADDR 0x68000000
+ #define MX25_AVIC_BASE_ADDR_VIRT 0xfc400000
+ #define MX25_AVIC_SIZE SZ_1M
+-
++#define MX25_SPBA0_BASE_ADDR UL(0x50000000)
++#define MX25_SPBA0_BASE_ADDR_VIRT 0xFC100000
++#define MX25_SPBA0_SIZE SZ_1M
++
++#define MX25_I2C1_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x80000)
++#define MX25_I2C3_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x84000)
++#define MX25_CAN1_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x88000)
++#define MX25_CAN2_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x8c000)
++#define MX25_I2C2_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x98000)
++#define MX25_OWIRE_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0x9c000)
++#define MX25_CSPI1_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0xa4000)
+ #define MX25_IOMUXC_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0xac000)
+-
++#define AUDMUX_BASE_ADDR (MX25_AIPS1_BASE_ADDR + 0xb0000)
+ #define MX25_CRM_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x80000)
+ #define MX25_GPT1_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x90000)
+ #define MX25_WDOG_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0xdc000)
+@@ -27,22 +41,205 @@
+ IMX_IO_ADDRESS(x, MX25_AIPS2) ?: \
+ IMX_IO_ADDRESS(x, MX25_AVIC))
+
++#define MX25_AIPS1_IO_ADDRESS(x) \
++ (((x) - MX25_AIPS1_BASE_ADDR) + MX25_AIPS1_BASE_ADDR_VIRT)
++#define MX25_AIPS2_IO_ADDRESS(x) \
++ (((x) - MX25_AIPS2_BASE_ADDR) + MX25_AIPS2_BASE_ADDR_VIRT)
++#define MX25_AVIC_IO_ADDRESS(x) \
++ (((x) - MX25_AVIC_BASE_ADDR) + MX25_AVIC_BASE_ADDR_VIRT)
++
+ #define MX25_UART1_BASE_ADDR 0x43f90000
+ #define MX25_UART2_BASE_ADDR 0x43f94000
++#define MX25_AUDMUX_BASE_ADDR 0x43fb0000
++#define MX25_UART3_BASE_ADDR 0x5000c000
++#define MX25_UART4_BASE_ADDR 0x50008000
++#define MX25_UART5_BASE_ADDR 0x5002c000
+
++#define MX25_CSPI3_BASE_ADDR 0x50004000
++#define MX25_CSPI2_BASE_ADDR 0x50010000
+ #define MX25_FEC_BASE_ADDR 0x50038000
++#define MX25_SSI2_BASE_ADDR 0x50014000
++#define MX25_SSI1_BASE_ADDR 0x50034000
+ #define MX25_NFC_BASE_ADDR 0xbb000000
+-#define MX25_DRYICE_BASE_ADDR 0x53ffc000
+ #define MX25_LCDC_BASE_ADDR 0x53fbc000
++#define MX25_OTG_BASE_ADDR 0x53ff4000
+
+-#define MX25_INT_DRYICE 25
+-#define MX25_INT_FEC 57
+ #define MX25_INT_NANDFC 33
+ #define MX25_INT_LCDC 39
+
+-#if defined(IMX_NEEDS_DEPRECATED_SYMBOLS)
+-#define UART1_BASE_ADDR MX25_UART1_BASE_ADDR
+-#define UART2_BASE_ADDR MX25_UART2_BASE_ADDR
++#define IO_ADDRESS(x) MX25_IO_ADDRESS(x)
++#define AVIC_IO_ADDRESS(x) MX25_AVIC_IO_ADDRESS(x)
++#define AVIC_BASE_ADDR MX25_AVIC_BASE_ADDR
++#define FEC_BASE_ADDR (MX25_FEC_BASE_ADDR)
++#define IIM_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000F0000)
++//MMC
++#define MMC_SDHC1_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000B4000)
++#define MMC_SDHC2_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000B8000)
++//SDMA(MMC) + (audio)
++#define SSI1_BASE_ADDR (MX25_SPBA0_BASE_ADDR + 0x00034000)
++#define SSI2_BASE_ADDR (MX25_SPBA0_BASE_ADDR + 0x00014000)
++#define ESAI_BASE_ADDR (MX25_SPBA0_BASE_ADDR + 0x00018000)
++#define SDMA_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000D4000)
++//WTD
++#define WDOG_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000DC000)
++//ADC
++#define SPBA0_BASE_ADDR 0x50000000
++#define TSC_BASE_ADDR (SPBA0_BASE_ADDR + 0x00030000)
++//SCC
++#define SCC_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000AC000)
++//RNG module
++#define RNGB_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000B0000)
++//DRYICE
++#define DRYICE_BASE_ADDR (MX25_AIPS2_BASE_ADDR + 0x000FC000)
++
++/*!
++ * Defines for modules using static and dynamic DMA channels
++ */
++#define MXC_DMA_CHANNEL_IRAM 30
++#define MXC_DMA_CHANNEL_UART1_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART1_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART2_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART2_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART3_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART3_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART4_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART4_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART5_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_UART5_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_MMC1 MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_SSI1_RX MXC_DMA_DYNAMIC_CHANNEL
++#ifdef CONFIG_SDMA_IRAM
++#define MXC_DMA_CHANNEL_SSI1_TX (MXC_DMA_CHANNEL_IRAM + 1)
++#else
++#define MXC_DMA_CHANNEL_SSI1_TX MXC_DMA_DYNAMIC_CHANNEL
+ #endif
++#define MXC_DMA_CHANNEL_SSI2_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_SSI2_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI1_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI1_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI2_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI2_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI3_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_CSPI3_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_ATA_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_ATA_TX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_MEMORY MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_ESAI_RX MXC_DMA_DYNAMIC_CHANNEL
++#define MXC_DMA_CHANNEL_ESAI_TX MXC_DMA_DYNAMIC_CHANNEL
++
++/*
++ * DMA request assignments
++ */
++#define DMA_REQ_EXTREQ0 0
++#define DMA_REQ_CCM 1
++#define DMA_REQ_ATA_TX_END 2
++#define DMA_REQ_ATA_TX 3
++#define DMA_REQ_ATA_RX 4
++#define DMA_REQ_CSPI2_RX 6
++#define DMA_REQ_CSPI2_TX 7
++#define DMA_REQ_CSPI1_RX 8
++#define DMA_REQ_CSPI1_TX 9
++#define DMA_REQ_UART3_RX 10
++#define DMA_REQ_UART3_TX 11
++#define DMA_REQ_UART4_RX 12
++#define DMA_REQ_UART4_TX 13
++#define DMA_REQ_EXTREQ1 14
++#define DMA_REQ_EXTREQ2 15
++#define DMA_REQ_UART2_RX 16
++#define DMA_REQ_UART2_TX 17
++#define DMA_REQ_UART1_RX 18
++#define DMA_REQ_UART1_TX 19
++#define DMA_REQ_SSI2_RX1 22
++#define DMA_REQ_SSI2_TX1 23
++#define DMA_REQ_SSI2_RX0 24
++#define DMA_REQ_SSI2_TX0 25
++#define DMA_REQ_SSI1_RX1 26
++#define DMA_REQ_SSI1_TX1 27
++#define DMA_REQ_SSI1_RX0 28
++#define DMA_REQ_SSI1_TX0 29
++#define DMA_REQ_NFC 30
++#define DMA_REQ_ECT 31
++#define DMA_REQ_ESAI_RX 32
++#define DMA_REQ_ESAI_TX 33
++#define DMA_REQ_CSPI3_RX 34
++#define DMA_REQ_CSPI3_TX 35
++#define DMA_REQ_SIM2_RX 36
++#define DMA_REQ_SIM2_TX 37
++#define DMA_REQ_SIM1_RX 38
++#define DMA_REQ_SIM1_TX 39
++#define DMA_REQ_TSC_GCQ 44
++#define DMA_REQ_TSC_TCQ 45
++#define DMA_REQ_UART5_RX 46
++#define DMA_REQ_UART5_TX 47
++
++/*
++ * Interrupt numbers
++ */
++#define MX25_INT_CSPI3 0
++#define MXC_INT_GPT4 1
++#define MXC_INT_OWIRE 2
++#define MX25_INT_I2C1 3
++#define MX25_INT_I2C2 4
++#define MX25_INT_UART4 5
++#define MXC_INT_RTIC 6
++#define MXC_INT_ESAI 7
++#define MXC_INT_SDHC2 8
++#define MXC_INT_SDHC1 9
++#define MX25_INT_I2C3 10
++#define MX25_INT_SSI2 11
++#define MX25_INT_SSI1 12
++#define MX25_INT_CSPI2 13
++#define MX25_INT_CSPI1 14
++#define MXC_INT_ATA 15
++#define MXC_INT_GPIO3 16
++#define MXC_INT_CSI 17
++#define MX25_INT_UART3 18
++#define MXC_INT_IIM 19
++#define MXC_INT_SIM1 20
++#define MXC_INT_SIM2 21
++#define MXC_INT_RNG 22
++#define MXC_INT_GPIO4 23
++#define MXC_INT_KPP 24
++#define MXC_INT_DRYICE_NORM 25
++#define MXC_INT_PWM 26
++#define MXC_INT_EPIT2 27
++#define MXC_INT_EPIT1 28
++#define MXC_INT_GPT3 29
++#define MXC_INT_POWER_FAIL 30
++#define MXC_INT_CCM 31
++#define MX25_INT_UART2 32
++#define MXC_INT_NANDFC 33
++#define MXC_INT_SDMA 34
++#define MXC_INT_USB_H2 35
++#define MXC_INT_PWM2 36
++#define MXC_INT_USB_OTG 37
++#define MXC_INT_SLCDC 38
++#define MXC_INT_LCDC 39
++#define MX25_INT_UART5 40
++#define MXC_INT_PWM3 41
++#define MXC_INT_PWM4 42
++#define MX25_INT_CAN1 43
++#define MX25_INT_CAN2 44
++#define MX25_INT_UART1 45
++#define MXC_INT_TSC 46
++#define MXC_INT_ECT 48
++#define MXC_INT_SCC_SCM 49
++#define MXC_INT_SCC_SMN 50
++#define MXC_INT_GPIO2 51
++#define MXC_INT_GPIO1 52
++#define MXC_INT_GPT2 53
++#define MXC_INT_GPT1 54
++#define MXC_INT_WDOG 55
++#define MXC_INT_DRYICE_SEC 56
++#define MX25_INT_FEC 57
++#define MXC_INT_EXT_INT5 58
++#define MXC_INT_EXT_INT4 59
++#define MXC_INT_EXT_INT3 60
++#define MXC_INT_EXT_INT2 61
++#define MXC_INT_EXT_INT1 62
++#define MXC_INT_EXT_INT0 63
++
++#define MXC_INT_GPT MXC_INT_GPT1
++
+
+ #endif /* ifndef __MACH_MX25_H__ */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/mxc.h linux.35.new/arch/arm/plat-mxc/include/mach/mxc.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/mxc.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/mxc.h 2010-12-03 09:51:55.372348122 +0100
+@@ -143,4 +143,35 @@
+ #define cpu_is_mx3() (cpu_is_mx31() || cpu_is_mx35() || cpu_is_mxc91231())
+ #define cpu_is_mx2() (cpu_is_mx21() || cpu_is_mx27())
+
++#ifndef __ASSEMBLY__
++
++#include <linux/types.h>
++
++/*
++ * This struct is to define the number of SSIs on a platform,
++ * DAM source port config, DAM external port config,
++ * regulator names, and other stuff audio needs.
++ */
++struct mxc_audio_platform_data {
++ int ssi_num;
++ int src_port;
++ int ext_port;
++
++ int intr_id_hp;
++ int ext_ram;
++ struct clk *ssi_clk[2];
++
++ int hp_irq;
++ int (*hp_status) (void);
++
++ int sysclk;
++
++ int (*init) (void); /* board specific init */
++ int (*amp_enable) (int enable);
++ int (*finit) (void); /* board specific finit */
++ void *priv; /* used by board specific functions */
++};
++
++#endif //__ASSEMBLY__
++
+ #endif /* __ASM_ARCH_MXC_H__ */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/mxc_nand.h linux.35.new/arch/arm/plat-mxc/include/mach/mxc_nand.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/mxc_nand.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/mxc_nand.h 2010-12-03 09:51:55.372348122 +0100
+@@ -20,9 +20,14 @@
+ #ifndef __ASM_ARCH_NAND_H
+ #define __ASM_ARCH_NAND_H
+
++struct mtd_partition;
++struct mtd_info;
++
+ struct mxc_nand_platform_data {
+ int width; /* data bus width in bytes */
+ int hw_ecc:1; /* 0 if supress hardware ECC */
+ int flash_bbt:1; /* set to 1 to use a flash based bbt */
++ struct mtd_partition *parts; /* optional array of mtd_partitions for static partitioning */
++ unsigned int nr_parts; /* number of mtd_partitions for static partitoning */
+ };
+ #endif /* __ASM_ARCH_NAND_H */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/mxc_tsc.h linux.35.new/arch/arm/plat-mxc/include/mach/mxc_tsc.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/mxc_tsc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/mxc_tsc.h 2010-12-03 09:51:55.376350318 +0100
+@@ -0,0 +1,32 @@
++/*
++ * Freescale i.MX25 Touch Screen Driver
++ *
++ * Copyright (c) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * Based on code from Freescale BSP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++typedef enum {
++ MXC_TSC_4WIRE,
++ MXC_TSC_5WIRE,
++} mxc_tsc_mode;
++
++struct mxc_tsc_pdata {
++ int pen_debounce_time; /* 0: disable debounce;
++ * 1..128: # of ADC clock cycles / 8 */
++ unsigned int intref:1, /* 0|1: internal reference disabled|enabled */
++ hsyncen:1, /* synchronize measurements with LCD HSYNC */
++ hsyncpol:1; /* select HSYNC polarity: 1 == active low */
++ unsigned int r_xplate; /* resistance (in Ohms) of X plate
++ * (required for pressure measurement */
++ unsigned int settle_detect; /* Settling time for touch detection (in ADC clock cycles) */
++ unsigned int settle_measure; /* Settling time for measurement (in ADC clock cycles) */
++ unsigned int settle_precharge; /* Settling time for precharge (in ADC clock cycles) */
++ int adc_clk; /* ADC clock frequency in Hz (max. 1750000);
++ * <= 0: use default (1666667) */
++ mxc_tsc_mode tsc_mode; /* select 4 wire or 5 wire mode */
++};
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/sdhci.h linux.35.new/arch/arm/plat-mxc/include/mach/sdhci.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/sdhci.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/sdhci.h 2010-12-20 14:58:29.196000606 +0100
+@@ -0,0 +1,50 @@
++#ifndef __MACH_SDHCI_H
++#define __MACH_SDHCI_H
++
++#include <linux/mmc/host.h>
++struct device;
++
++struct mxc_sdhci_platform_data {
++ /* Return values for the get_ro callback should be:
++ * 0 for a read/write card
++ * 1 for a read-only card
++ * -ENOSYS when not supported (equal to NULL callback)
++ * or a negative errno value when something bad happened
++ */
++ int (*get_ro)(struct device *);
++
++ /* board specific hook to (de)initialize the SD slot.
++ * The board code can call 'handler' on a card detection
++ * change giving data as argument.
++ */
++ int (*init)(struct device *dev, irq_handler_t handler, void *data);
++ void (*exit)(struct device *dev, void *data);
++
++ /* delay in ms between card detect IRQ and scanning for
++ * card insertion/removal
++ */
++ int detect_delay;
++
++ /* available voltages. If not given, assume
++ * MMC_VDD_32_33 | MMC_VDD_33_34
++ */
++ unsigned int ocr_avail;
++ unsigned int caps;
++ unsigned int min_clk;
++ unsigned int max_clk;
++ unsigned int mxc_quirks;
++
++ /* adjust slot voltage */
++ int (*setpower)(struct device *dev, unsigned int vdd);
++#if 1
++ // FIXME: get rid of this
++ int (*status)(struct device *dev);
++#endif
++ int (*suspend)(struct device *dev);
++ int (*resume)(struct device *dev);
++
++ /* Set card detection state to 1 */
++ unsigned int force_sd_detect;
++};
++
++#endif /* __MACH_SDHCI_H */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/sdma.h linux.35.new/arch/arm/plat-mxc/include/mach/sdma.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/sdma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/sdma.h 2010-12-03 09:51:55.376350318 +0100
+@@ -0,0 +1,563 @@
++
++/*
++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __ASM_ARCH_MXC_SDMA_H__
++#define __ASM_ARCH_MXC_SDMA_H__
++
++/*!
++ * @defgroup SDMA Smart Direct Memory Access (SDMA) Driver
++ */
++
++/*!
++ * @file arch-mxc/sdma.h
++ *
++ * @brief This file contains the SDMA API declarations.
++ *
++ * SDMA is responsible on moving data between peripherals and memories (MCU, EMI and DSP).
++ *
++ * @ingroup SDMA
++ */
++
++#include <stdarg.h>
++#include <linux/interrupt.h>
++
++#include <mach/dma.h>
++#include <mach/hardware.h>
++
++/*!
++ * This defines maximum DMA address
++ */
++#define MAX_DMA_ADDRESS 0xffffffff
++
++#define DMA_ADDR_INVALID ((dma_addr_t)0)
++
++/*!
++ * This defines maximum number of DMA channels
++ */
++#ifdef CONFIG_MXC_SDMA_API
++#define MAX_DMA_CHANNELS 32
++#define MXC_SDMA_DEFAULT_PRIORITY 1
++#define MXC_SDMA_MIN_PRIORITY 1
++#define MXC_SDMA_MAX_PRIORITY 7
++#else
++#define MAX_DMA_CHANNELS 0
++#endif
++
++#define MXC_FIFO_MEM_DEST_FIXED 0x1
++#define MXC_FIFO_MEM_SRC_FIXED 0x2
++
++#define SDMA_ASRC_INFO_WML_OFF 0
++#define SDMA_ASRC_INFO_WML_MASK ((1 << 10) - 1)
++#define SDMA_ASRC_INFO_PS (1 << 10)
++#define SDMA_ASRC_INFO_PA (1 << 11)
++#define SDMA_ASRC_INFO_TXFR_DIR (1 << 14)
++#define SDMA_ASRC_INFO_N_OFF 24
++#define SDMA_ASRC_INFO_N_MASK ((1 << 4) - 1)
++
++#define SDMA_ASRC_P2P_INFO_LWML_OFF 0
++#define SDMA_ASRC_P2P_INFO_LWML_MASK ((1 << 8) - 1)
++#define SDMA_ASRC_P2P_INFO_PS (1 << 8)
++#define SDMA_ASRC_P2P_INFO_PA (1 << 9)
++#define SDMA_ASRC_P2P_INFO_SPDIF (1 << 10)
++#define SDMA_ASRC_P2P_INFO_SP (1 << 11)
++#define SDMA_ASRC_P2P_INFO_DP (1 << 12)
++#define SDMA_ASRC_P2P_INFO_HWML_OFF 14
++#define SDMA_ASRC_P2P_INFO_HWML_MASK ((1 << 10) - 1)
++#define SDMA_ASRC_P2P_INFO_LWE (1 << 28)
++#define SDMA_ASRC_P2P_INFO_HWE (1 << 29)
++#define SDMA_ASRC_P2P_INFO_CONT (1 << 31)
++
++/*!
++ * This enumerates transfer types
++ */
++typedef enum {
++ emi_2_per = 0, /*!< EMI memory to peripheral */
++ emi_2_int, /*!< EMI memory to internal RAM */
++ emi_2_emi, /*!< EMI memory to EMI memory */
++ emi_2_dsp, /*!< EMI memory to DSP memory */
++ per_2_int, /*!< Peripheral to internal RAM */
++ per_2_emi, /*!< Peripheral to internal EMI memory */
++ per_2_dsp, /*!< Peripheral to DSP memory */
++ per_2_per, /*!< Peripheral to Peripheral */
++ int_2_per, /*!< Internal RAM to peripheral */
++ int_2_int, /*!< Internal RAM to Internal RAM */
++ int_2_emi, /*!< Internal RAM to EMI memory */
++ int_2_dsp, /*!< Internal RAM to DSP memory */
++ dsp_2_per, /*!< DSP memory to peripheral */
++ dsp_2_int, /*!< DSP memory to internal RAM */
++ dsp_2_emi, /*!< DSP memory to EMI memory */
++ dsp_2_dsp, /*!< DSP memory to DSP memory */
++ emi_2_dsp_loop, /*!< EMI memory to DSP memory loopback */
++ dsp_2_emi_loop, /*!< DSP memory to EMI memory loopback */
++ dvfs_pll, /*!< DVFS script with PLL change */
++ dvfs_pdr /*!< DVFS script without PLL change */
++} sdma_transferT;
++
++/*!
++ * This enumerates peripheral types
++ */
++typedef enum {
++ SSI, /*!< MCU domain SSI */
++ SSI_SP, /*!< Shared SSI */
++ MMC, /*!< MMC */
++ SDHC, /*!< SDHC */
++ UART, /*!< MCU domain UART */
++ UART_SP, /*!< Shared UART */
++ FIRI, /*!< FIRI */
++ CSPI, /*!< MCU domain CSPI */
++ CSPI_SP, /*!< Shared CSPI */
++ SIM, /*!< SIM */
++ ATA, /*!< ATA */
++ CCM, /*!< CCM */
++ EXT, /*!< External peripheral */
++ MSHC, /*!< Memory Stick Host Controller */
++ MSHC_SP, /*!< Shared Memory Stick Host Controller */
++ DSP, /*!< DSP */
++ MEMORY, /*!< Memory */
++ FIFO_MEMORY, /*!< FIFO type Memory */
++ SPDIF, /*!< SPDIF */
++ IPU_MEMORY, /*!< IPU Memory */
++ ASRC, /*!< ASRC */
++ ESAI, /*!< ESAI */
++} sdma_periphT;
++
++#ifndef TRANSFER_32BIT
++/*!
++ * This defines SDMA access data size
++ */
++#define TRANSFER_32BIT 0x00
++#define TRANSFER_8BIT 0x01
++#define TRANSFER_16BIT 0x02
++#define TRANSFER_24BIT 0x03
++
++#endif
++
++/*!
++ * This defines maximum device name length passed during mxc_request_dma().
++ */
++#define MAX_DEVNAME_LENGTH 32
++
++/*!
++ * This defines SDMA interrupt callback function prototype.
++ */
++typedef void (*dma_callback_t) (void *arg);
++
++/*!
++ * Structure containing sdma channel parameters.
++ */
++typedef struct {
++ __u32 watermark_level; /* Lower/upper threshold that
++ * triggers SDMA event
++ * for p2p, this is event1 watermark level
++ */
++ __u32 per_address; /* Peripheral source/destination
++ * physical address
++ * for p2p, this is destination address
++ */
++ sdma_periphT peripheral_type; /* Peripheral type */
++ sdma_transferT transfer_type; /* Transfer type */
++ int event_id; /* Event number,
++ * needed by all channels
++ * that started by peripherals dma
++ * request (per_2_*,*_2_per)
++ * Not used for memory and DSP
++ * transfers.
++ */
++ int event_id2; /* Second event number,
++ * used in ATA scripts only.
++ */
++ int bd_number; /* Buffer descriptors number.
++ * If not set, single buffer
++ * descriptor will be used.
++ */
++ dma_callback_t callback;/* callback function */
++ void *arg; /* callback argument */
++ unsigned long word_size:8; /* SDMA data access word size */
++ unsigned long ext:1; /* 1: extend parameter structure */
++} dma_channel_params;
++
++typedef struct {
++ dma_channel_params common;
++ unsigned long p2p_dir:1; /* 0: per2 to per.
++ * the device of peripheral_type is per.
++ * 1: per to per2
++ * the device of peripheral_type is per2
++ */
++ unsigned long info_bits; /* info field in context */
++ unsigned long info_mask; /* info field mask in context */
++ __u32 watermark_level2; /* event2 threshold that triggers SDMA event
++ * just valid for per_2_per.
++ */
++ __u32 per_address2; /* Peripheral source physical address.
++ * only valid for per_2_per.
++ */
++ struct dma_channel_info info; /* the channel special parameter */
++} dma_channel_ext_params;
++
++/*!
++ * Structure containing sdma request parameters.
++ */
++typedef struct {
++ /*! physical source memory address */
++ dma_addr_t sourceAddr;
++ /*! physical destination memory address */
++ dma_addr_t destAddr;
++ /*! amount of data to transfer,
++ * updated during mxc_dma_get_config
++ */
++ __u16 count;
++ /*!< DONE bit of the buffer descriptor,
++ * updated during mxc_dma_get_config
++ * 0 - means the BD is done and closed by SDMA
++ * 1 - means the BD is still being processed by SDMA
++ */
++ unsigned int bd_done:1,
++ /*!< CONT bit of the buffer descriptor,
++ * set it if full multi-buffer descriptor mechanism
++ * required.
++ */
++ bd_cont:1,
++ /*!< ERROR bit of the buffer descriptor,
++ * updated during mxc_dma_get_config.
++ * If it is set - there was an error during BD processing.
++ */
++ bd_error:1,
++ bd_wrap:1;
++} dma_request_t;
++
++/*!
++ * Structure containing sdma request parameters.
++ */
++typedef struct {
++ /*! address of ap_2_ap script */
++ int mxc_sdma_ap_2_ap_addr;
++ /*! address of ap_2_bp script */
++ int mxc_sdma_ap_2_bp_addr;
++ /*! address of ap_2_ap_fixed script */
++ int mxc_sdma_ap_2_ap_fixed_addr;
++ /*! address of bp_2_ap script */
++ int mxc_sdma_bp_2_ap_addr;
++ /*! address of loopback_on_dsp_side script */
++ int mxc_sdma_loopback_on_dsp_side_addr;
++ /*! address of mcu_interrupt_only script */
++ int mxc_sdma_mcu_interrupt_only_addr;
++
++ /*! address of firi_2_per script */
++ int mxc_sdma_firi_2_per_addr;
++ /*! address of firi_2_mcu script */
++ int mxc_sdma_firi_2_mcu_addr;
++ /*! address of per_2_firi script */
++ int mxc_sdma_per_2_firi_addr;
++ /*! address of mcu_2_firi script */
++ int mxc_sdma_mcu_2_firi_addr;
++
++ /*! address of uart_2_per script */
++ int mxc_sdma_uart_2_per_addr;
++ /*! address of uart_2_mcu script */
++ int mxc_sdma_uart_2_mcu_addr;
++ /*! address of per_2_app script */
++ int mxc_sdma_per_2_app_addr;
++ /*! address of mcu_2_app script */
++ int mxc_sdma_mcu_2_app_addr;
++ /*! address of per_2_per script */
++ int mxc_sdma_per_2_per_addr;
++
++ /*! address of uartsh_2_per script */
++ int mxc_sdma_uartsh_2_per_addr;
++ /*! address of uartsh_2_mcu script */
++ int mxc_sdma_uartsh_2_mcu_addr;
++ /*! address of per_2_shp script */
++ int mxc_sdma_per_2_shp_addr;
++ /*! address of mcu_2_shp script */
++ int mxc_sdma_mcu_2_shp_addr;
++
++ /*! address of ata_2_mcu script */
++ int mxc_sdma_ata_2_mcu_addr;
++ /*! address of mcu_2_ata script */
++ int mxc_sdma_mcu_2_ata_addr;
++
++ /*! address of app_2_per script */
++ int mxc_sdma_app_2_per_addr;
++ /*! address of app_2_mcu script */
++ int mxc_sdma_app_2_mcu_addr;
++ /*! address of shp_2_per script */
++ int mxc_sdma_shp_2_per_addr;
++ /*! address of shp_2_mcu script */
++ int mxc_sdma_shp_2_mcu_addr;
++
++ /*! address of mshc_2_mcu script */
++ int mxc_sdma_mshc_2_mcu_addr;
++ /*! address of mcu_2_mshc script */
++ int mxc_sdma_mcu_2_mshc_addr;
++
++ /*! address of spdif_2_mcu script */
++ int mxc_sdma_spdif_2_mcu_addr;
++ /*! address of mcu_2_spdif script */
++ int mxc_sdma_mcu_2_spdif_addr;
++
++ /*! address of asrc_2_mcu script */
++ int mxc_sdma_asrc_2_mcu_addr;
++
++ /*! address of ext_mem_2_ipu script */
++ int mxc_sdma_ext_mem_2_ipu_addr;
++
++ /*! address of descrambler script */
++ int mxc_sdma_descrambler_addr;
++
++ /*! address of dptc_dvfs script */
++ int mxc_sdma_dptc_dvfs_addr;
++
++ int mxc_sdma_utra_addr;
++
++ /*! address where ram code starts */
++ int mxc_sdma_ram_code_start_addr;
++ /*! size of the ram code */
++ int mxc_sdma_ram_code_size;
++ /*! RAM image address */
++ unsigned short *mxc_sdma_start_addr;
++} sdma_script_start_addrs;
++
++/*! Structure to store the initialized dma_channel parameters */
++typedef struct mxc_sdma_channel_params {
++ /*! Channel type (static channel number or dynamic channel) */
++ unsigned int channel_num;
++ /*! Channel priority [0x1(lowest) - 0x7(highest)] */
++ unsigned int chnl_priority;
++ /*! Channel params */
++ dma_channel_params chnl_params;
++} mxc_sdma_channel_params_t;
++
++/*! Structure to store the initialized dma_channel extend parameters */
++typedef struct mxc_sdma_channel_ext_params {
++ /*! Channel type (static channel number or dynamic channel) */
++ unsigned int channel_num;
++ /*! Channel priority [0x1(lowest) - 0x7(highest)] */
++ unsigned int chnl_priority;
++ /*! Channel extend params */
++ dma_channel_ext_params chnl_ext_params;
++} mxc_sdma_channel_ext_params_t;
++
++/*! Private SDMA data structure */
++typedef struct mxc_dma_channel_private {
++ /*! ID of the buffer that was processed */
++ unsigned int buf_tail;
++ /*! Tasklet for the channel */
++ struct tasklet_struct chnl_tasklet;
++ /*! Flag indicates if interrupt is required after every BD transfer */
++ unsigned int intr_after_every_bd:1,
++ circular:1; /* circular BD chain */
++} mxc_dma_channel_private_t;
++
++/*!
++ * Setup channel according to parameters.
++ * Must be called once after mxc_request_dma()
++ *
++ * @param channel channel number
++ * @param p channel parameters pointer
++ * @return 0 on success, error code on fail
++ */
++extern int mxc_dma_setup_channel(int channel, dma_channel_params * p);
++
++/*!
++ * Setup the channel priority. This can be used to change the default priority
++ * for the channel.
++ *
++ * @param channel channel number
++ * @param priority priority to be set for the channel
++ *
++ * @return 0 on success, error code on failure
++ */
++extern int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority);
++
++/*!
++ * Allocates dma channel.
++ * If channel's value is 0, then the function allocates a free channel
++ * dynamically and sets its value to channel.
++ * Else allocates requested channel if it is free.
++ * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned.
++ *
++ * @param channel pointer to channel number
++ * @param devicename device name
++ * @return 0 on success, error code on fail
++ */
++extern int mxc_request_dma(int *channel, const char *devicename);
++
++/*!
++ * Configures request parameters. Can be called multiple times after
++ * mxc_request_dma() and mxc_dma_setup_channel().
++ *
++ *
++ * @param channel channel number
++ * @param p request parameters pointer
++ * @param bd_index index of buffer descriptor to set
++ * @return 0 on success, error code on fail
++ */
++/* int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index); */
++extern int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index);
++
++/*!
++ * Returns request parameters.
++ *
++ * @param channel channel number
++ * @param p request parameters pointer
++ * @param bd_index index of buffer descriptor to get
++ * @return 0 on success, error code on fail
++ */
++/* int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index); */
++extern int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index);
++
++/*!
++ * This function is used by MXC IPC's write_ex2. It passes the a pointer to the
++ * data control structure to iapi_write_ipcv2()
++ *
++ * @param channel SDMA channel number
++ * @param ctrl_ptr Data Control structure pointer
++ */
++extern int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr);
++
++/*!
++ * This function is used by MXC IPC's read_ex2. It passes the a pointer to the
++ * data control structure to iapi_read_ipcv2()
++ *
++ * @param channel SDMA channel number
++ * @param ctrl_ptr Data Control structure pointer
++ */
++extern int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr);
++
++/*!
++ * Starts dma channel.
++ *
++ * @param channel channel number
++ */
++extern int mxc_dma_start(int channel);
++
++/*!
++ * Stops dma channel.
++ *
++ * @param channel channel number
++ */
++extern int mxc_dma_stop(int channel);
++
++/*!
++ * Frees dma channel.
++ *
++ * @param channel channel number
++ */
++extern void mxc_free_dma(int channel);
++
++/*!
++ * Sets callback function. Used with standard dma api
++ * for supporting interrupts
++ *
++ * @param channel channel number
++ * @param callback callback function pointer
++ * @param arg argument for callback function
++ */
++extern void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg);
++
++/*!
++ * Allocates uncachable buffer. Uses hash table.
++ *
++ * @param size size of allocated buffer
++ * @return pointer to buffer
++ */
++extern void *sdma_malloc(size_t size);
++
++#ifdef CONFIG_SDMA_IRAM
++/*!
++ * Allocates uncachable buffer from IRAM..
++ *
++ * @param size size of allocated buffer
++ * @return pointer to buffer
++ */
++extern void *sdma_iram_malloc(size_t size);
++#endif /* CONFIG_SDMA_IRAM */
++
++/*!
++ * Frees uncachable buffer. Uses hash table.
++ */
++void sdma_free(void *buf);
++
++/*!
++ * Converts virtual to physical address. Uses hash table.
++ *
++ * @param buf virtual address pointer
++ * @return physical address value
++ */
++extern dma_addr_t sdma_virt_to_phys(void *buf);
++
++/*!
++ * Converts physical to virtual address. Uses hash table.
++ *
++ * @param buf physical address value
++ * @return virtual address pointer
++ */
++extern void *sdma_phys_to_virt(dma_addr_t buf);
++
++/*!
++ * Configures the BD_INTR bit on a buffer descriptor parameters.
++ *
++ *
++ * @param channel channel number
++ * @param bd_index index of buffer descriptor to set
++ * @param bd_intr flag to set or clear the BD_INTR bit
++ */
++extern void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr);
++
++/*!
++ * Gets the BD_INTR bit on a buffer descriptor.
++ *
++ *
++ * @param channel channel number
++ * @param bd_index index of buffer descriptor to set
++ *
++ * @return returns the BD_INTR bit status
++ */
++extern int mxc_dma_get_bd_intr(int channel, int bd_index);
++
++/*!
++ * Stop the current transfer
++ *
++ * @param channel channel number
++ * @param buffer_number number of buffers (beginning with 0),
++ * whose done bits should be reset to 0
++ */
++extern int mxc_dma_reset(int channel, int buffer_number);
++
++/*!
++ * This functions Returns the SDMA paramaters associated for a module
++ *
++ * @param channel_id the ID of the module requesting DMA
++ * @return returns the sdma parameters structure for the device
++ */
++extern mxc_sdma_channel_params_t *mxc_sdma_get_channel_params(mxc_dma_device_t
++ channel_id);
++
++/*!
++ * This functions marks the SDMA channels that are statically allocated
++ *
++ * @param chnl the channel array used to store channel information
++ */
++extern void mxc_get_static_channels(mxc_dma_channel_t * chnl);
++
++/*!
++ * Initializes SDMA driver
++ */
++extern int __init sdma_init(void);
++
++extern void mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_addr);
++
++#define DEFAULT_ERR 1
++
++#endif
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/spba.h linux.35.new/arch/arm/plat-mxc/include/mach/spba.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/spba.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/spba.h 2010-12-03 09:51:55.376350318 +0100
+@@ -0,0 +1,66 @@
++
++/*
++ * Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup SPBA Shared Peripheral Bus Arbiter (SPBA)
++ * @ingroup MSL_MX31 MSL_MX35 MSL_MX37 MSL_MX51 MSL_MXC91321
++ */
++
++/*!
++ * @file arch-mxc/spba.h
++ * @brief This file contains the Shared Peripheral Bus Arbiter (spba) API.
++ *
++ * @ingroup SPBA
++ */
++
++#ifndef __ASM_ARCH_MXC_SPBA_H__
++#define __ASM_ARCH_MXC_SPBA_H__
++
++#ifdef __KERNEL__
++
++#define MXC_SPBA_RAR_MASK 0x7
++
++/*!
++ * Defines three SPBA masters: A - ARM, C - SDMA (no master B for MX31)
++ */
++enum spba_masters {
++ SPBA_MASTER_A = 1,
++ SPBA_MASTER_B = 2,
++ SPBA_MASTER_C = 4,
++};
++
++/*!
++ * This function allows the three masters (A, B, C) to take ownership of a
++ * shared peripheral.
++ *
++ * @param mod specified module as defined in \b enum \b #spba_module
++ * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters
++ *
++ * @return 0 if successful; -1 otherwise.
++ */
++int spba_take_ownership(int mod, int master);
++
++/*!
++ * This function releases the ownership for a shared peripheral.
++ *
++ * @param mod specified module as defined in \b enum \b #spba_module
++ * @param master one of more (or-ed together) masters as defined in \b enum \b #spba_masters
++ *
++ * @return 0 if successful; -1 otherwise.
++ */
++int spba_rel_ownership(int mod, int master);
++
++#endif /* __KERNEL__ */
++
++#endif /* __ASM_ARCH_MXC_SPBA_H__ */
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/ssi.h linux.35.new/arch/arm/plat-mxc/include/mach/ssi.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/ssi.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/include/mach/ssi.h 2010-12-03 09:51:55.380349316 +0100
+@@ -10,6 +10,9 @@
+ unsigned int flags;
+ #define IMX_SSI_DMA (1 << 0)
+ #define IMX_SSI_USE_AC97 (1 << 1)
++#define IMX_SSI_NET (1 << 2)
++#define IMX_SSI_SYN (1 << 3)
++#define IMX_SSI_USE_I2S_SLAVE (1 << 4)
+ void (*ac97_reset) (struct snd_ac97 *ac97);
+ void (*ac97_warm_reset)(struct snd_ac97 *ac97);
+ };
+diff -urN linux.35.old/arch/arm/plat-mxc/include/mach/ssi_port.h linux.35.new/arch/arm/plat-mxc/include/mach/ssi_port.h
+--- linux.35.old/arch/arm/plat-mxc/include/mach/ssi_port.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/include/mach/ssi_port.h 2010-12-03 09:51:55.380349316 +0100
+@@ -0,0 +1,31 @@
++/*
++ * include/asm-arm/arch-mxc/ssi_port.h
++ *
++ * Copyright (C) 2008 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * 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
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ */
++
++struct mxc_ssi_port {
++ int num;
++ struct module *owner;
++ struct platform_device *parent;
++ struct resource *res;
++ struct clk *ssi_clk;
++ int in_use;
++};
++
++extern int mxc_ssi_request_port(int num, struct platform_device *parent,
++ struct mxc_ssi_port **ssi_port);
++extern void mxc_ssi_release_port(struct mxc_ssi_port *ssi_port);
+diff -urN linux.35.old/arch/arm/plat-mxc/iomux-v3.c linux.35.new/arch/arm/plat-mxc/iomux-v3.c
+--- linux.35.old/arch/arm/plat-mxc/iomux-v3.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/iomux-v3.c 2010-12-03 09:51:55.380349316 +0100
+@@ -30,12 +30,34 @@
+ #include <mach/iomux-v3.h>
+
+ static void __iomem *base;
++#ifdef CONFIG_ARCH_MX25
++#define NUM_PADS 0x228
++#else
++#define NUM_PADS 0x200
++#endif
++
++static unsigned long iomux_v3_pad_alloc_map[NUM_PADS / BITS_PER_LONG];
++
++static inline int mxc_iomux_v3_pad_offset(struct pad_desc *pad)
++{
++ int pad_ofs;
++ if (cpu_is_mx25())
++ pad_ofs = pad->mux_ctrl_ofs;
++ else
++ pad_ofs = pad->pad_ctrl_ofs;
++ BUG_ON((pad_ofs >> 7) >= ARRAY_SIZE(iomux_v3_pad_alloc_map));
++ return pad_ofs;
++}
+
+ /*
+ * setups a single pad in the iomuxer
+ */
+ int mxc_iomux_v3_setup_pad(struct pad_desc *pad)
+ {
++ unsigned int pad_ofs = mxc_iomux_v3_pad_offset(pad);
++
++ if (test_and_set_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map))
++ return -EBUSY;
+ if (pad->mux_ctrl_ofs)
+ __raw_writel(pad->mux_mode, base + pad->mux_ctrl_ofs);
+
+@@ -65,6 +87,26 @@
+ }
+ EXPORT_SYMBOL(mxc_iomux_v3_setup_multiple_pads);
+
++void mxc_iomux_v3_release_pad(struct pad_desc *pad)
++{
++ unsigned int pad_ofs = mxc_iomux_v3_pad_offset(pad);
++
++ clear_bit(pad_ofs >> 2, iomux_v3_pad_alloc_map);
++}
++EXPORT_SYMBOL(mxc_iomux_v3_release_pad);
++
++void mxc_iomux_v3_release_multiple_pads(struct pad_desc *pad_list, int count)
++{
++ struct pad_desc *p = pad_list;
++ int i;
++
++ for (i = 0; i < count; i++) {
++ mxc_iomux_v3_release_pad(p);
++ p++;
++ }
++}
++EXPORT_SYMBOL(mxc_iomux_v3_release_multiple_pads);
++
+ void mxc_iomux_v3_init(void __iomem *iomux_v3_base)
+ {
+ base = iomux_v3_base;
+diff -urN linux.35.old/arch/arm/plat-mxc/Kconfig linux.35.new/arch/arm/plat-mxc/Kconfig
+--- linux.35.old/arch/arm/plat-mxc/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/Kconfig 2010-12-03 09:51:55.380349316 +0100
+@@ -1,5 +1,7 @@
+ if ARCH_MXC
+
++source "arch/arm/plat-mxc/devices/Kconfig"
++
+ menu "Freescale MXC Implementations"
+
+ choice
+@@ -25,6 +27,7 @@
+ select CPU_ARM926T
+ select ARCH_MXC_IOMUX_V3
+ select HAVE_FB_IMX
++ select ARCH_MXC_AUDMUX_V2
+ help
+ This enables support for systems based on the Freescale i.MX25 family
+
+@@ -99,4 +102,14 @@
+ config ARCH_MXC_AUDMUX_V2
+ bool
+
++config MXC_SSI_PORTS
++ bool "Generic SSI Layer"
++ depends on ARCH_MXC
++ help
++ This option enables the generic SSI layer that makes it possible to
++ write drivers that decide at runtime which SSI port to use.
++ Since the SSI signals must be routed through the AUDMUX, there is no
++ reason to hardwire any driver that utilizes the SSI interface to a specific
++ SSI port.
++
+ endif
+diff -urN linux.35.old/arch/arm/plat-mxc/Makefile linux.35.new/arch/arm/plat-mxc/Makefile
+--- linux.35.old/arch/arm/plat-mxc/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/arch/arm/plat-mxc/Makefile 2010-12-03 09:51:55.380349316 +0100
+@@ -13,6 +13,7 @@
+ obj-$(CONFIG_IMX_HAVE_IOMUX_V1) += iomux-v1.o
+ obj-$(CONFIG_ARCH_MXC_IOMUX_V3) += iomux-v3.o
+ obj-$(CONFIG_MXC_PWM) += pwm.o
++obj-$(CONFIG_MXC_SDMA_API) += sdma/
+ obj-$(CONFIG_USB_EHCI_MXC) += ehci.o
+ obj-$(CONFIG_MXC_ULPI) += ulpi.o
+ obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o
+@@ -21,3 +22,8 @@
+ obj-y += ssi-fiq.o
+ obj-y += ssi-fiq-ksym.o
+ endif
++
++obj-y += devices/
++
++mxc-ssi-ports-objs := ssi.o
++obj-$(CONFIG_MXC_SSI_PORTS) += mxc-ssi-ports.o
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/dma_sdma.c linux.35.new/arch/arm/plat-mxc/sdma/dma_sdma.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/dma_sdma.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/dma_sdma.c 2010-12-03 09:51:55.384181534 +0100
+@@ -0,0 +1,763 @@
++/*
++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file plat-mxc/sdma/dma_sdma.c
++ * @brief Front-end to the DMA handling. This handles the allocation/freeing
++ * of DMA channels, and provides a unified interface to the machines
++ * DMA facilities. This file contains functions for Smart DMA.
++ *
++ * @ingroup SDMA
++ */
++
++#include <linux/init.h>
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
++#include <mach/dma.h>
++#include <mach/hardware.h>
++#include <linux/slab.h>
++
++#include <epm.h>
++#include "sdma.h"
++
++#ifdef CONFIG_MXC_SDMA_API
++
++static mxc_dma_channel_t mxc_sdma_channels[MAX_DMA_CHANNELS];
++static mxc_dma_channel_private_t mxc_sdma_private[MAX_DMA_CHANNELS];
++
++/*!
++ * Tasket to handle processing the channel buffers
++ *
++ * @param arg channel id
++ */
++static void mxc_sdma_channeltasklet(unsigned long arg)
++{
++ dma_request_t req;
++ mxc_sdma_channel_params_t *chnl;
++ dma_channel_params *chnl_param;
++ mxc_dma_channel_t *chnl_info;
++ mxc_dma_channel_private_t *data_priv;
++ int ret;
++
++ chnl_info = &mxc_sdma_channels[arg];
++ data_priv = chnl_info->private;
++ chnl = mxc_sdma_get_channel_params(chnl_info->channel);
++ BUG_ON(chnl == NULL);
++ chnl_param = &chnl->chnl_params;
++
++ ret = mxc_dma_get_config(arg, &req, data_priv->buf_tail);
++ if (ret) {
++ DBG(0, "%s: Failed to get config for channel %ld buffer %u: %d\n",
++ __FUNCTION__, arg, data_priv->buf_tail, ret);
++ return;
++ }
++
++ DBG(0, "%s: dma_request %u: src: %08x dst: %08x done=%d cont=%d wrap=%d\n",
++ __FUNCTION__, data_priv->buf_tail, req.sourceAddr, req.destAddr,
++ req.bd_done, req.bd_cont, req.bd_wrap);
++
++ while (!req.bd_done) {
++ int error = MXC_DMA_DONE;
++ int bd_intr = mxc_dma_get_bd_intr(arg, data_priv->buf_tail);
++
++ if (bd_intr < 0) {
++ DBG(0, "%s: Failed to get bd_intr for channel %ld buffer %u: %d\n",
++ __FUNCTION__, arg, data_priv->buf_tail, ret);
++ return;
++ }
++
++ DBG(0, "%s: desc %u of %u\n", __FUNCTION__,
++ data_priv->buf_tail, chnl_param->bd_number);
++
++ if (!data_priv->circular || req.bd_error) {
++ DBG(0, "%s: Deactivating channel\n", __FUNCTION__);
++ chnl_info->active = 0;
++ }
++ if (req.bd_error) {
++ error = MXC_DMA_TRANSFER_ERROR;
++ }
++
++ DBG(0, "%s: bd_intr=%d\n", __FUNCTION__, bd_intr);
++ if (bd_intr) {
++ chnl_info->cb_fn(chnl_info->cb_args, error,
++ req.count);
++ }
++
++ if (data_priv->buf_tail == chnl_info->curr_buf) {
++ break;
++ }
++
++ ret = mxc_dma_set_config(arg, &req, data_priv->buf_tail);
++ if (ret) {
++ DBG(0, "%s: Failed to set config for channel %ld buffer %u: %d\n",
++ __FUNCTION__, arg, data_priv->buf_tail, ret);
++ return;
++ }
++
++ data_priv->buf_tail++;
++ if (data_priv->buf_tail >= chnl_param->bd_number || req.bd_wrap)
++ data_priv->buf_tail = 0;
++ memset(&req, 0, sizeof(req));
++ ret = mxc_dma_get_config(arg, &req, data_priv->buf_tail);
++ if (ret) {
++ DBG(0, "%s: Failed to get config for channel %ld buffer %u: %d\n",
++ __FUNCTION__, arg, data_priv->buf_tail, ret);
++ return;
++ }
++ DBG(0, "%s: dma_request %u: src: %08x dst: %08x done=%d cont=%d wrap=%d\n",
++ __FUNCTION__, data_priv->buf_tail, req.sourceAddr, req.destAddr,
++ req.bd_done, req.bd_cont, req.bd_wrap);
++ }
++}
++
++/*!
++ * This function is generally called by the driver at open time.
++ * The DMA driver would do any initialization steps that is required
++ * to get the channel ready for data transfer.
++ *
++ * @param channel_id a pre-defined id. The peripheral driver would specify
++ * the id associated with its peripheral. This would be
++ * used by the DMA driver to identify the peripheral
++ * requesting DMA and do the necessary setup on the
++ * channel associated with the particular peripheral.
++ * The DMA driver could use static or dynamic DMA channel
++ * allocation.
++ * @param dev_name module name or device name
++ * @return returns a negative number on error if request for a DMA channel did not
++ * succeed, returns the channel number to be used on success.
++ */
++int mxc_dma_request_ext(mxc_dma_device_t channel_id, char *dev_name,
++ struct dma_channel_info *info)
++{
++ mxc_sdma_channel_params_t *chnl;
++ mxc_dma_channel_private_t *data_priv;
++ int ret, i, channel_num;
++ mxc_sdma_channel_ext_params_t *p;
++
++ chnl = mxc_sdma_get_channel_params(channel_id);
++ if (chnl == NULL) {
++ return -EINVAL;
++ }
++
++ if (info) {
++ if (!chnl->chnl_params.ext)
++ return -EINVAL;
++ p = (mxc_sdma_channel_ext_params_t *)chnl;
++ memcpy(&p->chnl_ext_params.info, info, sizeof(info));
++ }
++
++ /* Enable the SDMA clock */
++ clk_enable(mxc_sdma_clk);
++
++ channel_num = chnl->channel_num;
++ if (chnl->channel_num == MXC_DMA_DYNAMIC_CHANNEL) {
++ ret = -EBUSY;
++ /* Get the first free channel */
++ for (i = MAX_DMA_CHANNELS - 1; i > 0; i--) {
++ /* See if channel is available */
++ if (!mxc_sdma_channels[i].dynamic ||
++ mxc_sdma_channels[i].lock) {
++ continue;
++ }
++ channel_num = i;
++ /* Check to see if we can get this channel */
++ ret = mxc_request_dma(&channel_num, dev_name);
++ if (ret == 0) {
++ break;
++ } else {
++ continue;
++ }
++ }
++ if (ret != 0) {
++ /* No free channel */
++ goto err_ret;
++ }
++ } else {
++ if (mxc_sdma_channels[chnl->channel_num].lock) {
++ ret = -EBUSY;
++ goto err_ret;
++ }
++ ret = mxc_request_dma(&channel_num, dev_name);
++ if (ret != 0) {
++ goto err_ret;
++ }
++ }
++
++ ret = mxc_dma_setup_channel(channel_num, &chnl->chnl_params);
++ if (ret != 0) {
++ DBG(0, "%s: Failed to setup DMA channel %d: %d\n", __FUNCTION__,
++ channel_num, ret);
++ goto err_free;
++ }
++ if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) {
++ ret = mxc_dma_set_channel_priority(channel_num,
++ chnl->chnl_priority);
++ if (ret != 0) {
++ pr_info("Failed to set channel prority, continuing with the existing priority\n");
++ }
++ }
++ mxc_sdma_channels[channel_num].lock = 1;
++ if ((chnl->chnl_params.transfer_type == per_2_emi) ||
++ (chnl->chnl_params.transfer_type == dsp_2_emi)) {
++ mxc_sdma_channels[channel_num].mode =
++ MXC_DMA_MODE_READ;
++ } else {
++ mxc_sdma_channels[channel_num].mode =
++ MXC_DMA_MODE_WRITE;
++ }
++ mxc_sdma_channels[channel_num].channel = channel_id;
++ data_priv = mxc_sdma_channels[channel_num].private;
++ tasklet_init(&data_priv->chnl_tasklet,
++ mxc_sdma_channeltasklet, channel_num);
++ if ((channel_id == MXC_DMA_ATA_RX) ||
++ (channel_id == MXC_DMA_ATA_TX)) {
++ data_priv->intr_after_every_bd = 0;
++ } else {
++ data_priv->intr_after_every_bd = 1;
++ }
++ return channel_num;
++
++err_free:
++ mxc_free_dma(channel_num);
++err_ret:
++ clk_disable(mxc_sdma_clk);
++ return ret;
++}
++
++/*!
++ * This function is generally called by the driver at close time. The DMA
++ * driver would do any cleanup associated with this channel.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++int mxc_dma_free(int channel_num)
++{
++ mxc_dma_channel_private_t *data_priv;
++
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) {
++ return -EINVAL;
++ }
++
++ if (!mxc_sdma_channels[channel_num].lock) {
++ return -EINVAL;
++ }
++
++ mxc_free_dma(channel_num);
++
++ /* Disable the SDMA clock */
++ clk_disable(mxc_sdma_clk);
++
++ mxc_sdma_channels[channel_num].lock = 0;
++ mxc_sdma_channels[channel_num].active = 0;
++ mxc_sdma_channels[channel_num].curr_buf = 0;
++ data_priv = mxc_sdma_channels[channel_num].private;
++ data_priv->buf_tail = 0;
++ tasklet_kill(&data_priv->chnl_tasklet);
++
++ return 0;
++}
++
++/*!
++ * Callback function called from the SDMA Interrupt routine
++ *
++ * @param arg driver specific argument that was registered
++ */
++static void mxc_dma_chnl_callback(void *arg)
++{
++ int channel;
++ mxc_dma_channel_private_t *data_priv;
++
++ channel = (int)arg;
++ DBG(0, "%s: channel %d\n", __FUNCTION__, channel);
++ data_priv = mxc_sdma_channels[channel].private;
++ /* Process the buffers in a tasklet */
++ tasklet_schedule(&data_priv->chnl_tasklet);
++}
++
++/*!
++ * This function would just configure the buffers specified by the user into
++ * dma channel. The caller must call mxc_dma_enable to start this transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param dma_buf an array of physical addresses to the user defined
++ * buffers. The caller must guarantee the dma_buf is
++ * available until the transfer is completed.
++ * @param num_buf number of buffers in the array
++ * @param mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer could not be
++ * added with DMA for transfer. On Success, it returns 0
++ */
++int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t *dma_buf,
++ int num_buf, mxc_dma_mode_t mode)
++{
++ int ret, i, prev_buf;
++ mxc_dma_channel_t *chnl_info;
++ mxc_dma_channel_private_t *data_priv;
++ mxc_sdma_channel_params_t *chnl;
++ dma_channel_params chnl_param;
++ dma_request_t req;
++
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0))
++ return -EINVAL;
++
++ if (num_buf <= 0)
++ return -EINVAL;
++
++ chnl_info = &mxc_sdma_channels[channel_num];
++ data_priv = chnl_info->private;
++ if (chnl_info->lock != 1)
++ return -ENODEV;
++
++ /* Check to see if all buffers are taken */
++ if (chnl_info->active)
++ return -EBUSY;
++
++ chnl = mxc_sdma_get_channel_params(chnl_info->channel);
++ chnl_param = chnl->chnl_params;
++
++ /* Re-setup the SDMA channel if the transfer direction or
++ * the number of assigned BDs is changed
++ */
++ if (chnl_param.peripheral_type != MEMORY &&
++ mode != chnl_info->mode) {
++
++ if (chnl_param.bd_number != num_buf)
++ DBG(0, "%s: Changing number of BDs for channel %u from %u to %u\n", __FUNCTION__,
++ channel_num, chnl_param.bd_number, num_buf);
++
++ chnl_param.bd_number = num_buf;
++ if (chnl_param.peripheral_type == DSP) {
++ if (mode == MXC_DMA_MODE_READ)
++ chnl_param.transfer_type = dsp_2_emi;
++ else
++ chnl_param.transfer_type = emi_2_dsp;
++ } else if (chnl_param.peripheral_type == FIFO_MEMORY) {
++ if (mode == MXC_DMA_MODE_READ)
++ chnl_param.per_address =
++ MXC_FIFO_MEM_SRC_FIXED;
++ else
++ chnl_param.per_address =
++ MXC_FIFO_MEM_DEST_FIXED;
++ } else {
++ if (mode == MXC_DMA_MODE_READ)
++ chnl_param.transfer_type = per_2_emi;
++ else
++ chnl_param.transfer_type = emi_2_per;
++ }
++ chnl_param.callback = mxc_dma_chnl_callback;
++ chnl_param.arg = (void *)channel_num;
++ ret = mxc_dma_setup_channel(channel_num, &chnl_param);
++ if (ret != 0)
++ return ret;
++
++ if (chnl->chnl_priority != MXC_SDMA_DEFAULT_PRIORITY) {
++ ret = mxc_dma_set_channel_priority(channel_num,
++ chnl->chnl_priority);
++ if (ret != 0) {
++ pr_info("Failed to set channel prority, continuing with the existing priority\n");
++ }
++ }
++ chnl_info->mode = mode;
++ }
++
++ for (i = 0; i < num_buf; i++, dma_buf++) {
++ memset(&req, 0, sizeof(req));
++ /* Check to see if all buffers are taken */
++ if (chnl_info->active) {
++ DBG(0, "%s: bd %u is already active\n",
++ __FUNCTION__, i);
++ break;
++ }
++ req.destAddr = dma_buf->dst_addr;
++ req.sourceAddr = dma_buf->src_addr;
++ if (chnl_param.peripheral_type == ASRC)
++ req.count = dma_buf->num_of_bytes / 4;
++ else
++ req.count = dma_buf->num_of_bytes;
++ req.bd_cont = 1;
++ if (data_priv->circular && i == num_buf - 1) {
++ DBG(0, "%s: Setting bd_wrap for desc[%d/%d]\n",
++ __FUNCTION__, i, num_buf);
++ req.bd_wrap = 1;
++ }
++ ret = mxc_dma_set_config(channel_num, &req,
++ chnl_info->curr_buf);
++ if (ret != 0) {
++ DBG(0, "%s: Failed to configure DMA: %d\n",
++ __FUNCTION__, ret);
++ return ret;
++ }
++ if (data_priv->intr_after_every_bd ||
++ (i == num_buf - 1)) {
++ mxc_dma_set_bd_intr(channel_num,
++ chnl_info->curr_buf, 1);
++ } else {
++ mxc_dma_set_bd_intr(channel_num,
++ chnl_info->curr_buf, 0);
++ }
++
++ prev_buf = chnl_info->curr_buf;
++ chnl_info->curr_buf++;
++ if (chnl_info->curr_buf >= chnl_param.bd_number) {
++ chnl_info->curr_buf = 0;
++ }
++ if (chnl_info->curr_buf == data_priv->buf_tail) {
++ if (!(data_priv->intr_after_every_bd) &&
++ (i != num_buf - 1)) {
++ /*
++ * Set the BD_INTR flag on the last BD that
++ * was queued
++ */
++ mxc_dma_set_bd_intr(channel_num, prev_buf, 1);
++ }
++ chnl_info->active = 1;
++ }
++ }
++
++ if (i == 0) {
++ return -EBUSY;
++ }
++ return 0;
++}
++
++/*!
++ * This function would just configure the scatterlist specified by the
++ * user into dma channel. This is a slight variation of mxc_dma_config(),
++ * it is provided for the convenience of drivers that have a scatterlist
++ * passed into them. It is the calling driver's responsibility to have the
++ * correct physical address filled in the "dma_address" field of the
++ * scatterlist.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param sg a scatterlist of buffers. The caller must guarantee
++ * the dma_buf is available until the transfer is
++ * completed.
++ * @param num_buf number of buffers in the array
++ * @param num_of_bytes total number of bytes to transfer. If set to 0, this
++ * would imply to use the length field of the scatterlist
++ * for each DMA transfer. Else it would calculate the size
++ * for each DMA transfer.
++ * @param mode specifies whether this is READ or WRITE operation
++ * @return This function returns a negative number on error if buffer could not
++ * be added with DMA for transfer. On Success, it returns 0
++ */
++int mxc_dma_sg_config(int channel_num, struct scatterlist *sg,
++ int num_buf, int num_of_bytes, mxc_dma_mode_t mode)
++{
++ int ret, i;
++ mxc_dma_requestbuf_t *dma_buf;
++ gfp_t gfp_flags = in_atomic() ? GFP_ATOMIC : GFP_KERNEL;
++ mxc_dma_channel_t *chnl_info;
++ mxc_dma_channel_private_t *data_priv;
++
++ DBG(0, "%s: chan %d %u buffers with %u bytes\n", __FUNCTION__,
++ channel_num, num_buf, num_of_bytes);
++
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) {
++ return -EINVAL;
++ }
++
++ if (!mxc_sdma_channels[channel_num].lock) {
++ return -EINVAL;
++ }
++
++ dma_buf = kmalloc(num_buf * sizeof(mxc_dma_requestbuf_t),
++ gfp_flags);
++ if (dma_buf == NULL) {
++ return -ENOMEM;
++ }
++
++ chnl_info = &mxc_sdma_channels[channel_num];
++ data_priv = chnl_info->private;
++ data_priv->intr_after_every_bd = 1;
++ data_priv->circular = 1;
++
++ for (i = 0; i < num_buf; i++) {
++ if (mode == MXC_DMA_MODE_READ) {
++ dma_buf[i].dst_addr = sg->dma_address;
++ dma_buf[i].src_addr = DMA_ADDR_INVALID;
++ } else {
++ dma_buf[i].dst_addr = DMA_ADDR_INVALID;
++ dma_buf[i].src_addr = sg->dma_address;
++ }
++
++ if ((num_of_bytes > sg->length) || (num_of_bytes == 0)) {
++ dma_buf[i].num_of_bytes = sg->length;
++ } else {
++ dma_buf[i].num_of_bytes = num_of_bytes;
++ }
++ sg = sg_next(sg);
++ if (num_of_bytes != 0)
++ num_of_bytes -= dma_buf[i].num_of_bytes;
++ DBG(0, "%s: desc[%d/%d] src: %08x dst: %08x len: %08x\n",
++ __FUNCTION__, i, num_buf, dma_buf[i].src_addr, dma_buf[i].dst_addr,
++ dma_buf[i].num_of_bytes);
++ }
++
++ ret = mxc_dma_config(channel_num, dma_buf, num_buf, mode);
++ kfree(dma_buf);
++ return ret;
++}
++
++/*!
++ * This function is provided if the driver would like to set/change its
++ * callback function.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @param callback a callback function to provide notification on transfer
++ * completion, user could specify NULL if he does not wish
++ * to be notified
++ * @param arg an argument that gets passed in to the callback
++ * function, used by the user to do any driver specific
++ * operations.
++ * @return this function returns a negative number on error if the callback
++ * could not be set for the channel or 0 on success
++ */
++int mxc_dma_callback_set(int channel_num,
++ mxc_dma_callback_t callback, void *arg)
++{
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) {
++ return -EINVAL;
++ }
++
++ if (!mxc_sdma_channels[channel_num].lock) {
++ return -EINVAL;
++ }
++
++ mxc_sdma_channels[channel_num].cb_fn = callback;
++ mxc_sdma_channels[channel_num].cb_args = arg;
++
++ mxc_dma_set_callback(channel_num, mxc_dma_chnl_callback,
++ (void *)channel_num);
++
++ return 0;
++}
++
++/*!
++ * This stops the DMA channel and any ongoing transfers. Subsequent use of
++ * mxc_dma_enable() will restart the channel and restart the transfer.
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++int mxc_dma_disable(int channel_num)
++{
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) {
++ return -EINVAL;
++ }
++
++ if (!mxc_sdma_channels[channel_num].lock) {
++ return -EINVAL;
++ }
++
++ mxc_dma_stop(channel_num);
++ return 0;
++}
++
++/*!
++ * This starts DMA transfer. Or it restarts DMA on a stopped channel
++ * previously stopped with mxc_dma_disable().
++ *
++ * @param channel_num the channel number returned at request time. This
++ * would be used by the DMA driver to identify the calling
++ * driver and do the necessary cleanup on the channel
++ * associated with the particular peripheral
++ * @return returns a negative number on error or 0 on success
++ */
++int mxc_dma_enable(int channel_num)
++{
++ if ((channel_num >= MAX_DMA_CHANNELS) || (channel_num < 0)) {
++ return -EINVAL;
++ }
++
++ if (!mxc_sdma_channels[channel_num].lock) {
++ return -EINVAL;
++ }
++
++ mxc_dma_start(channel_num);
++ return 0;
++}
++
++/*!
++ * Initializes dma structure with dma_operations
++ *
++ * @param dma dma structure
++ * @return returns 0 on success
++ */
++static int __init mxc_dma_init(void)
++{
++ int i;
++
++ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
++ mxc_sdma_channels[i].active = 0;
++ mxc_sdma_channels[i].lock = 0;
++ mxc_sdma_channels[i].curr_buf = 0;
++ mxc_sdma_channels[i].dynamic = 1;
++ mxc_sdma_private[i].buf_tail = 0;
++ mxc_sdma_channels[i].private = &mxc_sdma_private[i];
++ }
++ /*
++ * Make statically allocated channels unavailable for dynamic channel
++ * requests
++ */
++ mxc_get_static_channels(mxc_sdma_channels);
++
++ return 0;
++}
++
++arch_initcall(mxc_dma_init);
++
++#else
++int mxc_request_dma(int *channel, const char *devicename)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_setup_channel(int channel, dma_channel_params * p)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_set_config(int channel, dma_request_t * p, int bd_index)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_get_config(int channel, dma_request_t * p, int bd_index)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_start(int channel)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_stop(int channel)
++{
++ return -ENODEV;
++}
++
++void mxc_free_dma(int channel)
++{
++}
++
++void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg)
++{
++}
++
++void *sdma_malloc(size_t size)
++{
++ return NULL;
++}
++
++void sdma_free(void *buf)
++{
++}
++
++void *sdma_phys_to_virt(dma_addr_t buf)
++{
++ return NULL;
++}
++
++dma_addr_t sdma_virt_to_phys(void *buf)
++{
++ return DMA_ADDR_INVALID;
++}
++
++int mxc_dma_request(mxc_dma_device_t channel_id, char *dev_name)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_free(int channel_num)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_config(int channel_num, mxc_dma_requestbuf_t * dma_buf,
++ int num_buf, mxc_dma_mode_t mode)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_sg_config(int channel_num, struct scatterlist *sg,
++ int num_buf, int num_of_bytes, mxc_dma_mode_t mode)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_callback_set(int channel_num, mxc_dma_callback_t callback,
++ void *arg)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_disable(int channel_num)
++{
++ return -ENODEV;
++}
++
++int mxc_dma_enable(int channel_num)
++{
++ return -ENODEV;
++}
++
++EXPORT_SYMBOL(mxc_request_dma);
++EXPORT_SYMBOL(mxc_dma_setup_channel);
++EXPORT_SYMBOL(mxc_dma_set_channel_priority);
++EXPORT_SYMBOL(mxc_dma_set_config);
++EXPORT_SYMBOL(mxc_dma_get_config);
++EXPORT_SYMBOL(mxc_dma_start);
++EXPORT_SYMBOL(mxc_dma_stop);
++EXPORT_SYMBOL(mxc_free_dma);
++EXPORT_SYMBOL(mxc_dma_set_callback);
++EXPORT_SYMBOL(sdma_malloc);
++EXPORT_SYMBOL(sdma_free);
++EXPORT_SYMBOL(sdma_phys_to_virt);
++EXPORT_SYMBOL(sdma_virt_to_phys);
++
++#endif
++
++EXPORT_SYMBOL(mxc_dma_request_ext);
++EXPORT_SYMBOL(mxc_dma_free);
++EXPORT_SYMBOL(mxc_dma_config);
++EXPORT_SYMBOL(mxc_dma_sg_config);
++EXPORT_SYMBOL(mxc_dma_callback_set);
++EXPORT_SYMBOL(mxc_dma_disable);
++EXPORT_SYMBOL(mxc_dma_enable);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC Linux SDMA API");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/epm.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/epm.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/epm.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/epm.h 2010-12-03 09:51:55.384181534 +0100
+@@ -0,0 +1,254 @@
++/*
++ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#ifndef __ASM_ARCH_MXC_SDMA_REGS_H__
++#define __ASM_ARCH_MXC_SDMA_REGS_H__
++
++#ifdef DEBUG
++#ifdef CONFIG_MACH_TX25
++extern int tx25_debug;
++#define dbg_lvl(n) ((n) < tx25_debug)
++#elif defined(CONFIG_MACH_TX51)
++extern int tx51_debug;
++#define dbg_lvl(n) ((n) < tx51_debug)
++#else
++#error No debug support for this machine
++#endif
++#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++#define dbg_lvl(n) 0
++#define DBG(lvl, fmt...) do { } while (0)
++#endif
++
++#ifdef __KERNEL__
++#include <linux/kernel.h>
++#include <linux/bug.h>
++#include <linux/io.h>
++#include <asm/memory.h>
++#endif
++
++#include <linux/compiler.h>
++#include <mach/hardware.h>
++
++/* SDMA Reg definition */
++extern void __iomem *sdma_base_addr;
++#define SDMA_BASE_IO_ADDR sdma_base_addr
++
++#ifdef DEBUG
++#define __sdma_pa(a) ((a) - SDMA_BASE_IO_ADDR + SDMA_BASE_ADDR)
++
++static inline u32 iapi_raw_readl(void __iomem *addr,
++ const char *name, const char *fn)
++{
++ u32 val;
++
++ DBG(1, "%s: Reading %s[%08lx]\n", fn,
++ name, __sdma_pa(addr));
++ val = __raw_readl(addr);
++ DBG(0, "%s: Read %08x from %s[%08lx]\n", fn,
++ val, name, __sdma_pa(addr));
++ return val;
++}
++
++static inline void iapi_raw_writel(u32 val, void __iomem *addr,
++ const char *name, const char *fn)
++{
++ DBG(0, "%s: Writing %08x to %s[%08lx]\n", fn,
++ val, name, __sdma_pa(addr));
++ __raw_writel(val, addr);
++
++}
++
++#undef __raw_writel
++#undef __raw_readl
++
++#define __raw_readl(a) iapi_raw_readl(a, #a, __func__)
++#define __raw_writel(v, a) iapi_raw_writel(v, a, #a, __func__)
++#endif
++
++#define __REG32(base, offs) ((base) + (offs))
++#define __REG_ARRAY(base, offs, num, index) ({ \
++ BUG_ON((unsigned int)(index) >= (num)); \
++ __REG32(base, (offs) + ((index) << 2)); \
++})
++
++#define SDMA_H_C0PTR __REG32(SDMA_BASE_IO_ADDR, 0x000)
++#define SDMA_H_INTR __REG32(SDMA_BASE_IO_ADDR, 0x004)
++#define SDMA_H_STATSTOP __REG32(SDMA_BASE_IO_ADDR, 0x008)
++#define SDMA_H_START __REG32(SDMA_BASE_IO_ADDR, 0x00C)
++#define SDMA_H_EVTOVR __REG32(SDMA_BASE_IO_ADDR, 0x010)
++#define SDMA_H_DSPOVR __REG32(SDMA_BASE_IO_ADDR, 0x014)
++#define SDMA_H_HOSTOVR __REG32(SDMA_BASE_IO_ADDR, 0x018)
++#define SDMA_H_EVTPEND __REG32(SDMA_BASE_IO_ADDR, 0x01C)
++#define SDMA_H_DSPENBL __REG32(SDMA_BASE_IO_ADDR, 0x020)
++#define SDMA_H_RESET __REG32(SDMA_BASE_IO_ADDR, 0x024)
++#define SDMA_H_EVTERR __REG32(SDMA_BASE_IO_ADDR, 0x028)
++#define SDMA_H_INTRMSK __REG32(SDMA_BASE_IO_ADDR, 0x02C)
++#define SDMA_H_PSW __REG32(SDMA_BASE_IO_ADDR, 0x030)
++#define SDMA_H_EVTERRDBG __REG32(SDMA_BASE_IO_ADDR, 0x034)
++#define SDMA_H_CONFIG __REG32(SDMA_BASE_IO_ADDR, 0x038)
++#define SDMA_SDMA_LOCK __REG32(SDMA_BASE_IO_ADDR, 0x03C)
++#define SDMA_ONCE_ENB __REG32(SDMA_BASE_IO_ADDR, 0x040)
++#define SDMA_ONCE_DATA __REG32(SDMA_BASE_IO_ADDR, 0x044)
++#define SDMA_ONCE_INSTR __REG32(SDMA_BASE_IO_ADDR, 0x048)
++#define SDMA_ONCE_STAT __REG32(SDMA_BASE_IO_ADDR, 0x04C)
++#define SDMA_ONCE_CMD __REG32(SDMA_BASE_IO_ADDR, 0x050)
++#define SDMA_EVT_MIRROR __REG32(SDMA_BASE_IO_ADDR, 0x054)
++#define SDMA_ILLINSTADDR __REG32(SDMA_BASE_IO_ADDR, 0x058)
++#define SDMA_CHN0ADDR __REG32(SDMA_BASE_IO_ADDR, 0x05C)
++#define SDMA_ONCE_RTB __REG32(SDMA_BASE_IO_ADDR, 0x060)
++#define SDMA_XTRIG_CONF1 __REG32(SDMA_BASE_IO_ADDR, 0x070)
++#define SDMA_XTRIG_CONF2 __REG32(SDMA_BASE_IO_ADDR, 0x074)
++
++#ifdef SDMA_V2
++#define SDMA_CHNENBL(i) __REG_ARRAY(SDMA_BASE_IO_ADDR, 0x200, 48, i)
++#define SDMA_CHNENBL_0 __REG32(SDMA_BASE_IO_ADDR, 0x200)
++#define SDMA_CHNENBL_1 __REG32(SDMA_BASE_IO_ADDR, 0x204)
++#define SDMA_CHNENBL_2 __REG32(SDMA_BASE_IO_ADDR, 0x208)
++#define SDMA_CHNENBL_3 __REG32(SDMA_BASE_IO_ADDR, 0x20C)
++#define SDMA_CHNENBL_4 __REG32(SDMA_BASE_IO_ADDR, 0x210)
++#define SDMA_CHNENBL_5 __REG32(SDMA_BASE_IO_ADDR, 0x214)
++#define SDMA_CHNENBL_6 __REG32(SDMA_BASE_IO_ADDR, 0x218)
++#define SDMA_CHNENBL_7 __REG32(SDMA_BASE_IO_ADDR, 0x21C)
++#define SDMA_CHNENBL_8 __REG32(SDMA_BASE_IO_ADDR, 0x220)
++#define SDMA_CHNENBL_9 __REG32(SDMA_BASE_IO_ADDR, 0x224)
++#define SDMA_CHNENBL_10 __REG32(SDMA_BASE_IO_ADDR, 0x228)
++#define SDMA_CHNENBL_11 __REG32(SDMA_BASE_IO_ADDR, 0x22C)
++#define SDMA_CHNENBL_12 __REG32(SDMA_BASE_IO_ADDR, 0x230)
++#define SDMA_CHNENBL_13 __REG32(SDMA_BASE_IO_ADDR, 0x234)
++#define SDMA_CHNENBL_14 __REG32(SDMA_BASE_IO_ADDR, 0x238)
++#define SDMA_CHNENBL_15 __REG32(SDMA_BASE_IO_ADDR, 0x23C)
++#define SDMA_CHNENBL_16 __REG32(SDMA_BASE_IO_ADDR, 0x240)
++#define SDMA_CHNENBL_17 __REG32(SDMA_BASE_IO_ADDR, 0x244)
++#define SDMA_CHNENBL_18 __REG32(SDMA_BASE_IO_ADDR, 0x248)
++#define SDMA_CHNENBL_19 __REG32(SDMA_BASE_IO_ADDR, 0x24C)
++#define SDMA_CHNENBL_20 __REG32(SDMA_BASE_IO_ADDR, 0x250)
++#define SDMA_CHNENBL_21 __REG32(SDMA_BASE_IO_ADDR, 0x254)
++#define SDMA_CHNENBL_22 __REG32(SDMA_BASE_IO_ADDR, 0x258)
++#define SDMA_CHNENBL_23 __REG32(SDMA_BASE_IO_ADDR, 0x25C)
++#define SDMA_CHNENBL_24 __REG32(SDMA_BASE_IO_ADDR, 0x260)
++#define SDMA_CHNENBL_25 __REG32(SDMA_BASE_IO_ADDR, 0x264)
++#define SDMA_CHNENBL_26 __REG32(SDMA_BASE_IO_ADDR, 0x268)
++#define SDMA_CHNENBL_27 __REG32(SDMA_BASE_IO_ADDR, 0x26C)
++#define SDMA_CHNENBL_28 __REG32(SDMA_BASE_IO_ADDR, 0x270)
++#define SDMA_CHNENBL_29 __REG32(SDMA_BASE_IO_ADDR, 0x274)
++#define SDMA_CHNENBL_30 __REG32(SDMA_BASE_IO_ADDR, 0x278)
++#define SDMA_CHNENBL_31 __REG32(SDMA_BASE_IO_ADDR, 0x27C)
++#define SDMA_CHNENBL_32 __REG32(SDMA_BASE_IO_ADDR, 0x280)
++#define SDMA_CHNENBL_33 __REG32(SDMA_BASE_IO_ADDR, 0x284)
++#define SDMA_CHNENBL_34 __REG32(SDMA_BASE_IO_ADDR, 0x288)
++#define SDMA_CHNENBL_35 __REG32(SDMA_BASE_IO_ADDR, 0x28C)
++#define SDMA_CHNENBL_36 __REG32(SDMA_BASE_IO_ADDR, 0x290)
++#define SDMA_CHNENBL_37 __REG32(SDMA_BASE_IO_ADDR, 0x294)
++#define SDMA_CHNENBL_38 __REG32(SDMA_BASE_IO_ADDR, 0x298)
++#define SDMA_CHNENBL_39 __REG32(SDMA_BASE_IO_ADDR, 0x29C)
++#define SDMA_CHNENBL_40 __REG32(SDMA_BASE_IO_ADDR, 0x2A0)
++#define SDMA_CHNENBL_41 __REG32(SDMA_BASE_IO_ADDR, 0x2A4)
++#define SDMA_CHNENBL_42 __REG32(SDMA_BASE_IO_ADDR, 0x2A8)
++#define SDMA_CHNENBL_43 __REG32(SDMA_BASE_IO_ADDR, 0x2AC)
++#define SDMA_CHNENBL_44 __REG32(SDMA_BASE_IO_ADDR, 0x2B0)
++#define SDMA_CHNENBL_45 __REG32(SDMA_BASE_IO_ADDR, 0x2B4)
++#define SDMA_CHNENBL_46 __REG32(SDMA_BASE_IO_ADDR, 0x2B8)
++#define SDMA_CHNENBL_47 __REG32(SDMA_BASE_IO_ADDR, 0x2BC)
++
++#define SDMA_ONCE_COUNT __REG32(SDMA_BASE_IO_ADDR, 0x300)
++#define SDMA_ONCE_ECTL __REG32(SDMA_BASE_IO_ADDR, 0x304)
++#define SDMA_ONCE_EAA __REG32(SDMA_BASE_IO_ADDR, 0x308)
++#define SDMA_ONCE_EAB __REG32(SDMA_BASE_IO_ADDR, 0x30C)
++#define SDMA_ONCE_EAM __REG32(SDMA_BASE_IO_ADDR, 0x310)
++#define SDMA_ONCE_ED __REG32(SDMA_BASE_IO_ADDR, 0x314)
++#define SDMA_ONCE_EDM __REG32(SDMA_BASE_IO_ADDR, 0x318)
++#define SDMA_ONCE_PCMATCH __REG32(SDMA_BASE_IO_ADDR, 0x31C)
++
++#else
++
++#define SDMA_CHNENBL(i) __REG_ARRAY(SDMA_BASE_IO_ADDR, 0x80, 32, i)
++#define SDMA_CHNENBL_0 __REG32(SDMA_BASE_IO_ADDR, 0x080)
++#define SDMA_CHNENBL_1 __REG32(SDMA_BASE_IO_ADDR, 0x084)
++#define SDMA_CHNENBL_2 __REG32(SDMA_BASE_IO_ADDR, 0x088)
++#define SDMA_CHNENBL_3 __REG32(SDMA_BASE_IO_ADDR, 0x08C)
++#define SDMA_CHNENBL_4 __REG32(SDMA_BASE_IO_ADDR, 0x090)
++#define SDMA_CHNENBL_5 __REG32(SDMA_BASE_IO_ADDR, 0x094)
++#define SDMA_CHNENBL_6 __REG32(SDMA_BASE_IO_ADDR, 0x098)
++#define SDMA_CHNENBL_7 __REG32(SDMA_BASE_IO_ADDR, 0x09C)
++#define SDMA_CHNENBL_8 __REG32(SDMA_BASE_IO_ADDR, 0x0A0)
++#define SDMA_CHNENBL_9 __REG32(SDMA_BASE_IO_ADDR, 0x0A4)
++#define SDMA_CHNENBL_10 __REG32(SDMA_BASE_IO_ADDR, 0x0A8)
++#define SDMA_CHNENBL_11 __REG32(SDMA_BASE_IO_ADDR, 0x0AC)
++#define SDMA_CHNENBL_12 __REG32(SDMA_BASE_IO_ADDR, 0x0B0)
++#define SDMA_CHNENBL_13 __REG32(SDMA_BASE_IO_ADDR, 0x0B4)
++#define SDMA_CHNENBL_14 __REG32(SDMA_BASE_IO_ADDR, 0x0B8)
++#define SDMA_CHNENBL_15 __REG32(SDMA_BASE_IO_ADDR, 0x0BC)
++#define SDMA_CHNENBL_16 __REG32(SDMA_BASE_IO_ADDR, 0x0C0)
++#define SDMA_CHNENBL_17 __REG32(SDMA_BASE_IO_ADDR, 0x0C4)
++#define SDMA_CHNENBL_18 __REG32(SDMA_BASE_IO_ADDR, 0x0C8)
++#define SDMA_CHNENBL_19 __REG32(SDMA_BASE_IO_ADDR, 0x0CC)
++#define SDMA_CHNENBL_20 __REG32(SDMA_BASE_IO_ADDR, 0x0D0)
++#define SDMA_CHNENBL_21 __REG32(SDMA_BASE_IO_ADDR, 0x0D4)
++#define SDMA_CHNENBL_22 __REG32(SDMA_BASE_IO_ADDR, 0x0D8)
++#define SDMA_CHNENBL_23 __REG32(SDMA_BASE_IO_ADDR, 0x0DC)
++#define SDMA_CHNENBL_24 __REG32(SDMA_BASE_IO_ADDR, 0x0E0)
++#define SDMA_CHNENBL_25 __REG32(SDMA_BASE_IO_ADDR, 0x0E4)
++#define SDMA_CHNENBL_26 __REG32(SDMA_BASE_IO_ADDR, 0x0E8)
++#define SDMA_CHNENBL_27 __REG32(SDMA_BASE_IO_ADDR, 0x0EC)
++#define SDMA_CHNENBL_28 __REG32(SDMA_BASE_IO_ADDR, 0x0F0)
++#define SDMA_CHNENBL_29 __REG32(SDMA_BASE_IO_ADDR, 0x0F4)
++#define SDMA_CHNENBL_30 __REG32(SDMA_BASE_IO_ADDR, 0x0F8)
++#define SDMA_CHNENBL_31 __REG32(SDMA_BASE_IO_ADDR, 0x0FC)
++
++#define SDMA_ONCE_COUNT __REG32(SDMA_BASE_IO_ADDR, 0x200)
++#define SDMA_ONCE_ECTL __REG32(SDMA_BASE_IO_ADDR, 0x204)
++#define SDMA_ONCE_EAA __REG32(SDMA_BASE_IO_ADDR, 0x208)
++#define SDMA_ONCE_EAB __REG32(SDMA_BASE_IO_ADDR, 0x20C)
++#define SDMA_ONCE_EAM __REG32(SDMA_BASE_IO_ADDR, 0x210)
++#define SDMA_ONCE_ED __REG32(SDMA_BASE_IO_ADDR, 0x214)
++#define SDMA_ONCE_EDM __REG32(SDMA_BASE_IO_ADDR, 0x218)
++#define SDMA_ONCE_PCMATCH __REG32(SDMA_BASE_IO_ADDR, 0x21C)
++
++#endif /* SDMA_V2 */
++
++#define SDMA_CHNPRI(i) __REG_ARRAY(SDMA_BASE_IO_ADDR, 0x100, 32, i)
++#define SDMA_CHNPRI_0 __REG32(SDMA_BASE_IO_ADDR, 0x100)
++#define SDMA_CHNPRI_1 __REG32(SDMA_BASE_IO_ADDR, 0x104)
++#define SDMA_CHNPRI_2 __REG32(SDMA_BASE_IO_ADDR, 0x108)
++#define SDMA_CHNPRI_3 __REG32(SDMA_BASE_IO_ADDR, 0x10C)
++#define SDMA_CHNPRI_4 __REG32(SDMA_BASE_IO_ADDR, 0x110)
++#define SDMA_CHNPRI_5 __REG32(SDMA_BASE_IO_ADDR, 0x114)
++#define SDMA_CHNPRI_6 __REG32(SDMA_BASE_IO_ADDR, 0x118)
++#define SDMA_CHNPRI_7 __REG32(SDMA_BASE_IO_ADDR, 0x11C)
++#define SDMA_CHNPRI_8 __REG32(SDMA_BASE_IO_ADDR, 0x120)
++#define SDMA_CHNPRI_9 __REG32(SDMA_BASE_IO_ADDR, 0x124)
++#define SDMA_CHNPRI_10 __REG32(SDMA_BASE_IO_ADDR, 0x128)
++#define SDMA_CHNPRI_11 __REG32(SDMA_BASE_IO_ADDR, 0x12C)
++#define SDMA_CHNPRI_12 __REG32(SDMA_BASE_IO_ADDR, 0x130)
++#define SDMA_CHNPRI_13 __REG32(SDMA_BASE_IO_ADDR, 0x134)
++#define SDMA_CHNPRI_14 __REG32(SDMA_BASE_IO_ADDR, 0x138)
++#define SDMA_CHNPRI_15 __REG32(SDMA_BASE_IO_ADDR, 0x13C)
++#define SDMA_CHNPRI_16 __REG32(SDMA_BASE_IO_ADDR, 0x140)
++#define SDMA_CHNPRI_17 __REG32(SDMA_BASE_IO_ADDR, 0x144)
++#define SDMA_CHNPRI_18 __REG32(SDMA_BASE_IO_ADDR, 0x148)
++#define SDMA_CHNPRI_19 __REG32(SDMA_BASE_IO_ADDR, 0x14C)
++#define SDMA_CHNPRI_20 __REG32(SDMA_BASE_IO_ADDR, 0x150)
++#define SDMA_CHNPRI_21 __REG32(SDMA_BASE_IO_ADDR, 0x154)
++#define SDMA_CHNPRI_22 __REG32(SDMA_BASE_IO_ADDR, 0x158)
++#define SDMA_CHNPRI_23 __REG32(SDMA_BASE_IO_ADDR, 0x15C)
++#define SDMA_CHNPRI_24 __REG32(SDMA_BASE_IO_ADDR, 0x160)
++#define SDMA_CHNPRI_25 __REG32(SDMA_BASE_IO_ADDR, 0x164)
++#define SDMA_CHNPRI_26 __REG32(SDMA_BASE_IO_ADDR, 0x168)
++#define SDMA_CHNPRI_27 __REG32(SDMA_BASE_IO_ADDR, 0x16C)
++#define SDMA_CHNPRI_28 __REG32(SDMA_BASE_IO_ADDR, 0x170)
++#define SDMA_CHNPRI_29 __REG32(SDMA_BASE_IO_ADDR, 0x174)
++#define SDMA_CHNPRI_30 __REG32(SDMA_BASE_IO_ADDR, 0x178)
++#define SDMA_CHNPRI_31 __REG32(SDMA_BASE_IO_ADDR, 0x17C)
++
++#endif /* _mcuEpm_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiDefaults.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,131 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiDefaults.h
++ *
++ * $Id iapiDefaults.h $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ *
++ *
++ *
++ *
++ * $Log iapiDefaults.h $
++ *
++ *****************************************************************************/
++
++
++#ifndef _iapi_defaults_h
++#define _iapi_defaults_h
++
++/******************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include "sdmaStruct.h"
++
++/* ****************************************************************************
++ * Macro-command Section
++ * ***************************************************************************/
++
++/**
++ * Error codes
++ * lower 5 bits free to include channel number when available
++ * and bit number 6 must be set when channel number is available
++ *
++ * Note :
++ * 1) Abbreviations / naming convention :
++ * - BD : Buffer Descriptor
++ * - CC : Channel Context
++ * - CCB : Channel Control Block
++ * - CD : Channel Descriptor
++ * - B : Buffer
++ * - CH : Channel
++ *
++ */
++#define IAPI_SUCCESS 0
++#define IAPI_FAILURE (-1)
++#define IAPI_ERR_CH_AVAILABLE 0x00020
++#define IAPI_ERR_NO_ERROR 0x00000
++#define IAPI_ERR_NO_CCB_DEFINED 0x01000
++#define IAPI_ERR_BD_UNINITIALIZED 0x02000
++#define IAPI_ERR_BD_ALLOCATED 0x03000
++#define IAPI_ERR_BD_ALLOCATION 0x04000
++#define IAPI_ERR_CCB_ALLOC_FAILED 0x05000
++#define IAPI_ERR_CCB_UNINITIALIZED 0x06000
++#define IAPI_ERR_CC_ALREADY_DEFINED 0x07000
++#define IAPI_ERR_CC_ALLOC_FAILED 0x08000
++#define IAPI_ERR_CD_ALREADY_DEFINED 0x09000
++#define IAPI_ERR_CD_ALLOC_FAILED 0x0A000
++#define IAPI_ERR_CD_CHANGE_CH_NUMBER 0x0B000
++#define IAPI_ERR_CD_CHANGE_CCB_PTR 0x0C000
++#define IAPI_ERR_CD_CHANGE_UNKNOWN 0x0D000
++#define IAPI_ERR_CD_CHANGE 0x0E000
++#define IAPI_ERR_CD_UNINITIALIZED 0x0F000
++#define IAPI_ERR_CLOSE 0x10000
++#define IAPI_ERR_B_ALLOC_FAILED 0x11000
++#define IAPI_ERR_CONFIG_OVERRIDE 0x12000
++#define IAPI_ERR_CH_IN_USE 0x13000
++#define IAPI_ERR_CALLBACKSYNCH_UNKNOWN 0x14000
++#define IAPI_ERR_INVALID_PARAMETER 0x15000
++#define IAPI_ERR_TRUST 0x16000
++#define IAPI_ERR_CHANNEL_UNINITIALIZED 0x17000
++#define IAPI_ERR_RROR_BIT_READ 0x18000
++#define IAPI_ERR_RROR_BIT_WRITE 0x19000
++#define IAPI_ERR_NOT_ALLOWED 0x1A000
++#define IAPI_ERR_NO_OS_FN 0x1B000
++
++
++/*
++ * Global Variable Section
++ */
++
++/*
++ * Table to hold pointers to the callback functions registered by the users of
++ *I.API
++ */
++extern void (*callbackIsrTable[CH_NUM])(channelDescriptor *cd_p, void *arg);
++
++/*
++ * Table to hold user registered data pointers, to be privided in the callback
++ *function
++ */
++extern void *userArgTable[CH_NUM];
++
++/* channelDescriptor data structure filled with default data*/
++extern channelDescriptor iapi_ChannelDefaults;
++
++/* Global variable to hold the last error encountered in I.API operations*/
++extern int iapi_errno;
++
++/* Used in synchronization, to mark started channels*/
++extern volatile unsigned long iapi_SDMAIntr;
++
++/* Hold a pointer to the start of the CCB array, to be used in the IRQ routine
++ *to find the channel descriptor for the channed sending the interrupt to the
++ *core.
++ */
++extern channelControlBlock *iapi_CCBHead;
++
++/* configs_data structure filled with default data*/
++extern configs_data iapi_ConfigDefaults;
++
++#ifdef SDMA_V2
++extern sdmaState iapi_SdmaState;
++#endif
++
++#endif /* iapiDefaults_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapi.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapi.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapi.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,49 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapi.h
++ *
++ * $Id iapi.h $
++ *
++ * Description:
++ * Unique include for the whole IAPI library.
++ *
++ *
++ * http//compass.mot.com/go/115342679
++ *
++ * $Log iapi.h $
++ *
++ * ***************************************************************************/
++
++#ifndef _iapi_h
++#define _iapi_h
++
++/* ****************************************************************************
++ * Include File Section
++ * ***************************************************************************/
++#include <linux/types.h>
++#include <mach/hardware.h>
++
++#include <iapiOS.h>
++#include <iapiLow.h>
++#include <iapiMiddle.h>
++#include <iapiHigh.h>
++
++#ifdef MCU
++#include <iapiMiddleMcu.h>
++#endif /* MCU */
++
++
++
++#endif /* _iapi_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiHigh.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,142 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiHigh.h
++ *
++ * $Id iapiHigh.h $
++ *
++ * Description:
++ * prototypes for high level function of I.API
++ *
++ *
++ * http://venerque.sps.mot.com/pjt/sfs/www/iapi/softsim_api.pdf
++ *
++ * $Log iapiHigh.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiHigh_h
++#define _iapiHigh_h
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include "sdmaStruct.h"
++
++/* ****************************************************************************
++ * Macro-command Section
++ *****************************************************************************/
++enum {
++ IAPI_CHANGE_CHANDESC, /* 0x00 */
++ IAPI_CHANGE_BDNUM, /* 0x01 */
++ IAPI_CHANGE_BUFFSIZE, /* 0x02 */
++ IAPI_CHANGE_CHANBLOCK, /* 0x03 */
++ IAPI_CHANGE_INSTANCE, /* 0x04 */
++ IAPI_CHANGE_OWNERSHIP, /* 0x05 */
++ IAPI_CHANGE_SYNCH, /* 0x06 */
++ IAPI_CHANGE_TRUST, /* 0x07 */
++ IAPI_CHANGE_CALLBACKFUNC, /* 0x08 */
++ IAPI_CHANGE_CHANCCB, /* 0x09 */
++ IAPI_CHANGE_PRIORITY, /* 0x0a */
++ IAPI_CHANGE_BDWRAP, /* 0x0b */
++ IAPI_CHANGE_WATERMARK, /* 0x0c */
++ IAPI_CHANGE_SET_BDCONT, /* 0x0d */
++ IAPI_CHANGE_UNSET_BDCONT, /* 0x0e */
++ IAPI_CHANGE_SET_BDEXTD, /* 0x0f */
++ IAPI_CHANGE_UNSET_BDEXTD, /* 0x10 */
++ IAPI_CHANGE_EVTMASK1, /* 0x11 */
++ IAPI_CHANGE_EVTMASK2, /* 0x12 */
++ IAPI_CHANGE_PERIPHADDR, /* 0x13 */
++ IAPI_CHANGE_SET_BDINTR, /* 0x14 */
++ IAPI_CHANGE_UNSET_BDINTR, /* 0x15 */
++ IAPI_CHANGE_SET_TRANSFER_CD, /* 0x16 */
++ IAPI_CHANGE_FORCE_CLOSE, /* 0x17 */
++ IAPI_CHANGE_SET_TRANSFER, /* 0x18 */
++ IAPI_CHANGE_USER_ARG, /* 0x19 */
++ IAPI_CHANGE_SET_BUFFERADDR, /* 0x1a */
++ IAPI_CHANGE_SET_EXTDBUFFERADDR, /* 0x1b */
++ IAPI_CHANGE_SET_COMMAND, /* 0x1c */
++ IAPI_CHANGE_SET_COUNT, /* 0x1d */
++ IAPI_CHANGE_SET_STATUS, /* 0x1e */
++ IAPI_CHANGE_GET_BUFFERADDR, /* 0x1f */
++ IAPI_CHANGE_GET_EXTDBUFFERADDR, /* 0x20 */
++ IAPI_CHANGE_GET_COMMAND, /* 0x21 */
++ IAPI_CHANGE_GET_COUNT, /* 0x22 */
++ IAPI_CHANGE_GET_STATUS, /* 0x23 */
++ IAPI_CHANGE_BUFFER_LOCATION, /* 0x24 */
++ IAPI_CHANGE_SET_ENDIANNESS, /* 0x25 */
++#ifdef SDMA_V2
++ IAPI_ENTER_LOCK_MODE, /* 0x26 */
++#endif
++ IAPI_CHANGE_SET_INTR_MASK, /* 0x27 */
++ IAPI_CHANGE_UNSET_INTR_MASK, /* 0x28 */
++};
++
++
++/*
++ * Public Function Prototype Section
++ */
++int iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber);
++int iapi_Close(channelDescriptor *cd_p);
++int iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte);
++int iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte);
++int iapi_MemCopy(channelDescriptor *cd_p, void* dest, void* src,
++ unsigned long size);
++int iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest,
++ unsigned long param);
++
++
++int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2);
++
++int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2);
++
++#ifdef MCU
++int iapi_Init(channelDescriptor *cd_p, configs_data *config_p,
++ unsigned short *ram_image, unsigned short code_size,
++ dma_addr_t start_addr, unsigned short channel0_addr);
++#endif /* MCU */
++#ifdef DSP
++int iapi_Init(channelDescriptor *cd_p);
++#endif /* DSP */
++
++int iapi_StartChannel(unsigned char channel);
++int iapi_StopChannel(unsigned char channel);
++int iapi_SynchChannel(unsigned char channel);
++
++int iapi_GetChannelNumber(channelDescriptor *cd_p);
++unsigned long iapi_GetError(channelDescriptor *cd_p);
++int iapi_GetCount(channelDescriptor *cd_p);
++int iapi_GetCountAll(channelDescriptor *cd_p);
++
++#ifndef IRQ_KEYWORD
++#define IRQ_KEYWORD
++#endif /* IRQ_KEYWORD */
++
++IRQ_KEYWORD void IRQ_Handler(void);
++
++#ifdef MCU
++int iapi_GetScript(channelDescriptor *cd_p, void *buf, unsigned short size,
++ dma_addr_t address);
++int iapi_GetContext(channelDescriptor *cd_p, void *buf,
++ unsigned char channel);
++int iapi_SetScript(channelDescriptor *cd_p, void *buf, unsigned short nbyte,
++ dma_addr_t destAddr);
++int iapi_SetContext(channelDescriptor *cd_p, void *buf,
++ unsigned char channel);
++int iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p);
++
++int iapi_SetChannelEventMapping(unsigned char event, unsigned long channel_map);
++#endif /* MCU */
++
++#endif /* _iapiHigh_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLowDsp.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,50 @@
++/*
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/* ****************************************************************************
++ *
++ * File: iapiLowDsp.h
++ *
++ * $Id iapiLowDsp.h $
++ *
++ * Description:
++ * prototypes for low level function of I.API for DSP side only
++ *
++ *
++ *
++ *
++ * $Log iapiLowDsp.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiLowDsp_h
++#define _iapiLowDsp_h
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ *****************************************************************************/
++/* WARNING !!!!!
++ * This file is empty and it is normal, because there is no low level functions
++ * dedicated to the DSP but the file (iapi_LowDsp.h) must still exist because
++ * some project directly links the file. Previously, there were function
++ * iapi_EnableInterrupts,iapi_DisableInterrupts,iapi_WaitCore,iapi_StartChannel
++ * iapi_StopChannel but they are common to both MCU and DSP, so they have been
++ * moved to iapi_Low.h file.
++ */
++
++#endif /* _iapiLowDsp_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLow.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,70 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiLow.h
++ *
++ * $Id iapiLow.h $
++ *
++ * Description:
++ * prototypes for low level function of I.API
++ *
++ *
++ *
++ *
++ * $Log iapiLow.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiLow_h
++#define _iapiLow_h
++
++/* ****************************************************************************
++ * Boolean identifiers
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include "iapiOS.h"
++#include <linux/types.h>
++#include <mach/dma.h>
++
++/* ****************************************************************************
++ * Macro-command Section
++ *****************************************************************************/
++enum
++{
++ OR_OP,
++ AND_OP
++};
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ *****************************************************************************/
++typedef void (*CallbackISR)(channelDescriptor *cd_p, void *arg);
++
++void iapi_lowStartChannel(unsigned char channel);
++void iapi_lowStopChannel(unsigned char channel);
++int iapi_lowChangeIntrMask(unsigned int param, unsigned char op);
++void iapi_AttachCallbackISR(channelDescriptor *cd_p,
++ CallbackISR func_p);
++void iapi_DetachCallbackISR(channelDescriptor *cd_p);
++void iapi_ChangeCallbackISR(channelDescriptor *cd_p,
++ CallbackISR func_p);
++void iapi_lowSynchChannel(unsigned char channel);
++void iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command,
++ unsigned char status, unsigned short count,
++ void *buffAddr, dma_addr_t extBufferAddr);
++
++#endif /* _iapiLow_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiLowMcu.h 2010-12-03 09:51:55.388349760 +0100
+@@ -0,0 +1,58 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiLowMcu.h
++ *
++ * $Id iapiLowMcu.h $
++ *
++ * Description:
++ * prototypes for low level function of I.API of MCU side only
++ *
++ *
++ *
++ *
++ * $Log iapiLowMcu.h $
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiLowMcu_h
++#define _iapiLowMcu_h
++
++/******************************************************************************
++ * Include File Section
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ * ***************************************************************************/
++
++
++void iapi_InitChannelTables(void);
++int iapi_ChannelConfig(unsigned char channel, unsigned eventOverride,
++ unsigned mcuOverride, unsigned dspOverride);
++int iapi_Channel0Command(channelDescriptor *cd_p, void *buf,
++ unsigned short nbyte, unsigned char command);
++void iapi_lowGetScript(channelDescriptor *cd_p, void *buf, unsigned short size,
++ dma_addr_t address);
++void iapi_lowGetContext(channelDescriptor *cd_p, void *buf,
++ unsigned char channel);
++void iapi_lowSetScript(channelDescriptor *cd_p, void *buf, unsigned short nbyte,
++ dma_addr_t destAddr);
++void iapi_lowSetContext(channelDescriptor *cd_p, void *buf,
++ unsigned char channel);
++int iapi_lowAssignScript(channelDescriptor *cd_p, script_data *data_p);
++
++int iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map);
++
++#endif /* _iapiLowMcu_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddle.h 2010-12-03 09:51:55.392354434 +0100
+@@ -0,0 +1,52 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiMiddle.h
++ *
++ * $Id iapiMiddle.h $
++ *
++ * Description:
++ * prototypes for middle level function of I.API
++ *
++ *
++ *
++ *
++ * $Log iapiMiddle.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiMiddle_h
++#define _iapiMiddle_h
++
++/* ****************************************************************************
++ * Include File Section
++ ******************************************************************************/
++#include "sdmaStruct.h"
++#ifdef MCU
++#include "iapiMiddleMcu.h"
++#endif /* MCU */
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ ******************************************************************************/
++bufferDescriptor *iapi_AllocBD(channelControlBlock *ccb_p);
++int iapi_AllocContext(contextData **ctxd_p, unsigned char channel);
++int iapi_AllocChannelDesc(channelDescriptor **cd_p, unsigned char channel);
++int iapi_ChangeChannelDesc (channelDescriptor *cd_p,
++ unsigned char whatToChange, unsigned long newval);
++void iapi_InitializeCallbackISR(void (*func_p)(channelDescriptor *cd_p,
++ void *arg));
++int iapi_InitializeMemory (channelControlBlock *ccb_p);
++
++#endif /* iapiMiddle_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiMiddleMcu.h 2010-12-03 09:51:55.392354434 +0100
+@@ -0,0 +1,41 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiMiddleMcu.h
++ *
++ * $Id iapiMiddleMcu.h $
++ *
++ * Description:
++ * prototypes for middle level function of I.API
++ *
++ *
++ *
++ *
++ * $Log iapiMiddleMcu.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiMiddleMcu_h
++#define _iapiMiddleMcu_h
++
++/* ****************************************************************************
++ * Include File Section
++ ******************************************************************************/
++#include "sdmaStruct.h"
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ ******************************************************************************/
++
++#endif /* iapiMiddleMcu_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/iapiOS.h 2010-12-03 09:51:55.392354434 +0100
+@@ -0,0 +1,95 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiOS.h
++ *
++ * $Id iapiOS.h $
++ *
++ * Description:
++ * prototypes for OS level function of I.API
++ *
++ *
++ *
++ *
++ * $Log iapiOS.h
++ *
++ * ***************************************************************************/
++
++#ifndef _iapiOS_h
++#define _iapiOS_h
++
++/* ****************************************************************************
++ * Boolean identifiers
++ *****************************************************************************/
++#define NO_OS 0
++#define LINUX 1
++#define SYMBIAN 2
++#define WINCE 3
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#if OS == NO_OS
++#include <stdlib.h>
++#elif OS == LINUX
++#include <linux/types.h>
++#endif
++
++#include "sdmaStruct.h"
++#include "iapiDefaults.h"
++#ifdef MCU
++#include "iapiLowMcu.h"
++#endif /* MCU */
++
++/* ****************************************************************************
++ * Macro-command Section
++ *****************************************************************************/
++#ifdef CONFIG_SDMA_IRAM
++#define IRAM_MALLOC(x) (*iapi_iram_Malloc)(x)
++#else
++#define IRAM_MALLOC(x) (*iapi_Malloc)(x)
++#endif
++#define MALLOC(x) (*iapi_Malloc)(x)
++#define FREE(x) if ((x) != NULL) (*iapi_Free)(x)
++
++#define GOTO_SLEEP(x) (iapi_GotoSleep)(x)
++#define INIT_SLEEP(x) (iapi_InitSleep)(x)
++
++/* ****************************************************************************
++ * Public Function Prototype Section
++ *****************************************************************************/
++
++#ifdef CONFIG_SDMA_IRAM
++extern void *(*iapi_iram_Malloc)(size_t size);
++#endif
++extern void *(*iapi_Malloc)(size_t size);
++extern void (*iapi_Free)(void *ptr);
++
++extern dma_addr_t (*iapi_Virt2Phys)(void *ptr);
++extern void *(*iapi_Phys2Virt)(dma_addr_t);
++
++extern void (*iapi_WakeUp)(int);
++extern void (*iapi_GotoSleep)(int);
++extern void (*iapi_InitSleep)(int);
++
++extern void *(*iapi_memcpy)(void *dest, const void *src, size_t count);
++extern void *(*iapi_memset)(void *dest, int c, size_t count);
++
++extern void (*iapi_EnableInterrupts)(void);
++extern void (*iapi_DisableInterrupts)(void);
++
++extern int (*iapi_GetChannel)(int);
++extern int (*iapi_ReleaseChannel)(int);
++
++#endif /* _iapiOS_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/include/sdmaStruct.h 2010-12-03 09:51:55.392354434 +0100
+@@ -0,0 +1,465 @@
++/******************************************************************************
++ *
++ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: sdmaStruct.h
++ *
++ * $Id sdmaStruct.h $
++ *
++ * Description: provides necessary definitions and inclusion for ipcmStruct.c
++ *
++ * $Log $
++ *
++ *****************************************************************************/
++#ifndef _sdmaStruct_h
++#define _sdmaStruct_h
++
++/* ****************************************************************************
++ * Include File Section
++ ******************************************************************************/
++
++/* ****************************************************************************
++ * Macro-command Section
++ ******************************************************************************/
++
++/**
++ * Identifier NULL
++ */
++#ifndef NULL
++#define NULL 0
++#endif
++
++/**
++ * Boolean identifiers
++ */
++#ifndef FALSE
++#define FALSE 0
++#endif
++
++#ifndef TRUE
++#define TRUE 1
++#endif
++
++/**
++ * Number of channels
++ */
++#define CH_NUM 32
++/**
++ * Number of events
++ */
++#ifdef SDMA_V2
++#define EVENTS_NUM 48
++#else
++#define EVENTS_NUM 32
++#endif
++/**
++ * Channel configuration
++ */
++#define DONT_OWN_CHANNEL 0
++#define OWN_CHANNEL 1
++
++/**
++ * Ownership (value defined to computed decimal value)
++ */
++#define CH_OWNSHP_OFFSET_EVT 0
++#define CH_OWNSHP_OFFSET_MCU 1
++#define CH_OWNSHP_OFFSET_DSP 2
++/**
++ * Indexof the greg which holds address to start a script from when channel
++ * becomes current.
++ */
++#define SDMA_NUMBER_GREGS 8
++
++/**
++ * Channel contexts management
++ */
++
++#define CHANNEL_CONTEXT_BASE_ADDRESS 0x800
++/**
++ * Buffer descriptor status values.
++ */
++#define BD_DONE 0x01
++#define BD_WRAP 0x02
++#define BD_CONT 0x04
++#define BD_INTR 0x08
++#define BD_RROR 0x10
++#define BD_LAST 0x20
++#define BD_EXTD 0x80
++
++
++/**
++ * Data Node descriptor status values.
++ */
++#define DND_END_OF_FRAME 0x80
++#define DND_END_OF_XFER 0x40
++#define DND_DONE 0x20
++#define DND_UNUSED 0x01
++
++/**
++ * IPCV2 descriptor status values.
++ */
++#define BD_IPCV2_END_OF_FRAME 0x40
++
++
++#define IPCV2_MAX_NODES 50
++/**
++ * Error bit set in the CCB status field by the SDMA,
++ * in setbd routine, in case of a transfer error
++ */
++#define DATA_ERROR 0x10000000
++
++/**
++ * Buffer descriptor commands.
++ */
++#define C0_ADDR 0x01
++#define C0_LOAD 0x02
++#define C0_DUMP 0x03
++#define C0_SETCTX 0x07
++#define C0_GETCTX 0x03
++#define C0_SETDM 0x01
++#define C0_SETPM 0x04
++#define C0_GETDM 0x02
++#ifdef SDMA_V2
++#define C0_GETPM 0x06
++#else
++#define C0_GETPM 0x08
++#endif
++/**
++ * Transfer types, encoded in the BD command field
++ */
++#define TRANSFER_32BIT 0x00
++#define TRANSFER_8BIT 0x01
++#define TRANSFER_16BIT 0x02
++#define TRANSFER_24BIT 0x03
++
++#define TRANSFER_TYPE_MASK 0x03 /* MASK FOR BIT0 and BIT1 of BD Command Field*/
++/**
++ * Memory types, encoded in the BD command field
++ */
++#define EXTERNAL_MEM 0x04
++#define INTERNAL_MEM ~0x04
++
++#define BUFFER_LOC_MASK 0x04 /* MASK FOR BIT2 of BD Command Field*/
++/**
++ * Change endianness indicator in the BD command field
++ */
++#define CHANGE_ENDIANNESS 0x80
++
++#define ENDIANNESS_MASK 0x80 /* MASK FOR BIT7 of BD Command Field*/
++/**
++ * Size in bytes
++ */
++#define SDMA_BD_SIZE 8
++#define SDMA_EXTENDED_BD_SIZE 12
++#define BD_NUMBER 4
++/**
++ * Channel interrupt policy
++ */
++#define DEFAULT_POLL 0
++#define CALLBACK_ISR 1
++/**
++ * Channel status
++ */
++#define UNINITIALIZED 0
++#define INITIALIZED 1
++
++/**
++ * IoCtl particular values
++ */
++#define SET_BIT_ALL 0xFFFFFFFF
++#define BD_NUM_OFFSET 16
++#define BD_NUM_MASK 0xFFFF0000
++
++/**
++ * Maximum values for IoCtl calls, used in high or middle level calls
++ */
++#define MAX_BD_NUM 1024
++#define MAX_BD_SIZE 65536
++#define MAX_BLOCKING 2
++#define MAX_SYNCH 2
++#define MAX_OWNERSHIP 8
++#define MAX_CH_PRIORITY 8
++#define MAX_TRUST 2
++#define MAX_WML 256
++
++
++/**
++ * Access to channelDescriptor fields
++ */
++enum {
++ IAPI_CHANNELNUMBER, /* 0x00 */
++ IAPI_BUFFERDESCNUMBER, /* 0x01 */
++ IAPI_BUFFERSIZE, /* 0x02 */
++ IAPI_BLOCKING, /* 0x03 */
++ IAPI_CALLBACKSYNCH, /* 0x04 */
++ IAPI_OWNERSHIP, /* 0x05 */
++ IAPI_PRIORITY, /* 0x06 */
++ IAPI_TRUST, /* 0x07 */
++ IAPI_UNUSED, /* 0x08 */
++ IAPI_CALLBACKISR_PTR, /* 0x09 */
++ IAPI_CCB_PTR, /* 0x0a */
++ IAPI_BDWRAP, /* 0x0b */
++ IAPI_WML, /* 0x0c */
++};
++
++#ifdef SDMA_V2
++
++/**
++ * Enum for SDMA states
++ */
++typedef enum {
++ UNDEF,
++ OPEN,
++ LOCK,
++ CLOSED,
++ CLOSE_LOCK
++} sdmaState;
++
++/**
++ * LOCK Register Value
++ */
++ #define RESET_CLEAR_LOCK 0x03
++ #define RESET_NOCLEAR_LOCK 0x01
++
++#define RESET_CLR_BIT_OFFSET 1
++#define LOCK_BIT_OFFSET 0
++
++#endif
++
++/**
++ * Default values for channel descriptor - nobody ownes the channel
++ */
++#define CD_DEFAULT_OWNERSHIP 7
++
++
++/**
++ * User Type Section
++ */
++
++/**
++ * Command/Mode/Count of buffer descriptors
++ */
++
++#if (ENDIANNESS==B_I_G_ENDIAN)
++typedef struct iapi_modeCount_ipcv2 {
++ unsigned long status : 8; /* L, E , D bits stored here */
++ unsigned long reserved : 8;
++ unsigned long count : 16; /* <size of the buffer pointed by this BD */
++} modeCount_ipcv2;
++#else
++typedef struct iapi_modeCount_ipcv2 {
++ unsigned long count : 16; /* size of the buffer pointed by this BD */
++ unsigned long reserved : 8; /* Reserved*/
++ unsigned long status : 8; /* L, E , D bits stored here */
++} modeCount_ipcv2;
++#endif
++/**
++ * Data Node descriptor - IPCv2
++ * (differentiated between evolutions of SDMA)
++ */
++typedef struct iapi_dataNodeDescriptor {
++ modeCount_ipcv2 mode; /* command, status and count */
++ dma_addr_t bufferAddr; /* address of the buffer described */
++} dataNodeDescriptor;
++
++#if (ENDIANNESS==B_I_G_ENDIAN)
++typedef struct iapi_modeCount_ipcv1_v2 {
++ unsigned long endianness: 1;
++ unsigned long reserved: 7;
++ unsigned long status : 8; /* E,R,I,C,W,D status bits stored here */
++ unsigned long count : 16; /* size of the buffer pointed by this BD */
++} modeCount_ipcv1_v2;
++#else
++typedef struct iapi_modeCount_ipcv1_v2 {
++ unsigned long count : 16; /* size of the buffer pointed by this BD */
++ unsigned long status : 8; /* E,R,I,C,W,D status bits stored here */
++ unsigned long reserved: 7;
++ unsigned long endianness: 1;
++} modeCount_ipcv1_v2;
++#endif
++/**
++ * Buffer descriptor
++ * (differentiated between evolutions of SDMA)
++ */
++typedef struct iapi_bufferDescriptor_ipcv1_v2 {
++ modeCount_ipcv1_v2 mode; /* command, status and count */
++ dma_addr_t bufferAddr; /* address of the buffer described */
++ dma_addr_t extBufferAddr; /* extended buffer address */
++} bufferDescriptor_ipcv1_v2;
++
++
++/**
++ * Mode/Count of data node descriptors - IPCv2
++ */
++
++#if (ENDIANNESS==B_I_G_ENDIAN)
++typedef struct iapi_modeCount {
++ unsigned long command : 8; /* command mostly used for channel 0 */
++ unsigned long status : 8; /* E,R,I,C,W,D status bits stored here */
++ unsigned long count : 16; /* size of the buffer pointed by this BD */
++} modeCount;
++#else
++typedef struct iapi_modeCount {
++ unsigned long count : 16; /* size of the buffer pointed by this BD */
++ unsigned long status : 8; /* E,R,I,C,W,D status bits stored here */
++ unsigned long command : 8; /* command mostly used for channel 0 */
++} modeCount;
++#endif
++
++
++/**
++ * Buffer descriptor
++ * (differentiated between evolutions of SDMA)
++ */
++typedef struct iapi_bufferDescriptor {
++ modeCount mode; /* command, status and count */
++ dma_addr_t bufferAddr; /* address of the buffer described */
++ dma_addr_t extBufferAddr; /* extended buffer address */
++} bufferDescriptor;
++
++
++
++struct iapi_channelControlBlock;
++struct iapi_channelDescriptor;
++/**
++ * Channel Descriptor
++ */
++typedef struct iapi_channelDescriptor {
++ unsigned char channelNumber ;/* stores the channel number */
++ unsigned short bufferSize ;/* size (in bytes) of buffer descriptors */
++ unsigned short bufferDescNumber;/* number of BD's automatically allocated for this channel */
++ unsigned long blocking :3;/* blocking / non blocking feature selection */
++ unsigned long callbackSynch :1;/* polling/ callback method selection */
++ unsigned long ownership :3;/* ownership of the channel (host+dedicated+event)*/
++ unsigned long priority :3;/* reflects the SDMA channel priority register */
++ unsigned long trust :1;/* trusted buffers or kernel allocated */
++ unsigned long useDataSize :1;/* indicates if the dataSize field is meaningfull */
++ unsigned long dataSize :2;/* data transfer size - 8,16,24 or 32 bits*/
++ unsigned long forceClose :1;/* if TRUE, close channel even with BD owned by SDMA*/
++ unsigned long scriptId :7;/* number of the script */
++ unsigned long watermarkLevel:10;/* Watermark level for the peripheral access*/
++ unsigned long eventMask1; /* First Event mask */
++ unsigned long eventMask2; /* Second Event mask */
++ unsigned long peripheralAddr; /* Address of the peripheral or its fifo when needed */
++ void (*callbackISR_ptr)(struct iapi_channelDescriptor*, void*); /* pointer to the callback function (or NULL) */
++ struct iapi_channelControlBlock *ccb_ptr; /* pointer to the channel control block associated to this channel */
++} channelDescriptor;
++
++/**
++ * Channel Status
++ */
++typedef struct iapi_channelStatus {
++ unsigned long unused :27,
++ data_error : 1,
++ even_more_unused: 1,
++ openedInit : 1, /* channel is initialized */
++ stateDirection: 1, /* sdma is reading/writing (as seen from channel owner core) */
++ execute : 1; /* channel is being processed (started) */
++} channelStatus;
++
++/**
++ * Channel control Block
++ */
++typedef struct iapi_channelControlBlock {
++ dma_addr_t currentBDptr; /* current buffer descriptor processed */
++ dma_addr_t baseBDptr; /* first element of buffer descriptor array */
++ channelDescriptor *channelDescriptor; /* pointer to the channel descriptor */
++ channelStatus status; /* open/close ; started/stopped ; read/write */
++} channelControlBlock;
++
++/**
++ * Context structure.
++ */
++#if (ENDIANNESS==B_I_G_ENDIAN)
++typedef struct iapi_stateRegisters {
++ unsigned long sf : 1;/* source falut while loading data */
++ unsigned long unused0: 1;/* */
++ unsigned long rpc :14;/* return program counter */
++ unsigned long t : 1;/* test bit:status of arithmetic & test instruction*/
++ unsigned long unused1: 1;/* */
++ unsigned long pc :14;/* program counter */
++ unsigned long lm : 2;/* loop mode */
++ unsigned long epc :14;/* loop end program counter */
++ unsigned long df : 1;/* destiantion falut while storing data */
++ unsigned long unused2: 1;/* */
++ unsigned long spc :14;/* loop start program counter */
++} stateRegiters;
++#else
++typedef struct iapi_stateRegisters {
++ unsigned long pc :14;/* program counter */
++ unsigned long unused1: 1;/* */
++ unsigned long t : 1;/* test bit: status of arithmetic & test instruction*/
++ unsigned long rpc :14;/* return program counter */
++ unsigned long unused0: 1;/* */
++ unsigned long sf : 1;/* source falut while loading data */
++ unsigned long spc :14;/* loop start program counter */
++ unsigned long unused2: 1;/* */
++ unsigned long df : 1;/* destiantion falut while storing data */
++ unsigned long epc :14;/* loop end program counter */
++ unsigned long lm : 2;/* loop mode */
++} stateRegiters;
++#endif
++
++/**
++ * This is SDMA version of SDMA
++ */
++typedef struct iapi_contextData {
++ stateRegiters channelState; /* channel state bits */
++ unsigned long gReg[SDMA_NUMBER_GREGS]; /* general registers */
++ unsigned long mda; /* burst dma destination address register */
++ unsigned long msa; /* burst dma source address register */
++ unsigned long ms; /* burst dma status register */
++ unsigned long md; /* burst dma data register */
++ unsigned long pda; /* peripheral dma destination address register */
++ unsigned long psa; /* peripheral dma source address register */
++ unsigned long ps; /* peripheral dma status register */
++ unsigned long pd; /* peripheral dma data register */
++ unsigned long ca; /* CRC polynomial register */
++ unsigned long cs; /* CRC accumulator register */
++ unsigned long dda; /* dedicated core destination address register */
++ unsigned long dsa; /* dedicated core source address register */
++ unsigned long ds; /* dedicated core status register */
++ unsigned long dd; /* dedicated core data register */
++ unsigned long scratch0; /* scratch */
++ unsigned long scratch1; /* scratch */
++ unsigned long scratch2; /* scratch */
++ unsigned long scratch3; /* scratch */
++ unsigned long scratch4; /* scratch */
++ unsigned long scratch5; /* scratch */
++ unsigned long scratch6; /* scratch */
++ unsigned long scratch7; /* scratch */
++} contextData;
++
++/**
++ *This structure holds the necessary data for the assignment in the
++ * dynamic channel-script association
++ */
++typedef struct iapi_script_data {
++ unsigned short load_address;/* start address of the script */
++ unsigned long wml; /* parameters for the channel descriptor */
++ unsigned long shp_addr; /* shared peripheral base address */
++ unsigned long event_mask1; /* First Event mask */
++ unsigned long event_mask2; /* Second Event mask */
++} script_data;
++
++/**
++ *This structure holds the the useful bits of the CONFIG register
++ */
++typedef struct iapi_configs_data {
++ unsigned long dspdma :1; /* indicates if the DSPDMA is used */
++ unsigned long rtdobs :1; /* indicates if Real-Time Debug pins are enabled */
++ unsigned long acr :1; /* indicates if AHB freq /core freq = 2 or 1 */
++ unsigned long csm :2; /* indicates which context switch mode is selected */
++} configs_data;
++
++#endif /* _sdmaStruct_h */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/Makefile linux.35.new/arch/arm/plat-mxc/sdma/iapi/Makefile
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/Makefile 2010-12-03 09:51:55.392354434 +0100
+@@ -0,0 +1,5 @@
++#
++# Makefile for I.API sources.
++#
++
++obj-y := src/
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiDefaults.c 2010-12-03 09:51:55.396349340 +0100
+@@ -0,0 +1,128 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiDefaults.c
++ *
++ * $Id iapiDefaults.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ *
++ * Usage:
++ *
++ * Files:
++ *
++ *
++* /
++ *
++ * $Log iapiDefaults.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ ******************************************************************************/
++#include <iapi.h>
++
++/* ****************************************************************************
++ * Global Variable Section
++ ******************************************************************************/
++
++/**
++ * @brief System Call-back ISRs Table
++ */
++void (*callbackIsrTable[CH_NUM])(channelDescriptor *cd_p, void *arg);
++
++/**
++ * @brief User registered pointers table
++ */
++void *userArgTable[CH_NUM];
++
++/**
++ * @brief Pointer to the first CCB in the CCB array
++ */
++channelControlBlock *iapi_CCBHead = NULL;
++
++
++/**Default channel description.
++ *
++ * Initialization values are:\n
++ * - channelNumber = 0
++ * - bufferDescNumber = 1
++ * - bufferSize = 8
++ * - blocking = 0
++ * - callbackSynch = DEFAULT_POLL
++ * - ownership = CD_DEFAULT_OWNERSHIP
++ * - priority = 1
++ * - trust = TRUE
++ * - useDataSize = 0
++ * - dataSize = 0
++ * - forceClose = 0
++ * - scriptId = 0
++ * - watermarkLevel = 0
++ * - eventMask1 = 0
++ * - eventMask2 = 0
++ * - peripheralAddr = NULL
++ * - callbackISR_ptr = NULL
++ * - iapi_channelControlBlock = NULL
++ */
++channelDescriptor iapi_ChannelDefaults = {
++ 0, 1, 8, 0, DEFAULT_POLL,
++ CD_DEFAULT_OWNERSHIP, 1, TRUE, 0, 0, 0, 0,
++ 0, 0x00, 0x00, 0x00, NULL, NULL,
++};
++
++/**
++ * Integrated error management
++ */
++int iapi_errno = 0;
++volatile unsigned long iapi_SDMAIntr = 0;
++
++/* Default config register.
++ * Initialization values are:
++ * dspdma used
++ * Real-Time Debug pins disabled
++ * AHB freq / core freq = 2
++ * dynamic context switch
++*/
++
++/* DSPDMA (12th) bit of CONFIG Register should be zero when DSP DMA is not connected.
++ * Otherwise it can even lead to hang while doing the context switch.
++ * Hence for all MAD targets, iapi_ConfigDefaults should be updated to:
++ * { 0, 0, 0, 3 OR 0 } depending on whether context switching
++ * needs to be static or dynamic */
++configs_data iapi_ConfigDefaults = {
++ /* according to the i.MX25 reference manual this should be configured as 0 */
++#ifndef CONFIG_ARCH_MX25
++ 1,
++#else
++ 0,
++#endif
++ 0,
++ 0,
++ 3,
++};
++
++#ifdef SDMA_V2
++/* Default sdma State : UNDEF
++ *possible value are UNDEF, OPEN, LOCK, CLOSED, CLOSE_LOCK
++ */
++
++sdmaState iapi_SdmaState = UNDEF;
++#endif
++
++/* ***************************************************************************/
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiHigh.c 2010-12-03 09:51:55.404347330 +0100
+@@ -0,0 +1,2462 @@
++/******************************************************************************
++ *
++ * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiHigh.c
++ *
++ * $Id iapiHigh.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the HIGH level functions of the I.API.
++ *
++ *
++ * /
++ *
++ * $Log iapiHigh.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <stdarg.h>
++#include <string.h>
++#include <linux/err.h>
++#include <linux/io.h>
++
++#include <epm.h>
++#include <iapi.h>
++
++#ifdef DEBUG
++#include <mach/sdma.h>
++#if CH_NUM != MAX_DMA_CHANNELS
++#error BAD number of DMA channels!
++#endif
++#endif
++
++/* ****************************************************************************
++ * External Reference Section (for compatibility with already developed code)
++ *****************************************************************************/
++static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, void *data);
++
++/* ****************************************************************************
++ * Global Variable Section
++ *****************************************************************************/
++#define MAX_CHANNEL 32
++
++static dataNodeDescriptor *dnd_read_control_struct[MAX_CHANNEL];
++
++/* MASK to nullify all the bits of Status in Data Node descriptor apart from L, E and D */
++#define GET_LED_MASK 0xE0
++
++/* Table defines mapping of Data Node Descriptor to Buffer Descriptor status */
++static unsigned char dnd_2_bd_status[] = {
++ [0x00] = 0x85, /* L = 0, E = 0, D = 0 */
++ [0x20] = 0x84, /* L = 0, E = 0, D = 1 */
++ [0x40] = 0xAB, /* L = 0, E = 1, D = 0 */
++ [0x60] = 0xAA, /* L = 0, E = 1, D = 1 */
++ [0x80] = 0xC5, /* L = 1, E = 0, D = 0 */
++ [0xA0] = 0xC4, /* L = 1, E = 0, D = 1 */
++ [0xC0] = 0xEB, /* L = 1, E = 1, D = 0 */
++ [0xE0] = 0xEA, /* L = 1, E = 1, D = 1 */
++};
++/* ****************************************************************************
++ * Function Section
++ *****************************************************************************/
++
++/* ***************************************************************************/
++/* Opens an SDMA channel to be used by the library.
++ *
++ * <b>Algorithm:</b>\n
++ *
++ * - Check if initialization is necessary.
++ * - Check that user initialized OS dependant functions.
++ * - Test validity of input parameters
++ * - Check whole channel control block data structure
++ * - Finish initializations (tables with default values)
++ * - Initialize channel 0 is dedicated to communications with SDMA
++ * - Check channel control block definition
++ * - if the channel descriptor is not initialized, initialize it with
++ * the default value
++ * - If buffer descriptor already allocated, exit with iapi_errno filled
++ * complete the lowest bits with the number of 'D' bits set
++ * - Buffer Descriptors allocation
++ * - Channel's configuration properties (mcu side only)
++ * - read/write direction => enable/disable channel setting
++ *
++ * @param *cd_p If channelNumber is 0, it is pointer to channel descriptor
++ * for the channnel 0 to be opened and
++ * has default values.
++ * For other channels, this function should be called after
++ * channel 0 has been opened, and it's channel descriptor
++ * has been allocated.
++ * @param channelNumber channel to be opened
++ *
++ * @return
++ * - IAPI_SUCCESS : OK
++ * - -iapi_errno : close failed, return negated value of iapi_errno
++ */
++int
++iapi_Open(channelDescriptor *cd_p, unsigned char channelNumber)
++{
++ channelControlBlock *ccb_p;
++ channelControlBlock *local_ccb_p;
++ channelDescriptor *local_cd_p;
++ bufferDescriptor *bd_p;
++ int index;
++
++ DBG(0, "%s: cd_p=%p channel=%d\n", __FUNCTION__, cd_p, channelNumber);
++
++ /*
++ * 1. Check if initialization is necessary
++ */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED |
++ IAPI_ERR_CH_AVAILABLE | channelNumber;
++ return -iapi_errno;
++ }
++
++ /* Verify these functions every time */
++ if ((iapi_GetChannel == NULL) || (iapi_ReleaseChannel == NULL)) {
++ iapi_errno = IAPI_ERR_NO_OS_FN | channelNumber;
++ return -iapi_errno;
++ }
++
++ /* Try to aquire channel */
++ if (iapi_GetChannel(channelNumber) != 0) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | channelNumber;
++ return -iapi_errno;
++ }
++
++ DBG(0, "%s@%d: cd_p=%p ccb_ptr=%p\n", __FUNCTION__, __LINE__, cd_p,
++ cd_p->ccb_ptr);
++ if (channelNumber == 0 && cd_p->ccb_ptr == NULL) {
++ int i;
++
++ /* Verify that the user initialized all OS dependant functions required
++ * by the library.
++ */
++ if ((iapi_Malloc == NULL) ||
++ (iapi_Free == NULL) ||
++ (iapi_Virt2Phys == NULL) ||
++ (iapi_Phys2Virt == NULL) ||
++ (iapi_GotoSleep == NULL) ||
++ (iapi_WakeUp == NULL) ||
++ (iapi_InitSleep == NULL) ||
++ (iapi_memset == NULL) ||
++ (iapi_memcpy == NULL)) {
++ iapi_errno = IAPI_ERR_NO_OS_FN | channelNumber;
++ iapi_ReleaseChannel(channelNumber);
++ return -iapi_errno;
++ }
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /* Whole channel control block data structure */
++ ccb_p = MALLOC(CH_NUM * sizeof(channelControlBlock));
++ if (ccb_p == NULL) {
++ iapi_errno = IAPI_ERR_CCB_ALLOC_FAILED |
++ IAPI_ERR_CH_AVAILABLE | channelNumber;
++ iapi_ReleaseChannel(channelNumber);
++ return -iapi_errno;
++ }
++ DBG(0, "%s: ccb allocated at %p..%p\n", __FUNCTION__, ccb_p,
++ (unsigned char *)(ccb_p + CH_NUM) - 1);
++
++ /* Zero-out the CCB structures array just allocated */
++ iapi_memset(ccb_p, 0x00, CH_NUM * sizeof(channelControlBlock));
++ for (i = 0; i < CH_NUM; i++) {
++ ccb_p[i].baseBDptr = DMA_ADDR_INVALID;
++ ccb_p[i].currentBDptr = DMA_ADDR_INVALID;
++ }
++ /* Save the address of the CCB structures array */
++ iapi_CCBHead = ccb_p;
++
++ cd_p->ccb_ptr = ccb_p;
++ ccb_p->channelDescriptor = cd_p;
++ DBG(0, "%s: channelDescriptor %p=%p\n", __FUNCTION__,
++ &ccb_p->channelDescriptor, cd_p);
++#ifdef MCU
++ /* finish initializations */
++ iapi_InitChannelTables();
++#endif /* MCU */
++ /* Channel 0 is dedicated to communications with SDMA */
++ cd_p->ownership = ((DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ cd_p->bufferDescNumber = 1;
++ }
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /*
++ * 2. Check channel control block
++ */
++ ccb_p = cd_p->ccb_ptr;
++ if (ccb_p == NULL) {
++ iapi_errno = IAPI_ERR_NO_CCB_DEFINED |
++ IAPI_ERR_CH_AVAILABLE |
++ channelNumber;
++ iapi_ReleaseChannel(channelNumber);
++ return -iapi_errno;
++ }
++
++ DBG(0, "%s@%d: ccb_p=%p\n", __FUNCTION__, __LINE__, ccb_p);
++ /* Control block & Descriptor associated with the channel being worked on */
++ local_ccb_p = &ccb_p[channelNumber];
++ local_cd_p = ccb_p[channelNumber].channelDescriptor;
++
++ DBG(0, "%s@%d: local_ccb_p[%d]=%p local_cd_p[%p]=%p\n", __FUNCTION__, __LINE__,
++ channelNumber, local_ccb_p,
++ &ccb_p[channelNumber].channelDescriptor, local_cd_p);
++ /* If the channel is not initialized, initialize it with the default value */
++ if (local_cd_p == NULL) {
++ int result = iapi_AllocChannelDesc(&local_cd_p, channelNumber);
++ if (result!= IAPI_SUCCESS) {
++ iapi_ReleaseChannel(channelNumber);
++ return result; //is already negated from iapi_AllocChannelDesc
++ }
++
++ local_cd_p->ccb_ptr = (struct iapi_channelControlBlock *)local_ccb_p;
++ local_ccb_p->channelDescriptor = local_cd_p;
++ }
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /*
++ * 3. If buffer descriptor already allocated, exit with iapi_errno filled
++ */
++ if (local_ccb_p->baseBDptr != DMA_ADDR_INVALID) {
++ int result = IAPI_ERR_BD_ALLOCATED;
++
++ bd_p = iapi_Phys2Virt(local_ccb_p->baseBDptr);
++ if (bd_p == NULL) {
++ iapi_errno = IAPI_ERR_BD_ALLOCATION;
++ return -iapi_errno;
++ }
++ DBG(0, "%s: bd_p=%p phys=%08x\n", __FUNCTION__, bd_p, local_ccb_p->baseBDptr);
++ for (index = 1; index < local_cd_p->bufferDescNumber; index++) {
++ if ((bd_p->mode.status & BD_DONE) == BD_DONE) {
++ /* complete the lowest bits with the number of 'D' bits set */
++ result++;
++ }
++ bd_p++;
++ }
++ iapi_errno = result;
++ iapi_ReleaseChannel(channelNumber);
++ return -iapi_errno;
++ }
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /*
++ * 4. Buffer Descriptors allocation
++ */
++ iapi_InitializeMemory(local_ccb_p);
++
++#ifdef MCU
++ /*
++ * 5. Channel's configuration properties (mcu side only)
++ */
++ iapi_ChannelConfig(channelNumber,
++ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_EVT) & 1,
++ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_MCU) & 1,
++ (local_cd_p->ownership >> CH_OWNSHP_OFFSET_DSP) & 1);
++#endif /* MCU */
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /* Setting interrupt handling */
++ iapi_ChangeCallbackISR(local_cd_p, local_cd_p->callbackISR_ptr);
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /* Call initialization fn for polling synch on this channel */
++ INIT_SLEEP(channelNumber);
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /* No user arg pointer yet */
++ userArgTable[cd_p->channelNumber] = NULL;
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ /*
++ * 6. read/write direction => enable/disable channel
++ */
++#ifdef MCU
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++#if 1
++ __raw_writel(1, SDMA_CHNPRI(channelNumber));
++#else
++ channelPriorityMatx = &SDMA_CHNPRI_0;
++ channelPriorityMatx[channelNumber] = 1;
++#endif
++#endif /* MCU */
++
++ DBG(0, "%s@%d: \n", __FUNCTION__, __LINE__);
++ local_ccb_p->status.openedInit = TRUE;
++ iapi_ReleaseChannel(channelNumber);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/** Attempts to read nbyte from the data buffer descriptor associated with the
++ * channel channelNumber, into the user's data buffer pointed to by buf.
++ *
++ * <b>Algorithm:</b>\n
++ * - Check data structures are properly initialized:
++ * - Channel descriptor validity
++ * - Control block & Descriptor associated with the channel being worked on
++ * - Check initialization has been done for trusted channels
++ * - If transfer data size is used, check validity of combination transfer
++ * size/requested bytes
++ * - Set the 'D' done bits on all buffer descriptors
++ * - Starting of the channel
++ * - Synchronization mechanism handling:
++ * - for callback: just exit function
++ * - for polling: call the synchronization function then read data from
++ * buffer until either nbyte parameter is reached or all buffer descriptors
++ * have been processed.
++ *
++ * <b>Notes:</b>\n
++ * 1) Virtual DMA SDMA channels are unidirectional, an iapi_Read authorized
++ * on a channel means that we are expecting to receive from the SDMA. The
++ * meaning of an interrupt received from the SDMA is therefore that the
++ * data has been copied from the SDMA to the host's data buffers and is
++ * already passed on upper layers of the application.\n
++ *
++ * @param *cd_p chanenl descriptor for the channel to read from
++ * @param *buf buffer to receive the data
++ * @param nbyte number of bytes to read from channel
++ *
++ * @return
++ * - number of bytes read
++ * - -iapi_errno : in case of failure return negated value of iapi_errno
++ */
++int
++iapi_Read(channelDescriptor *cd_p, void *buf, unsigned short nbyte)
++{
++ int index;
++ int readBytes;
++ int toRead;
++ unsigned int copyFinished;
++ unsigned int bufsize;
++ bufferDescriptor *bd_p;
++ channelControlBlock *ccb_p;
++ unsigned char *local_buf;
++ unsigned char chNum;
++ unsigned char div;
++
++ iapi_errno = IAPI_ERR_NO_ERROR;
++
++ /*
++ * 1. Check data structures are properly initialized
++ */
++ /* Channel descriptor validity */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Channel control block validity */
++ if (cd_p->ccb_ptr == NULL) {
++ iapi_errno = IAPI_ERR_CCB_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Control block & Descriptor associated with the channel being worked on */
++ chNum = cd_p->channelNumber;
++ ccb_p = cd_p->ccb_ptr;
++
++ /* Try to aquire channel */
++ if (iapi_GetChannel(chNum) != 0) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | chNum;
++ return -iapi_errno;
++ }
++
++ /* Check if channel is already opened/initialized */
++ if (ccb_p->status.openedInit == FALSE) {
++ iapi_errno = IAPI_ERR_CHANNEL_UNINITIALIZED |
++ IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++
++ /* Buffer descriptor validity */
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ if (bd_p == NULL) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED |
++ IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++
++
++ /* Check initialization has been done for trusted channels */
++ if (cd_p->trust == TRUE) {
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if ((bd_p->bufferAddr == DMA_ADDR_INVALID) ||
++ (bd_p->mode.count == 0)) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED |
++ IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ }
++
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ /* If transfer data size is used, check that the required read length is
++ * divisible by transfer data size expressed in bytes
++ */
++ if (cd_p->useDataSize) {
++ /* Check for divisibility only if data size different then 8bit */
++ if (cd_p->dataSize != TRANSFER_8BIT) {
++ switch(cd_p->dataSize) {
++ case TRANSFER_32BIT:
++ div = 4;
++ break;
++ case TRANSFER_16BIT:
++ div = 2;
++ break;
++ case TRANSFER_24BIT:
++ div = 3;
++ break;
++ /* we should not get to default */
++ default:
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ /* check the total number of bytes requested */
++ if ((nbyte % div) != 0) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ /* now check the length of every BD */
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if ((bd_p->mode.count % div) != 0) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ }
++ }
++
++ /*
++ * 2. Set the 'D' done bits on all buffer descriptors
++ */
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ bd_p->mode.status |= BD_DONE;
++ bd_p++;
++ }
++
++ /*
++ * 3. Starting of the channel
++ */
++ iapi_lowStartChannel(chNum);
++ ccb_p->status.execute = TRUE;
++ readBytes = 0;
++
++ /*
++ * 4. Synchronization mechanism handling
++ */
++ if (cd_p->callbackSynch == DEFAULT_POLL) {
++ iapi_SynchChannel(chNum);
++
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ toRead = nbyte;
++ copyFinished = FALSE;
++ local_buf = buf;
++
++ /*
++ * Check the 'RROR' bit on all buffer descriptors, set error number
++ * and return IAPI_FAILURE if set.
++ */
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if (bd_p->mode.status & BD_RROR) {
++ iapi_errno = IAPI_ERR_RROR_BIT_READ | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++
++
++ /*
++ * 5. Read loop
++ */
++
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ while (!copyFinished) {
++ if (!(bd_p->mode.status & BD_DONE)) {
++ if (cd_p->trust == FALSE) {
++ bufsize = cd_p->bufferSize;
++ } else {
++ bufsize = bd_p->mode.count;
++ }
++ /* if L bit is set, read only "count" bytes and exit the loop */
++ if (bd_p->mode.status & BD_LAST) {
++ bufsize = bd_p->mode.count;
++ copyFinished = TRUE;
++ }
++ if (toRead > bufsize) {
++ if (cd_p->trust == FALSE) {
++ iapi_memcpy(local_buf, iapi_Phys2Virt(bd_p->bufferAddr), bufsize);
++ local_buf += bufsize;
++ }
++ readBytes += bufsize;
++ toRead -= bufsize;
++ /* advance bd_p only if bit L is not set. The loop will exit anyway. */
++ if (!(bd_p->mode.status & BD_LAST)) {
++ if (bd_p->mode.status & BD_WRAP) {
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ } else if ((iapi_Phys2Virt(ccb_p->baseBDptr +
++ (cd_p->bufferDescNumber - 1) *
++ sizeof(bufferDescriptor))) != bd_p) {
++ bd_p++;
++ } else {
++ /* finished here : end of buffer descriptors */
++ copyFinished = TRUE;
++ }
++ }
++ } else {
++ if (cd_p->trust == FALSE) {
++ iapi_memcpy(local_buf, iapi_Phys2Virt(bd_p->bufferAddr), toRead);
++ local_buf += toRead;
++ }
++ readBytes += toRead;
++ toRead = 0;
++ /* finished successfully : readBytes = nbytes */
++ copyFinished = TRUE;
++ }
++ } else {
++ /* finished here : buffer not already done */
++ copyFinished = TRUE;
++ }
++ }
++ iapi_ReleaseChannel(chNum);
++ }
++
++ /*
++ *If synchronization type is callback, the user of I.API must
++ *release the channel
++ */
++ return readBytes;
++}
++
++/****************************************************************************
++ * Attempts to write nbyte from the buffer pointed to by buf to the channel
++ * data buffers associated with the opened channel number channelNumber
++ *
++ * <b>Algorithm:</b>\n
++ *
++ * - Check data structures are properly initialized:
++ * - Channel descriptor validity
++ * - Channel control block validity
++ * - Buffer descriptor validity
++ * - If transfer data size is used, check validity of combination transfer
++ * size/requested bytes
++ * - Write loop\n
++ * Write occurs in the buffer acceded form buffer descriptor and continues
++ * to the "next" buffer which can be:\n
++ * -# the last BD of the ring so re-start from beginning\n
++ * -# the last BD of the BD array but no ring so finish\n
++ * -# (general case) the next BD in the BD array\n
++ * And copy continues until data fit in the current buffer or the nbyte
++ * parameter is reached.
++ * - Starting of the channel
++ *
++ * <b>Notes:</b>\n
++ * 1) Virtual DMA SDMA channels are unidirectionnal, an iapi_Write authorized
++ * on a channel means that we are expecting to send to the SDMA. The
++ * meaning of an interrupt received from the SDMA is therfore that the
++ * data has been delivered to the SDMA.
++ *
++ * @param *cd_p chanenl descriptor for the channel to write to
++ * @param *buf buffer with data to be written
++ * @param nbyte number of bytes to write to channel
++ *
++ * @return
++ * - number of bytes written
++ * - -iapi_errno if failure
++ */
++int
++iapi_Write(channelDescriptor *cd_p, void *buf, unsigned short nbyte)
++{
++ int writtenBytes = 0;
++ unsigned int toWrite;
++ unsigned int copyFinished;
++ unsigned int buffsize;
++ unsigned int index = 0;
++ bufferDescriptor *bd_p;
++ channelControlBlock *ccb_p;
++ unsigned char *local_buf;
++ unsigned char chNum;
++ unsigned char div;
++
++ iapi_errno = IAPI_ERR_NO_ERROR;
++
++ /*
++ * 1. Check data structures are properly initialized
++ */
++ /* Channel descriptor validity */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Channel control block validity */
++ if (cd_p->ccb_ptr == NULL) {
++ iapi_errno = IAPI_ERR_CCB_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Control block & Descriptpor associated with the channel being worked on */
++ chNum = cd_p->channelNumber;
++ ccb_p = cd_p->ccb_ptr;
++
++ /* Try to aquire channel */
++ if (iapi_GetChannel(chNum) != 0) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | chNum;
++ return -iapi_errno;
++ }
++
++ /* Buffer descriptor validity */
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ if (bd_p == NULL) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++
++ /* Check initialization has been done for trusted channels */
++ if (cd_p->trust == TRUE) {
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if ((bd_p->bufferAddr == DMA_ADDR_INVALID) || (bd_p->mode.count == 0)) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ }
++
++
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ /* If transfer data size is used, check that the required write length is
++ * divisible by transfer data size expressed in bytes
++ */
++ if (cd_p->useDataSize) {
++ /* Check for divisibility only if data size different then 8bit */
++ if (cd_p->dataSize != TRANSFER_8BIT) {
++ switch(cd_p->dataSize) {
++ case TRANSFER_32BIT:
++ div = 4;
++ break;
++ case TRANSFER_16BIT:
++ div = 2;
++ break;
++ case TRANSFER_24BIT:
++ div = 3;
++ break;
++ default:
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ /* check the total number of bytes requested */
++ if ((nbyte % div) != 0) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ /* now check the length of every BD */
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if ((bd_p->mode.count % div) != 0) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ }
++ }
++
++ /*
++ * 2. Write loop
++ */
++ local_buf = buf;
++ toWrite = nbyte;
++ copyFinished = FALSE;
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++
++ while (!copyFinished) {
++ /* variable buffsize contains the number of bytes that the SDMA
++ * will transfer at each pass of the while loop */
++ /* in NON trusted mode, buffsize is copied from Channel
++ * descriptor bufferSize (same size for all transfers) */
++
++ if (cd_p->trust == FALSE) {
++ buffsize = cd_p->bufferSize;
++ } else {
++ /* in TRUSTED mode, it's up to the user to specify the size of each buffer thru an IoCtl call */
++ /* This IoCtl has directly modified the bd_p->mode.count */
++ /* therefore, buffersize is copied from the bd_p->mode.count */
++ buffsize = bd_p->mode.count;
++ }
++ DBG(-1, "%s: nbyte=%u towrite=%u buffsize=%u\n", __FUNCTION__,
++ nbyte, toWrite, buffsize);
++
++ /* in any mode (trusted or non trusted), the transfer size must be overridden by */
++ /* "toWrite" when there is less remaining bytes to transfer than the current buffer size */
++ if (toWrite < buffsize) {
++ buffsize = toWrite;
++ }
++
++ if (!(bd_p->mode.status & BD_DONE)) {
++ /* More data to write than a single buffer can contain */
++ if (cd_p->trust == FALSE) {
++ iapi_memcpy(iapi_Phys2Virt(bd_p->bufferAddr),
++ local_buf, buffsize);
++ local_buf += buffsize;
++ }
++
++ /* update the BD count that will be used by the SDMA to transfer the proper nb of bytes */
++ bd_p->mode.count = buffsize;
++
++ bd_p->mode.status |= BD_DONE;
++ writtenBytes += buffsize;
++ toWrite -= buffsize;
++ /* Prepares access to the "next" buffer */
++ if (toWrite == 0) {
++ /* - case 1 - finished successfully : writtenBytes = nbytes */
++ copyFinished = TRUE;
++ } else if ((bd_p->mode.status & BD_WRAP)) {
++ /* - case 2 - Last BD and WRAP bit set so re-start from beginning */
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ } else if ((iapi_Phys2Virt(
++ ccb_p->baseBDptr +
++ (cd_p->bufferDescNumber - 1) *
++ sizeof(bufferDescriptor))) ==
++ bd_p) {
++ /* - case 3 - Last BD of the BD but not ring */
++ copyFinished = TRUE;
++ } else {
++ /* - case 4 - general : next BD in the BD array */
++ bd_p++;
++ }
++ } else {
++ /* finished here : buffer not already done */
++ copyFinished = TRUE;
++ }
++ }
++
++ ccb_p->currentBDptr = ccb_p->baseBDptr;
++
++ /*
++ * 3. Starting of the channel
++ */
++ iapi_lowStartChannel(chNum);
++ ccb_p->status.execute = TRUE;
++
++ if (cd_p->callbackSynch == DEFAULT_POLL) {
++ iapi_SynchChannel(chNum);
++ /*
++ * Check the 'RROR' bit on all buffer descriptors, set error number
++ * and return IAPI_FAILURE if set.
++ */
++ bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if (bd_p->mode.status & BD_RROR) {
++ iapi_errno = IAPI_ERR_RROR_BIT_WRITE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ iapi_ReleaseChannel(chNum);
++ }
++
++ /*
++ * If synchronization type is callback, the user of I.API must
++ * release the channel
++ */
++ return writtenBytes;
++}
++
++/* ***************************************************************************/
++/* This function is used to receive data from the SDMA.
++ *
++ * <b>Algorithm:</b>\n
++ *
++ * The data control structure would be copied to IPCv1 complied Buffer
++ * Descriptor Array. This array shall be allocated from non cacheable memory.
++ * It would then provide this buffer descriptor array as an input to SDMA using
++ * channel control block and then configure the Host Enable (HE) or
++ * DSP enable (DE) bit of SDMA for the channel used for this transfer depending
++ * on the source.
++ *
++ * <b>Notes:</b>\n
++ * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized
++ * on a channel means that source processor is expecting to send to the destination
++ * processor. The meaning of an interrupt received from the SDMA notifies that the
++ * data has been delivered to the destination processor.
++ *
++ * @param *cd_p chanenl descriptor for the channel to receive from
++ * @param *data_control_struct_ipcv2
++
++ * Data Control structure:
++ * -------------------------
++ * | Data Node Descriptor 1|
++ * -------------------------
++ * | Data Node Descriptor 2|
++ * -------------------------
++ * | : |
++ * | : |
++ * -------------------------
++ * |Data Node Descriptor n |
++ * -------------------------
++ *
++ * Data Node Descriptor (Buffer Descriptor):
++ *------------------------------------------------------------------------------
++ *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
0|
++ *------------------------------------------------------------------------------
++ *| L E D R R R R R |<---- Reserved ----> |<- Length-> |
++ *------------------------------------------------------------------------------
++ *| <---------------------------- Data Ptr ----------------------------------->|
++ *------------------------------------------------------------------------------
++ *
++ * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame
++ * E bit (END): If set, we reached the end of the buffers passed to the function
++ * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been
++ * filled by the SDMA.
++ * Length: Length of data pointed by this node in bytes
++ * Data Ptr: Pointer to the data pointed to by this node.
++ * The Function Shall not be called for the same channel unless the Read callback has been
++ * received for channel for which it has been called already.
++ *
++ * @return
++ * - IAPI_SUCCESS on success, IAPI_ERROR otherwise
++ *
++ *- -iapi_errno if failure
++ */
++
++int iapi_Read_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2)
++{
++ channelControlBlock *ccb_p;
++/* The Parameters passed are considered to be validated by the upper layers */
++ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p;
++ dataNodeDescriptor *dnd_p = data_control_struct_ipcv2;
++
++ ccb_p = cd_p->ccb_ptr;
++ iapi_errno = IAPI_ERR_NO_ERROR;
++
++ if (ccb_p->baseBDptr == DMA_ADDR_INVALID) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ ccb_p->currentBDptr = ccb_p->baseBDptr;
++
++ /* Copy the data Node descriptor information to new BDs */
++ bd_ipcv2_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++
++ while (1) {
++ bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr;
++ bd_ipcv2_p->mode.count = dnd_p->mode.count;
++#ifdef MCU
++ bd_ipcv2_p->mode.endianness = 1;
++#endif
++#ifdef DSP
++ bd_ipcv2_p->mode.endianness = 0;
++#endif
++
++ bd_ipcv2_p->mode.status = dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK];
++
++ if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) {
++ /* Break the loop at End of Transfer */
++ break;
++ }
++ bd_ipcv2_p++;
++ dnd_p++;
++ }
++ /*
++ * Store the buffer address
++ */
++ dnd_read_control_struct[cd_p->channelNumber] = data_control_struct_ipcv2;
++ /*
++ * Register the Call Back
++ */
++
++ iapi_AttachCallbackISR(cd_p, iapi_read_ipcv2_callback);
++
++ /*
++ * Starting of the channel
++ */
++ iapi_lowStartChannel(cd_p->channelNumber);
++ ccb_p->status.execute = TRUE;
++
++ return IAPI_SUCCESS;
++}
++
++
++/* ***************************************************************************/
++/*
++ * The function is used send a group of buffers to SDMA.
++ * <b>Algorithm:</b>\n
++ *
++ * The data control structure would be copied to IPCv1 complied Buffer
++ * Descriptor Array. This array shall be allocated from non cacheable memory.
++ * It would then provide this buffer descriptor array as an input to SDMA using
++ * channel control block and then configure the Host Enable (HE) or
++ * DSP enable (DE) bit of SDMA for the channel used for this transfer depending
++ * on the source.
++ * The Function Shall not be called for the same channel unless the Read callback has been
++ * received for channel for which it has been called already.
++ *
++ * <b>Notes:</b>\n
++ * Virtual DMA channels are unidirectional, an iapi_Write_ipcv2 authorized
++ * on a channel means that source processor is expecting to send to the destination
++ * processor. The meaning of an interrupt received from the SDMA notifies that the
++ * data has been delivered to the destination processor.
++ *
++ * @param *cd_p chanenl descriptor for the channel to write to
++ * @param *data_control_struct_ipcv2
++
++ * Data Control structure:
++ * -------------------------
++ * | Data Node Descriptor 1|
++ * -------------------------
++ * | Data Node Descriptor 2|
++ * -------------------------
++ * | : |
++ * | : |
++ * -------------------------
++ * |Data Node Descriptor n |
++ * -------------------------
++ *
++ * Data Node Descriptor (Buffer Descriptor):
++ *------------------------------------------------------------------------------
++ *| 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15
0|
++ *------------------------------------------------------------------------------
++ *| L E D R R R R R |<---- Reserved ----> |<- Length-> |
++ *------------------------------------------------------------------------------
++ *| <---------------------------- Data Ptr ----------------------------------->|
++ *------------------------------------------------------------------------------
++ *
++ * L bit (LAST): If set, means that this buffer of data is the last buffer of the frame
++ * E bit (END): If set, we reached the end of the buffers passed to the function
++ * D bit (DONE): Only valid on the read callback. When set, means that the buffer has been
++ * filled by the SDMA.
++ * Length: Length of data pointed by this node in bytes
++ * Data Ptr: Pointer to the data pointed to by this node.
++ *
++ *
++ * @return
++ * - iapi sucess on success.
++ * - -iapi_errno if failure
++ */
++
++int iapi_Write_ipcv2(channelDescriptor *cd_p, void *data_control_struct_ipcv2)
++{
++ channelControlBlock *ccb_p;
++/* The Parameters passed are considered to be validated by the upper layers */
++ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p;
++ dataNodeDescriptor *dnd_p = data_control_struct_ipcv2;
++ ccb_p = cd_p->ccb_ptr;
++ iapi_errno = IAPI_ERR_NO_ERROR;
++
++ if (ccb_p->baseBDptr == DMA_ADDR_INVALID) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ ccb_p->currentBDptr = ccb_p->baseBDptr;
++
++ bd_ipcv2_p = iapi_Phys2Virt(ccb_p->currentBDptr);
++ /* Copy the data Node descriptor information to new BDs */
++ while (1) {
++ bd_ipcv2_p->bufferAddr = dnd_p->bufferAddr;
++ bd_ipcv2_p->mode.count = dnd_p->mode.count;
++
++#ifdef MCU
++ bd_ipcv2_p->mode.endianness = 1;
++#endif
++#ifdef DSP
++ bd_ipcv2_p->mode.endianness = 0;
++#endif
++
++ bd_ipcv2_p->mode.status = dnd_2_bd_status[dnd_p->mode.status & GET_LED_MASK];
++
++ if ((dnd_p->mode.status & DND_END_OF_XFER) != 0) {
++ /* Break the loop at End of Transfer */
++ break;
++ }
++ bd_ipcv2_p++;
++ dnd_p++;
++ }
++
++ /*
++ * Starting of the channel
++ */
++ iapi_lowStartChannel(cd_p->channelNumber);
++ ccb_p->status.execute = TRUE;
++
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/** Call back ISR for the IPCv2 Receive.
++ *
++ * <b>Algorithm:</b>\n
++ * - This would copy back the informationfrom IPCv1 BD to IPCv2 BD on
++ * the receiving processor
++ *
++ * @return
++ * - void
++ */
++
++static void iapi_read_ipcv2_callback(struct iapi_channelDescriptor *cd_p, void *data)
++{
++ dataNodeDescriptor *dnd_p = dnd_read_control_struct[cd_p->channelNumber];//cd_p->ccb_ptr->channelDNDBuffer;
++ bufferDescriptor_ipcv1_v2 *bd_ipcv2_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ int index;
++
++ for (index = MAX_BD_NUM - 1; index >= 0; index--) {
++ dnd_p->mode.status = 0;
++ dnd_p->mode.count = bd_ipcv2_p->mode.count;
++
++ dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_DONE ? 0x00 : DND_DONE;
++ dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_IPCV2_END_OF_FRAME ? DND_END_OF_FRAME : 0x00;
++ dnd_p->mode.status |= bd_ipcv2_p->mode.status & BD_LAST ? DND_END_OF_XFER : 0x00;
++ cd_p->ccb_ptr->currentBDptr = iapi_Virt2Phys(bd_ipcv2_p);
++
++ if ((bd_ipcv2_p->mode.status & BD_LAST) ||
++ !(bd_ipcv2_p->mode.status & BD_CONT))
++ break;
++ dnd_p++;
++ bd_ipcv2_p++;
++ }
++
++ /* Call back the Original ISR */
++ cd_p->callbackISR_ptr(cd_p, data);
++}
++
++/* ***************************************************************************/
++/**Terminates a channel.
++ *
++ * <b>Algorithm:</b>\n
++ * - Check input parameters ans data structures
++ * - Check that all buffes have been processed (test all 'D' bits)
++ * - Stop the channel execution
++ * - Free alocated memory structures
++ * - Re-instantiate default interrupt handling
++ *
++ * @param *cd_p chanenl descriptor for the channel to close
++ *
++ * @return
++ * - IAPI_SUCCESS : OK
++ * - -iapi_errno : close failed
++ */
++int
++iapi_Close(channelDescriptor *cd_p)
++{
++ int index = 0;
++ unsigned char chNum;
++ channelControlBlock *ccb_p;
++
++ /*
++ * 1. Check input parameters ans data structures
++ */
++ if (cd_p != NULL) {
++ if (cd_p->ccb_ptr != NULL) {
++ chNum = cd_p->channelNumber;
++ ccb_p = cd_p->ccb_ptr;
++ } else {
++ iapi_errno = IAPI_ERR_NO_CCB_DEFINED | IAPI_ERR_CH_AVAILABLE;
++ return -iapi_errno;
++ }
++ } else {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE;
++ return -iapi_errno;
++ }
++ /* Try to aquire channel */
++ if (iapi_GetChannel(chNum) != 0) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | chNum;
++ return -iapi_errno;
++ }
++
++ /*
++ * 2. Check that all buffes have been processed (test all 'D' bits),
++ * only if the forceClose bit in channel descriptor is set to FALSE
++ */
++ if (ccb_p->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++
++ if (bd_p == NULL) {
++ iapi_errno = IAPI_ERR_BD_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE | chNum;
++ return -iapi_errno;
++ }
++ if (cd_p->forceClose == FALSE) {
++ for (index = cd_p->bufferDescNumber; index > 0; index--) {
++ if (bd_p->mode.status & BD_DONE) {
++ iapi_errno = IAPI_ERR_CLOSE | IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_ReleaseChannel(chNum);
++ return -iapi_errno;
++ }
++ bd_p++;
++ }
++ } else {
++ /* if the closing is forced, mark channel unused and
++ * set BD ownership to processor
++ */
++ ccb_p->status.execute = FALSE;
++ for (index = cd_p->bufferDescNumber; index > 0; index--) {
++ bd_p->mode.status &= ~BD_DONE;
++ bd_p++;
++ }
++ }
++ }
++
++ /*
++ * 3. Stop the channel execution
++ */
++ iapi_lowStopChannel(chNum);
++
++ /*
++ * 4. Free alocated memory structures
++ */
++ if (cd_p->trust == FALSE && ccb_p->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bd_p = iapi_Phys2Virt(ccb_p->baseBDptr);
++
++ for (index = cd_p->bufferDescNumber; index > 0; index--) {
++ FREE(iapi_Phys2Virt(bd_p->bufferAddr));
++ bd_p++;
++ }
++ }
++
++ /*
++ * 5. Re-instantiate default interrupt handling
++ */
++ iapi_DetachCallbackISR(cd_p);
++ if (ccb_p->baseBDptr != DMA_ADDR_INVALID) {
++ FREE(iapi_Phys2Virt(ccb_p->baseBDptr));
++ ccb_p->baseBDptr = DMA_ADDR_INVALID;
++ ccb_p->currentBDptr = DMA_ADDR_INVALID;
++ }
++ FREE(cd_p);
++ ccb_p->channelDescriptor = NULL;
++ ccb_p->status.openedInit = FALSE;
++
++ iapi_ReleaseChannel(chNum);
++
++ return IAPI_SUCCESS;
++}
++
++static inline int iapi_clr_status(channelDescriptor *cd_p, unsigned long param,
++ unsigned long mask)
++{
++ int retvalue = IAPI_SUCCESS;
++ bufferDescriptor *bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ if (param == SET_BIT_ALL) {
++ int j;
++
++ for (j = 0; j < cd_p->bufferDescNumber; j++) {
++ bde_p->mode.status &= ~mask;
++ bde_p++;
++ }
++ } else if (param < cd_p->bufferDescNumber) {
++ bde_p[param].mode.status &= ~mask;
++ } else {
++ retvalue = IAPI_FAILURE;
++ }
++ return retvalue;
++}
++
++static inline int iapi_set_status(channelDescriptor *cd_p, unsigned long param,
++ unsigned long mask)
++{
++ int retvalue = IAPI_SUCCESS;
++ bufferDescriptor *bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ if (param == SET_BIT_ALL) {
++ int j;
++
++ for (j = 0; j < cd_p->bufferDescNumber; j++) {
++ bde_p->mode.status |= mask;
++ bde_p++;
++ }
++ } else if (param < cd_p->bufferDescNumber) {
++ bde_p[param].mode.status |= mask;
++ } else {
++ retvalue = IAPI_FAILURE;
++ }
++ return retvalue;
++}
++
++static inline int iapi_set_command(channelDescriptor *cd_p, unsigned long param,
++ unsigned long cmd)
++{
++ int retvalue = IAPI_SUCCESS;
++ bufferDescriptor *bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ if (param == SET_BIT_ALL) {
++ int j;
++
++ for (j = 0; j < cd_p->bufferDescNumber; j++) {
++ bde_p->mode.command = cmd;
++ bde_p++;
++ }
++ } else if (param < cd_p->bufferDescNumber) {
++ bde_p[param].mode.command = cmd;
++ } else {
++ retvalue = IAPI_FAILURE;
++ }
++ return retvalue;
++}
++
++/* ***************************************************************************/
++/**The request argument selects the control function to be performed.
++ *
++ * <b>Algorithm:</b>\n
++ *
++ * - Check data structures are properly initialized:
++ * - Channel descriptor validity
++ * - Channel control block validity
++ * - The ctlRequest parameter contains in the lower 16 bits the control code of
++ * the change to be performed, and in the upper 16 bits, the BD to be
++ * modified if the change affects a BD od the channel.
++ * - Selection of the parameter to change and appropriate sanity checks:
++ * - Channel Descriptor: changes the pointer to the channel descriptor
++ * structure, the pointer to the new channel descriptor is given in the third
++ * argument call
++ * - Buffer Descriptor Number: changes the number of buffer descriptor for the
++ * channel
++ * - Buffer size: changes the size of the data buffers pointed to by the
++ * buffer descriptor; note that all buffer descriptors are assumed to have the
++ * same size for a given buffer descripotr chain
++ * - Blocking policy: changes the blocking policy for the read and write calls
++ * - Ownership: changes direction: turnaround
++ * - Synchronization method: changes the callback type, default or user. The *
++ * callback function table is set accordingly
++ * - Trust property: trust can only be changed through ChangeChannelDesc first
++ * request, this guarantees the close/open sequence for the channel
++ * - Callback Interrupt service routine pointer: changes the callback function
++ * pointer, when this method is used, to replace it with a new one
++ * - Channel control block pointer: not available
++ * - Priority: changes the channel priority directly in SDMA register
++ * - Watermark level: changes the value of the peripheral watermark level that
++ * passed to the script. The new value is passed in the third parameter call.
++ * - Wrap bit: changes to set to 1 the Wrap bit of the last buffer descriptor
++ *
++ * @param *cd_p channel descriptor for the channel to modify
++ * @param ctlRequest request control code and, if tha case, number of BD to be
++ * changed
++ * @param param parameter for the modification
++ *
++ * @return
++ * - IAPI_SUCCESS : OK
++ * - -iapi_errno : operation failed
++ */
++int
++iapi_IoCtl(channelDescriptor *cd_p, unsigned long ctlRequest,
++ unsigned long param)
++{
++ int result = IAPI_SUCCESS;
++ unsigned char chNum;
++ unsigned long clean_ctlRequest; /* lower 16 bits of the ctlRequest */
++ unsigned long bd_num; /* upper 16 bits of the ctlRequest */
++
++ DBG(0, "%s: cd=%p req=%08lx param=%08lx\n", __FUNCTION__,
++ cd_p, ctlRequest, param);
++ /*
++ * 1. Check data structures are properly initialized
++ */
++ /* Channel descriptor validity */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Channel control block validity */
++ if (cd_p->ccb_ptr == NULL) {
++ iapi_errno = IAPI_ERR_CCB_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Control block & Descriptor associated with the channel being worked on */
++ chNum = cd_p->channelNumber;
++
++ /* Remove, if exists, BD number specified in upper bits of ctlRequest */
++ clean_ctlRequest = ctlRequest & ~BD_NUM_MASK;
++
++ /* Extract, if exists, BD number specified in upper bits of ctlRequest */
++ bd_num = (ctlRequest & BD_NUM_MASK) >> BD_NUM_OFFSET;
++
++ /* Check that the bd_num is valid */
++ if (bd_num >= cd_p->bufferDescNumber) {
++ DBG(0, "%s: BD number %lu out of range: %u\n", __FUNCTION__,
++ bd_num, cd_p->bufferDescNumber);
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | chNum;
++ return -iapi_errno;
++ }
++
++ /* All checks OK, try to aquire channel */
++ if (iapi_GetChannel(chNum) != 0) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | chNum;
++ return -iapi_errno;
++ }
++
++ /*
++ * 2. Selection of the parameter to change and appropriate sanity checks
++ */
++ switch (clean_ctlRequest) {
++ case IAPI_CHANGE_CHANDESC:
++ /*
++ * Channel Descriptor
++ * --- Changes the pointer to the channel descriptor structure: the pointer
++ * to the new channel descriptor is given in the third argument call.
++ */
++ if ((void *)param == NULL) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER;
++ result = -iapi_errno;
++ } else {
++ channelDescriptor *chParam = (channelDescriptor *)param;
++
++ if (chParam->channelNumber != chNum) {
++ /* Release ch so it can be aquired by the Close fn */
++ iapi_ReleaseChannel(chNum);
++ result = iapi_Close(cd_p);
++ if (result == IAPI_SUCCESS) {
++ FREE(cd_p);
++ iapi_AllocChannelDesc(&cd_p,
++ chParam->channelNumber);
++ iapi_memcpy(cd_p, chParam,
++ sizeof(channelDescriptor));
++ /* Channel is released allready, so Open can get the channel */
++ result = iapi_Open(cd_p,
++ chParam->channelNumber);
++ if (result != IAPI_SUCCESS) {
++ return result; /* error code already set in iapi_Open */
++ }
++ } else {
++ return result; /* error code already set in iapi_Close */
++ }
++ } else {
++ iapi_errno = IAPI_ERR_CD_CHANGE |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ result = -iapi_errno;
++ break;
++ }
++ }
++ break;
++
++ case IAPI_CHANGE_BDNUM:
++ /*
++ * Buffer Descriptor Number
++ * --- Changes the number of buffer descriptor for the channel.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, param);
++ break;
++
++ case IAPI_CHANGE_BUFFSIZE:
++ /*
++ * Buffer size
++ * --- Changes the size of the data buffers pointed to by the buffer
++ * descriptor; note that all buffer descriptors are assumed to have the
++ * same size for a given buffer descripotr chain.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, param);
++ break;
++
++ case IAPI_CHANGE_CHANBLOCK:
++ /*
++ * Blocking policy
++ * --- Changes the blocking policy for the read and write calls.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BLOCKING, param);
++ break;
++
++ case IAPI_CHANGE_OWNERSHIP:
++ /*
++ * Ownership
++ * --- Changes direction: turnaround
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_OWNERSHIP, param);
++ break;
++
++ case IAPI_CHANGE_SYNCH:
++ /*
++ * Synchronization method
++ * --- Changes the callback type, default or user. The callback function
++ * table is set accordingly.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKSYNCH, param);
++ break;
++
++ case IAPI_CHANGE_TRUST:
++ /*
++ * Trust property
++ * --- trust can only be changed through ChangeChannelDesc first request,
++ * this guarantees the close/open sequence for the channel.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, param);
++ break;
++
++ case IAPI_CHANGE_CALLBACKFUNC:
++ /*
++ * Callback Interrupt service routine pointer
++ * --- Cahnges the callback function pointer, when this method is used, to
++ * replace it with a new one.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_CALLBACKISR_PTR, param);
++ break;
++
++ case IAPI_CHANGE_CHANCCB:
++ /*
++ * Channel control block pointer
++ * --- NA
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_CCB_PTR, param);
++ break;
++#ifdef MCU
++ case IAPI_CHANGE_PRIORITY:
++ /*
++ * Priority
++ * --- Changes the channel priority directly in SDMA register
++ */
++ if (param < MAX_CH_PRIORITY) {
++ __raw_writel(param, SDMA_CHNPRI(cd_p->channelNumber));
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++#endif /* MCU */
++ case IAPI_CHANGE_BDWRAP:
++ /*
++ * Wrap
++ * --- Set to 1 the wrap bit of the last buffer descriptor of the array.
++ * it provides the possibility to have a circular buffer structure.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BDWRAP, param);
++ break;
++
++ case IAPI_CHANGE_WATERMARK:
++ /*
++ * Watermark
++ * --- Changes the value of the peripheral watermark level that triggers
++ * a DMA request. It impacts context of the channel, therefore channel 0
++ * must be started to update the context with this new value.
++ */
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_WML, param);
++ break;
++
++ case IAPI_CHANGE_SET_BDINTR:
++ /*
++ * INTR
++ * --- Set the INTR bit on specified BD or on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_set_status(cd_p, param, BD_INTR);
++ break;
++
++ case IAPI_CHANGE_UNSET_BDINTR:
++ /*
++ * INTR
++ * --- Unset the INTR bit on specified BD or on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_clr_status(cd_p, param, BD_INTR);
++ break;
++
++ case IAPI_CHANGE_EVTMASK1:
++ /*
++ * EventMask1
++ * --- Changes the value of the eventMask1
++ */
++ cd_p->eventMask1 = param;
++ break;
++
++ case IAPI_CHANGE_EVTMASK2:
++ /*
++ * EventMask2
++ * --- Changes the value of the eventMask2
++ */
++ cd_p->eventMask2 = param;
++ break;
++
++ case IAPI_CHANGE_PERIPHADDR:
++ /*
++ * Peripheral Address
++ * --- Changes the value of the peripheralAddr
++ */
++ cd_p->peripheralAddr = param;
++ break;
++
++ case IAPI_CHANGE_SET_BDCONT:
++ /*
++ * Cont
++ * --- Set the CONT bit on specified BD on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_set_status(cd_p, param, BD_CONT);
++ break;
++
++ case IAPI_CHANGE_UNSET_BDCONT:
++ /*
++ * Cont
++ * --- Unset the CONT bit on specified BD or on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_clr_status(cd_p, param, BD_CONT);
++ break;
++
++ case IAPI_CHANGE_SET_BDEXTD:
++ /*
++ * EXTD
++ * --- Set the EXTD bit on specified BD or on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_set_status(cd_p, param, BD_EXTD);
++ break;
++
++ case IAPI_CHANGE_UNSET_BDEXTD:
++ /*
++ * EXTD
++ * --- Unset the EXTD bit on specified BD or on all BD's if SET_BIT_ALL
++ * is passed as parameter.
++ */
++ result = iapi_clr_status(cd_p, param, BD_EXTD);
++ break;
++
++ case IAPI_CHANGE_SET_TRANSFER_CD:
++ /*
++ * TRANSFER SIZE to be used for this channel
++ * --- Set the transfer size used indicator and code for transfer size in
++ * the CD
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++ int j;
++
++ if ((param == TRANSFER_8BIT) || (param == TRANSFER_16BIT) ||
++ (param == TRANSFER_24BIT) || (param == TRANSFER_32BIT)) {
++ cd_p->useDataSize = TRUE;
++ cd_p->dataSize = param;
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ for (j = 0; j < cd_p->bufferDescNumber; j++) {
++ bde_p->mode.command = param;
++ bde_p++;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_USER_ARG:
++ /*
++ * USER_ARG
++ * --- Set the user selectable pointer to be received by the callback
++ * function, if IRQ synch is used
++ */
++ userArgTable[cd_p->channelNumber]= (void *)param;
++ break;
++
++ case IAPI_CHANGE_FORCE_CLOSE:
++ /*
++ * FORCE_CLOSE
++ * --- Set the forceClose bit in channelDescriptor to value passed in param.
++ * If this bit is TRUE, the channel in closed even if some BD are still
++ * owned by the SDMA.
++ */
++ if ((param == TRUE) || (param == FALSE)) {
++ cd_p->forceClose = param;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | cd_p->channelNumber;
++ result = -iapi_errno;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_TRANSFER:
++ /*
++ * TRANSFER type
++ * --- Set the last 2 bits in the command field of the BD to specify the
++ * transfer type 8, 16, 24, or 32 bits on all BD's, allready set in the CD
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ if ((param == TRANSFER_8BIT) || (param == TRANSFER_16BIT) ||
++ (param == TRANSFER_24BIT) || (param == TRANSFER_32BIT)) {
++ int j;
++
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ for (j = 0; j < cd_p->bufferDescNumber; j++) {
++ bde_p->mode.command = param;
++ bde_p++;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_BUFFERADDR:
++ /*
++ * BUFFER address
++ * --- Change buffer address in BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++
++ /* DO NOT translate address to physical */
++ bde_p->bufferAddr = (dma_addr_t)param;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_GET_BUFFERADDR:
++ /*
++ * BUFFER address
++ * --- Get the buffer address from the BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++ dma_addr_t *retval = (dma_addr_t *)param;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* DO NOT Translate to virtual */
++ *retval = bde_p->bufferAddr;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_EXTDBUFFERADDR:
++ /*
++ * EXTENDED BUFFER address
++ * --- Change extended buffer address in BD specified in the upper 16 bits
++ * of the ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++
++ /* DO NOT translate address to physical. The user might want something else
++ * here
++ */
++ bde_p->extBufferAddr = (dma_addr_t)param;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_GET_EXTDBUFFERADDR:
++ /*
++ * EXTENDED BUFFER address
++ * --- Get extended buffer address from the BD specified in the upper 16 bits
++ * of the ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++ dma_addr_t *retval = (dma_addr_t *)param;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++
++ /* DO NOT translate address to vitual - user knows what is here.
++ */
++ *retval = bde_p->extBufferAddr;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_COMMAND:
++ /*
++ * COMMAND field
++ * --- Change command field in BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Update command field */
++ bde_p->mode.command = param;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_GET_COMMAND:
++ /*
++ * COMMAND field
++ * --- Get the command field from the BD specified in the upper 16 bits
++ * of the ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Get the command field */
++ *((unsigned long *)param) = bde_p->mode.command;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_COUNT:
++ /*
++ * COUNT field
++ * --- Change count field in BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Update count field */
++ bde_p->mode.count = param;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_GET_COUNT:
++ /*
++ * COUNT field
++ * --- Get the count field of the BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Update count field */
++ *((unsigned long *)param) = bde_p->mode.count;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_SET_STATUS:
++ /*
++ * STATUS field
++ * --- Change status field in BD specified in the upper 16 bits of the
++ * ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Update status field */
++ DBG(1, "%s: BD[%ld] %08x->%08lx\n", __FUNCTION__,
++ bd_num, bde_p->mode.status, param);
++ bde_p->mode.status = param;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ case IAPI_CHANGE_GET_STATUS:
++ /*
++ * STATUS field
++ * --- Get the status field of the BD specified in the upper 16 bits
++ * of the ctlRequest.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ /* Get pointer to the BD structure to change */
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ /* Update status field */
++ *((unsigned long *)param) = bde_p->mode.status;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++#ifdef MCU
++ case IAPI_CHANGE_SET_ENDIANNESS:
++ /*
++ * Endianness
++ * --- Set the ENDIANNESS indicator in the command filed of the specified BD
++ * or on all BD's if SET_BIT_ALL is passed as parameter.
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ if (param == SET_BIT_ALL) {
++ int j;
++
++ for (j = 0; j < cd_p->bufferDescNumber; j++, bde_p++) {
++ /* Clear the respective bits in the command field
++ * and set the new parameter value
++ */
++ bde_p->mode.command &= ~ENDIANNESS_MASK;
++ bde_p->mode.command |= CHANGE_ENDIANNESS &
++ ENDIANNESS_MASK;
++ }
++ } else if (param < cd_p->bufferDescNumber) {
++ bde_p[param].mode.command &= ~ENDIANNESS_MASK;
++ bde_p[param].mode.command |= CHANGE_ENDIANNESS &
++ ENDIANNESS_MASK;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++#ifdef SDMA_V2
++ case IAPI_ENTER_LOCK_MODE:
++ /*
++ * SDMA State
++ * --- Enter the SDMA into LOCK Mode. No RAM update allowed except same Context
++ * update with same PC Value.
++ */
++ if (param == RESET_CLEAR_LOCK) {
++ __raw_writel(1 << RESET_CLR_BIT_OFFSET, SDMA_SDMA_LOCK);
++ __raw_writel(1 << LOCK_BIT_OFFSET, SDMA_SDMA_LOCK);
++ iapi_SdmaState = LOCK;
++ } else if (param == RESET_NOCLEAR_LOCK) {
++ __raw_writel(1 << LOCK_BIT_OFFSET, SDMA_SDMA_LOCK);
++ iapi_SdmaState = LOCK;
++ }
++ break;
++#endif
++#endif
++ case IAPI_CHANGE_SET_INTR_MASK:
++ /*
++ * Interrupt Mask
++ * --- Sets the Interrupt Mask directly in SDMA register. Can be used to set
++ * mask per channel or for all channels(SET_BIT_ALL)
++ * In case of error, the error reflects the channel number the error is received for.
++ */
++ if (param == SET_BIT_ALL) {
++ result = iapi_lowChangeIntrMask(SET_BIT_ALL, OR_OP);
++ } else {
++ /* chnum is Extracted earlier in iapi_Ioctl() and checked for validity */
++ result = iapi_lowChangeIntrMask(1 << chNum, OR_OP);
++ }
++ /* iapi_errno has been set by iapi_lowChangeIntrMask() */
++ if (result != IAPI_SUCCESS)
++ result |= IAPI_ERR_CH_AVAILABLE | chNum;
++ break;
++
++ case IAPI_CHANGE_UNSET_INTR_MASK:
++ /*
++ * Interrupt Mask
++ * --- Clears the Interrupt Mask directly in SDMA register. Can be used to clear
++ * mask per channel or for all channels(SET_BIT_ALL)
++ * In case of error, the error reflects the channel number the error is received for.
++ */
++ if (param == SET_BIT_ALL) {
++ result = iapi_lowChangeIntrMask(~SET_BIT_ALL, AND_OP);
++ } else {
++ result = iapi_lowChangeIntrMask(~(1 << chNum), AND_OP);
++ }
++ /* iapi_errno has been set by iapi_lowChangeIntrMask() */
++ if (result != IAPI_SUCCESS)
++ result |= IAPI_ERR_CH_AVAILABLE | chNum;
++ break;
++
++ case IAPI_CHANGE_BUFFER_LOCATION:
++ /* Buffer Location
++ * Set whether Buffer is located in External Memory or Internal Memory
++ */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ bufferDescriptor *bde_p;
++
++ bde_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bde_p += bd_num;
++ if ((param == EXTERNAL_MEM) || (param == INTERNAL_MEM)) {
++ /* Clear the respective bits in the command field
++ * and set the new parameter value
++ */
++ bde_p->mode.command &= ~BUFFER_LOC_MASK;
++ bde_p->mode.command |= param & BUFFER_LOC_MASK;
++ } else {
++ result = IAPI_FAILURE;
++ }
++ } else {
++ result = IAPI_FAILURE;
++ }
++ break;
++
++ default:
++ iapi_errno = IAPI_ERR_CD_CHANGE_UNKNOWN |
++ IAPI_ERR_CH_AVAILABLE | chNum;
++ result = -iapi_errno;
++ }
++
++ iapi_ReleaseChannel(chNum);
++ return result;
++}
++
++/* ***************************************************************************/
++/**Initialization of the SDMA - opening of channel 0, download RAM image.
++ *
++ * <b>Algorithm:</b>\n
++ * - open channel 0
++ * - if ram_image pointer passed is not NULL, download RAM image to SDMA
++ *
++ * @param
++ * - cd_p channel descriptor pointer for channel 0
++ * - ram_image pointer to RAM image to download, or NULL if this operation
++ * is not required
++ * - code_size size of the RAM image, in bytes
++ * - start_addr start address for the RAM image
++ *
++ * @return
++ * - IAPI_SUCCESS if all operations were successful
++ * - negated I.API error code if any operation failed
++ */
++#ifdef MCU
++int
++iapi_Init(channelDescriptor *cd_p, configs_data *config_p, unsigned short *ram_image,
++ unsigned short code_size, dma_addr_t start_addr, unsigned short channel0_addr)
++{
++#endif
++#ifdef DSP
++int
++iapi_Init(channelDescriptor *cd_p)
++{
++#endif
++ int retvalue; /* Variable to store the results from I.API calls */
++
++ /* Check initialization not allredy done */
++ if (iapi_CCBHead != NULL) {
++ iapi_errno = IAPI_ERR_NOT_ALLOWED;
++ return -iapi_errno;
++ }
++ /* Be sure SDMA has not started yet */
++#ifdef MCU
++ __raw_writel(0, SDMA_H_C0PTR);
++#endif
++#ifdef DSP
++ __raw_writel(0, SDMA_D_C0PTR);
++#endif
++
++ /* Try to open channel 0 */
++ retvalue = iapi_Open(cd_p, 0);
++ if (retvalue != IAPI_SUCCESS) {
++ return retvalue;
++ }
++#if 0
++ print_hex_dump(KERN_DEBUG, "sdma: ", DUMP_PREFIX_ADDRESS, 4, 4,
++ cd_p->ccb_ptr, CH_NUM * sizeof(channelControlBlock), 0);
++#endif
++#ifdef MCU
++ /* Set Command Channel (Channel Zero) */
++ __raw_writel(0x4000 | (channel0_addr & 0x3FFF), SDMA_CHN0ADDR);
++
++ /* Set bits of CONFIG register but with static context switching */
++ __raw_writel((config_p->dspdma << 12) | (config_p->rtdobs << 11) |
++ (config_p->acr << 4), SDMA_H_CONFIG);
++
++ /* Send the address for the host channel table to the SDMA */
++ __raw_writel(iapi_Virt2Phys(iapi_CCBHead), SDMA_H_C0PTR);
++ /* If required, download the RAM image for SDMA */
++ if (ram_image != NULL) {
++ retvalue = iapi_SetScript(cd_p, ram_image, code_size,
++ start_addr);
++ }
++
++ /* Set bits of CONFIG register with given context switching mode */
++ __raw_writel((config_p->dspdma << 12) | (config_p->rtdobs << 11) |
++ (config_p->acr << 4) | config_p->csm, SDMA_H_CONFIG);
++
++#endif
++#ifdef DSP
++ /* Send the address for the host channel table to the SDMA */
++ __raw_writel(iapi_Virt2Phys(iapi_CCBHead), SDMA_D_C0PTR);
++#endif
++
++#ifdef SDMA_V2
++ iapi_SdmaState = OPEN;
++#endif
++ return retvalue;
++}
++
++
++/* ***************************************************************************/
++/**High layer interface for starting a channel
++ *
++ * <b>Algorithm:</b>\n
++ * - call low layer function for starting a channel
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_StartChannel(unsigned char channel)
++{
++ iapi_lowStartChannel(channel);
++ return IAPI_SUCCESS;
++}
++/* ***************************************************************************/
++/**High layer interface for stopping a channel
++ *
++ * <b>Algorithm:</b>\n
++ * - call low layer function for stopping a channel
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_StopChannel(unsigned char channel)
++{
++ iapi_lowStopChannel(channel);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**High layer interface for synchronising a channel
++ *
++ * <b>Algorithm:</b>\n
++ * - call low layer function for stopping a channel
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int iapi_SynchChannel(unsigned char channel)
++{
++ iapi_lowSynchChannel(channel);
++ return IAPI_SUCCESS;
++}
++
++#ifdef MCU
++/* ***************************************************************************/
++/**High layer interface for getting program memory data from SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_GetScript(channelDescriptor *cd_p, void *buf, unsigned short size,
++ dma_addr_t address)
++{
++ iapi_lowGetScript(cd_p, buf, size, address);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**High layer interface for getting data memory from SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_GetContext(channelDescriptor *cd_p, void *buf, unsigned char channel)
++{
++ iapi_lowGetContext(cd_p, buf, channel);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**High layer interface for set program memory data to SDMA - e.g. scripts
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_SetScript(channelDescriptor *cd_p, void *buf, unsigned short nbyte,
++ dma_addr_t destAddr)
++{
++ iapi_lowSetScript(cd_p, buf, nbyte, destAddr);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**High layer interface for set data memory to SDMA - e.g. contexts.
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_SetContext(channelDescriptor *cd_p, void *buf, unsigned char channel)
++{
++ iapi_lowSetContext(cd_p, buf, channel);
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**High layer interface used to associate specified channel with a script.
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_AssignScript(channelDescriptor *cd_p, script_data *data_p)
++{
++ /* VERIFY THAT THE CHANNEL IT IS OPENED !!!! */
++ return iapi_lowAssignScript(cd_p, data_p);
++}
++
++/* ***************************************************************************/
++/**High layer interface used to associate specified channel with a script.
++ *
++ * <b>Algorithm:</b>\n
++ * - call coresponding low layer function
++ *
++ * @return
++ * - IAPI_SUCCESS
++ */
++int
++iapi_SetChannelEventMapping(unsigned char event, unsigned long channel_map)
++{
++ return iapi_lowSetChannelEventMapping(event, channel_map);
++}
++#endif
++
++
++
++#ifdef DSP
++#define SDMA_DI SDMA_D_INTR
++void IRQ_Handler();
++#pragma interrupt IRQ_Handler
++#endif
++
++#ifdef MCU
++#define SDMA_DI SDMA_H_INTR
++#endif
++
++#ifndef IRQ_KEYWORD
++#define IRQ_KEYWORD
++#endif /* IRQ_KEYWORD */
++
++/* ***************************************************************************/
++/**
++ *@brief Find the first set bit in data parameter.
++ *
++ * Find the first set bit in unsigned integer parameter data. Data is scanned
++ * from MSB to LSB, searching for the set bit. The value returned is the
++ * offset from the most significant bit of data. If bit 31 is set, the value
++ * returned is zero. If no bits are set, a value of 32 is returned. This is compliant
++ * with the MCore FF1 instruction.
++ *
++ *
++ *
++ * @param
++ * - data: variable to check
++ *
++ * @return
++ * - the offset of the most significant bit set from the MSB
++ */
++static unsigned int
++quartz_FF1(unsigned int data)
++{
++ register unsigned int result = 0;
++ while ((result <= 31) && !(data & 0x80000000U)) {
++ data <<= 1U;
++ result++;
++ }
++
++ return result;
++}
++#ifdef DEBUG
++static void dump_chan(channelControlBlock *ccb, int chan)
++{
++ dma_addr_t bd_phys = ccb[chan].baseBDptr;
++ int i;
++
++ if (bd_phys == DMA_ADDR_INVALID)
++ return;
++
++ while (1) {
++ bufferDescriptor *bd = iapi_Phys2Virt(bd_phys);
++
++ DBG(1, "BD[%2d]@%08x count=%d CONT=%d DONE=%d WRAP=%d LAST=%d INTR=%d ERR=%d EXTD=%d\n",
++ i, iapi_Virt2Phys(bd), bd->mode.count,
++ !!(bd->mode.status & BD_CONT),
++ !!(bd->mode.status & BD_DONE),
++ !!(bd->mode.status & BD_WRAP),
++ !!(bd->mode.status & BD_LAST),
++ !!(bd->mode.status & BD_INTR),
++ !!(bd->mode.status & BD_RROR),
++ !!(bd->mode.status & BD_EXTD));
++ if (bd->mode.status & (BD_LAST | BD_WRAP)) {
++ break;
++ }
++ bd_phys += ((bd->mode.status & BD_EXTD) ?
++ SDMA_EXTENDED_BD_SIZE : SDMA_BD_SIZE);
++ i++;
++ }
++}
++
++static void dump_dma(void)
++{
++ dma_addr_t reg;
++
++ reg = __raw_readl(SDMA_H_C0PTR);
++ if (reg != DMA_ADDR_INVALID) {
++ channelControlBlock *ccb = iapi_Phys2Virt(reg);
++ int chan;
++
++ for (chan = 0; chan < CH_NUM; chan++) {
++ dump_chan(ccb, chan);
++ }
++ }
++}
++#endif // DEBUG
++
++IRQ_KEYWORD
++void
++IRQ_Handler(void)
++{
++ unsigned int intrReg;/* interrupt register mask for clearing the interrupt bit */
++ unsigned char chNum; /* SDMA channel number generating the IRQ */
++
++ /* Disable interrupts */
++ iapi_DisableInterrupts();
++ /*
++ * Clear interrupt in SDMA DI register => ACK to the SDMA the IT request.
++ * Get each interrupt number, clear them one after the other.
++ */
++ if (__raw_readl(SDMA_DI) != 0) {
++ chNum = CH_NUM - 1 - quartz_FF1(__raw_readl(SDMA_DI));
++ intrReg = 1 << chNum;
++ } else {
++ chNum = 32;
++ intrReg = 0;
++ }
++ DBG(0, "%s: SDMA_DI=%08x\n", __FUNCTION__, __raw_readl(SDMA_DI));
++#ifdef DEBUG
++ dump_dma();
++#endif
++ while (intrReg != 0) {
++ DBG(0, "%s: ACK %08x\n", __FUNCTION__, intrReg);
++ __raw_writel(intrReg, SDMA_DI);
++ iapi_SDMAIntr |= intrReg;
++ iapi_WakeUp(chNum);
++ if (callbackIsrTable[chNum] != NULL) {
++ /* release channel before callback, so IoCtl's are available */
++ iapi_ReleaseChannel(chNum);
++ callbackIsrTable[chNum](iapi_CCBHead[chNum].channelDescriptor,
++ userArgTable[chNum]);
++ }
++
++ chNum = CH_NUM - 1 - quartz_FF1(__raw_readl(SDMA_DI));
++ intrReg = 1 << chNum;
++ }
++
++ /* Enable interrupts */
++ iapi_EnableInterrupts();
++ DBG(0, "%s: Done\n", __FUNCTION__);
++}
++
++/* ***************************************************************************/
++/**
++ *@brief Perform a memory copy operation, in the memory of the same processor
++ *
++ * Size bytes are copied from the src address to dest address. It is used
++ * the channel pointed by cd_p, which must be configured prior to this call:
++ * opened, associated with the script to perform the operation - DSP_2_DSP,
++ * or MCU_2_MCU - and have the synchronization option set.
++ *
++ *
++ *
++ * @param
++ * - cd_p: channel configured to perform DSP_2_DSP or MCU_2_MCU transfers
++ * - dest: destination memory address
++ * - src : source memory address
++ * - size: number of bytes to copy from src to dest
++ *
++ * @return
++ * - the offset of the most significant bit set from the MSB
++ */
++
++int iapi_MemCopy(channelDescriptor *cd_p, void *dest, void *src, unsigned long size)
++{
++ int result = IAPI_SUCCESS;
++ bufferDescriptor *bd_p;
++
++ /* Channel descriptor validity */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* Check and set correct parameter */
++ if (cd_p->trust != TRUE) {
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_TRUST, TRUE);
++ }
++
++ if (cd_p->bufferDescNumber != 1) {
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERDESCNUMBER, 1);
++ if (result != IAPI_SUCCESS) {
++ return result;
++ }
++ }
++
++ if (cd_p->bufferSize != size) {
++ result = iapi_ChangeChannelDesc(cd_p, IAPI_BUFFERSIZE, size);
++ if (result != IAPI_SUCCESS) {
++ return result;
++ }
++ }
++ /* Set addresses */
++ bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ bd_p->bufferAddr = iapi_Virt2Phys(src);
++ bd_p->extBufferAddr = iapi_Virt2Phys(dest);
++
++ /* Set mode */
++ bd_p->mode.count = size;
++ bd_p->mode.command = 0x00;
++ bd_p->mode.status = BD_INTR | BD_EXTD | BD_DONE | BD_WRAP;
++
++ /* Decide if we sleep or not */
++ if (cd_p->callbackSynch == DEFAULT_POLL) {
++ iapi_StartChannel(cd_p->channelNumber);
++ /* Call synchronization routine */
++ iapi_SynchChannel(cd_p->channelNumber);
++ } else {
++ /* Just start the channel */
++ iapi_StartChannel(cd_p->channelNumber);
++ }
++
++ return result;
++}
++
++/* ***************************************************************************/
++/**Return the channel number from the channel descriptor
++ *
++ * @param cd_p pointer to channel descriptor to obtain the channel number
++ *
++ * @return
++ * - the channel number
++ *
++ */
++int iapi_GetChannelNumber(channelDescriptor *cd_p)
++{
++ return cd_p->channelNumber;
++}
++
++/* ***************************************************************************/
++/**Return the error bit from the current BD of the channel
++ *
++ *
++ * @param cd_p pointer to channel descriptor
++ *
++ * @return
++ * - 0 if no error detected
++ * - BD_RROR | DATA_ERROR if error detected
++ *
++ */
++unsigned long iapi_GetError(channelDescriptor *cd_p)
++{
++ bufferDescriptor *bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->currentBDptr);
++
++ if (bd_p == NULL)
++ return -EINVAL;
++
++ return (bd_p->mode.status & BD_RROR) |
++ cd_p->ccb_ptr->status.data_error;
++}
++
++/* ***************************************************************************/
++/**Return the count from the current BD of the channel
++ *
++ *
++ * @param cd_p pointer to channel descriptor
++ *
++ * @return
++ * - count field of the current BD for the channel
++ *
++ */
++int iapi_GetCount(channelDescriptor *cd_p)
++{
++ bufferDescriptor *bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->currentBDptr);
++
++ if (bd_p == NULL)
++ return -EINVAL;
++
++ return bd_p->mode.count;
++}
++
++/* ***************************************************************************/
++/**Return the sum of counts for all the BD's owned by the processor for
++ * the channel specified by the received parameter.
++ *
++ *
++ * @param cd_p pointer to channel descriptor
++ *
++ * @return
++ * - sum of count fields
++ *
++ */
++int iapi_GetCountAll(channelDescriptor *cd_p)
++{
++ int retval = 0;
++ int i;
++ bufferDescriptor *bd_p;
++
++ bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ for (i = 0; i < cd_p->bufferDescNumber &&
++ !(bd_p->mode.status & BD_DONE); i++, bd_p++) {
++ retval += bd_p->mode.count;
++ }
++ return retval;
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLow.c 2010-12-03 09:51:55.404347330 +0100
+@@ -0,0 +1,153 @@
++/******************************************************************************
++ *
++ * Copyright 2007-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiLow.c
++ *
++ * $Id iapiLow.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the LOW level functions of the I.API.
++ *
++ *
++ * /
++ *
++ * $Log iapiLow.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <linux/kernel.h>
++
++#include <epm.h>
++#include <iapiLow.h>
++
++/**
++ * Function Section
++ */
++
++
++/* ***************************************************************************/
++/**Records an ISR callback function pointer into the ISR callback
++ * function table
++ *
++ * @param cd_p channel descriptor to attach callback to
++ * @param func_p pointer to the callback function to be registered
++ *
++ * @return none
++ */
++void
++iapi_AttachCallbackISR(channelDescriptor *cd_p, CallbackISR func_p)
++{
++ if (cd_p->callbackSynch == CALLBACK_ISR) {
++ iapi_DisableInterrupts();
++ callbackIsrTable[cd_p->channelNumber] = func_p;
++ iapi_EnableInterrupts();
++ } else if (cd_p->callbackSynch == DEFAULT_POLL) {
++ callbackIsrTable[cd_p->channelNumber] = NULL;
++ } else {
++ iapi_errno = IAPI_ERR_CALLBACKSYNCH_UNKNOWN |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ WARN_ON(1);
++ }
++}
++
++
++/* ***************************************************************************/
++/**Detaches (removes) an ISR callback function pointer from the ISR callback
++ * function table
++ *
++ * <b>Algorithm:</b>\n
++ * - Attach a null function to replace the original one.
++ *
++ * @param cd_p channel descriptor to detach callback from
++ *
++ * @return none
++ */
++void
++iapi_DetachCallbackISR(channelDescriptor *cd_p)
++{
++ iapi_AttachCallbackISR(cd_p, NULL);
++}
++
++/* ***************************************************************************/
++/**Updates an ISR callback function pointer into the ISR callback function
++ * table
++ *
++ * <b>Algorithm:</b>\n
++ * - Detach the old function pointer (if any) and attach the new one
++ *
++ * @param cd_p channel descriptor to attach callback to
++ * @param func_p pointer to the callback function to be registered
++ *
++ * @return none
++ */
++void
++iapi_ChangeCallbackISR(channelDescriptor *cd_p, CallbackISR func_p)
++{
++ iapi_DetachCallbackISR(cd_p);
++ iapi_AttachCallbackISR(cd_p, func_p);
++}
++
++/* ***************************************************************************/
++/**Loop while the channel is not done on the SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - Loop doing nothing but checking the I.API global variable to indicate
++ * that the channel has been completed (interrupt from SDMA)
++ *
++ * <b>Notes:</b>\n
++ * - The ISR must update the I.API global variable iapi_SDMAIntr.
++ *
++ * @param channel channel number to poll on
++ *
++ * @return none
++ */
++void
++iapi_lowSynchChannel(unsigned char channel)
++{
++ //while (!((1UL << channel) & iapi_SDMAIntr));
++ GOTO_SLEEP(channel);
++ DBG(0, "%s: Done: %08lx->%08lx\n", __FUNCTION__, iapi_SDMAIntr,
++ iapi_SDMAIntr & ~(1 << channel));
++ iapi_SDMAIntr &= ~(1 << channel);
++}
++
++/* ***************************************************************************/
++/**Fill the buffer descriptor with the values given in parameter.
++ *
++ * @return none
++ */
++void
++iapi_SetBufferDescriptor(bufferDescriptor *bd_p, unsigned char command,
++ unsigned char status, unsigned short count,
++ void *buffAddr, dma_addr_t extBufferAddr)
++{
++ bd_p->mode.command = command;
++ bd_p->mode.status = status;
++ bd_p->mode.count = count;
++ if (buffAddr != NULL) {
++ bd_p->bufferAddr = iapi_Virt2Phys(buffAddr);
++ } else {
++ bd_p->bufferAddr = DMA_ADDR_INVALID;
++ }
++ bd_p->extBufferAddr = extBufferAddr;
++}
++
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLowDsp.c 2010-12-03 09:51:55.404347330 +0100
+@@ -0,0 +1,79 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiLowDsp.c
++ *
++ * $Id iapiLowDsp.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the LOW level functions of the I.API specific to MCU.
++ *
++ *
++ *
++ *
++ * $Log iapiLowDsp.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include "epm.h"
++#include "iapiLow.h"
++
++/* ****************************************************************************
++ * Function Section
++ *****************************************************************************/
++#ifdef DSP
++
++/* ***************************************************************************/
++/**Starts the channel (core specific register)
++ *
++ * <b>Algorithm:</b>\n
++ * - Bit numbered "channel" of DspEnStartReg register is set
++ *
++ * @param channel channel to start
++ *
++ * @return none
++ */
++void
++iapi_lowStartChannel (unsigned char channel)
++{
++ SDMA_D_START |= (1 << channel);
++}
++
++/* ***************************************************************************/
++/**Stops the channel (core specific register)
++ *
++ * <b>Algorithm:</b>
++ * - Bit numbered "channel" of DspEnStopReg register is cleared
++ *
++ * <b>Notes:</b>\n
++ * - This is a write one to clear register
++ *
++ * @param channel channel to stop
++ *
++ * @return none
++ */
++void
++iapi_lowStopChannel (unsigned char channel)
++{
++ SDMA_D_STATSTOP &= (1 << channel);
++}
++
++#endif /* DSP */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiLowMcu.c 2010-12-03 09:51:55.408346904 +0100
+@@ -0,0 +1,545 @@
++/******************************************************************************
++ *
++ * Copyright 2007-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiLowMcu.c
++ *
++ * $Id iapiLowMcu.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the LOW level functions of the I.API specific to MCU.
++ *
++ *
++ * http://compass/mot.com/go/115342679
++ *
++ * $Log iapiLowMcu.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <string.h>
++#include <linux/io.h>
++
++#include <epm.h>
++#include <iapiLow.h>
++
++/* ****************************************************************************
++ * Function Section
++ *****************************************************************************/
++#ifdef MCU
++
++/* ***************************************************************************/
++/**Send a command on SDMA's channel zero.
++ * Check if buffer descriptor is already used by the sdma, if yes return
++ * an error as c0BDNum is wrong.
++ *
++ * <b>Notes</b>\n
++ * There is an upgrade in the script on the Context load command and
++ * the fact that the context structure has a fixed length of 20 or 24
++ * depending on SDMA versions.
++ *
++ * @return
++ * - IAPI_SUCCESS
++ * - -iapi_errno if failure
++ */
++int
++iapi_Channel0Command(channelDescriptor *cd_p, void *buf,
++ unsigned short nbyte, unsigned char command)
++{
++ channelControlBlock *ccb_p;
++ bufferDescriptor *bd_p;
++ int result = IAPI_SUCCESS;
++ unsigned char chNum;
++
++ /*
++ * Check data structures are properly initialized
++ */
++ /* Channel descriptor validity */
++ if (cd_p == NULL) {
++ result = IAPI_ERR_CD_UNINITIALIZED;
++ iapi_errno = result;
++ return -result;
++ }
++
++ /* Channel control block validity */
++ if (cd_p->ccb_ptr == NULL) {
++ result = IAPI_ERR_CCB_UNINITIALIZED;
++ iapi_errno = result;
++ return -result;
++ }
++
++ /* Control block & Descriptpor associated with the channel being worked on */
++ chNum = cd_p->channelNumber;
++ ccb_p = cd_p->ccb_ptr;
++
++ /* Is channel already in use ? */
++ if (ccb_p->baseBDptr != DMA_ADDR_INVALID) {
++ result = IAPI_ERR_BD_ALLOCATED | IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_errno = result;
++ return -result;
++ }
++
++ /* Allocation of buffer descriptors */
++ bd_p = MALLOC(sizeof(bufferDescriptor));
++ if (bd_p != NULL) {
++ ccb_p->baseBDptr = iapi_Virt2Phys(bd_p);
++ } else {
++ result = IAPI_ERR_BD_ALLOCATION | IAPI_ERR_CH_AVAILABLE | chNum;
++ iapi_errno = result;
++ return -result;
++ }
++
++ /* Buffer descriptor setting */
++ iapi_SetBufferDescriptor(bd_p, command, BD_WRAP | BD_DONE | BD_INTR,
++ nbyte, buf, DMA_ADDR_INVALID);
++
++ /* Actually the transfer */
++ iapi_lowStartChannel(cd_p->channelNumber);
++ iapi_lowSynchChannel(cd_p->channelNumber);
++
++ /* Cleaning of allocation */
++ FREE(bd_p);
++ ccb_p->baseBDptr = DMA_ADDR_INVALID;
++
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**Changes the interrupt Mask (core specific register)
++ *
++ * Algorithm:
++ * - Program value as per the passed in arguments to the core-specific Interrupt Mask Reg.
++ *
++ * @param
++ * Value to be AND-ed or Or-ed with the interrupt Mask reg
++ * @op
++ * Operation(AND or OR) to be performed on the Interrupt Mask Reg.
++ * @return
++ * - IAPI_SUCCESS
++ * - iapi_errno if failure
++ */
++int
++iapi_lowChangeIntrMask(unsigned int param, unsigned char op)
++{
++ switch (op) {
++ case OR_OP:
++ __raw_writel(__raw_readl(SDMA_H_INTRMSK) | param, SDMA_H_INTRMSK);
++ break;
++ case AND_OP:
++ __raw_writel(__raw_readl(SDMA_H_INTRMSK) & ~param, SDMA_H_INTRMSK);
++ break;
++ default:
++ iapi_errno = IAPI_ERR_NOT_ALLOWED;
++ return iapi_errno;
++ }
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**Starts the channel (core specific register)
++ *
++ * <b>Algorithm:</b>\n
++ * - Bit numbered "channel" of HostEnStartReg register is set
++ *
++ * @param channel channel to start
++ *
++ * @return none
++ */
++void
++iapi_lowStartChannel(unsigned char channel)
++{
++ DBG(0, "%s: %p: %08x->%08x\n", __FUNCTION__, SDMA_H_START,
++ __raw_readl(SDMA_H_START), __raw_readl(SDMA_H_START) | (1 << channel));
++ __raw_writel(__raw_readl(SDMA_H_START) | (1 << channel), SDMA_H_START);
++}
++
++/* ***************************************************************************/
++/**Stops the channel (core specific register)
++ *
++ * <b>Algorithm:</b>
++ * - Bit numbered "channel" of HostEnStopReg register is cleared
++ *
++ * <b>Notes:</b>\n
++ * - This is a write one to clear register
++ *
++ * @param channel channel to stop
++ *
++ * @return none
++ */
++void
++iapi_lowStopChannel(unsigned char channel)
++{
++ DBG(0, "%s: %p: %08x->%08x\n", __FUNCTION__, SDMA_H_STATSTOP,
++ __raw_readl(SDMA_H_STATSTOP), __raw_readl(SDMA_H_STATSTOP) & ~(1 << channel));
++ __raw_writel(1 << channel, SDMA_H_STATSTOP);
++}
++
++/* ***************************************************************************/
++/**Initialize the initial priority of registers and channel enable
++ * RAM from the MCU side. No channels are enabled, all priorities are set to 0.
++ *
++ * @return none
++ */
++void
++iapi_InitChannelTables(void)
++{
++ int i;
++
++ /* No channel is enabled */
++ for (i = 0; i < EVENTS_NUM; i++) {
++ __raw_writel(0, SDMA_CHNENBL_0 + (i << 2));
++ }
++ //iapi_memset((void *)&SDMA_CHNENBL_0, 0x00, sizeof(unsigned long) * EVENTS_NUM);
++
++ /* All channels have priority 0 */
++ for (i = 0; i < EVENTS_NUM; i++) {
++ __raw_writel(0, SDMA_CHNPRI_0 + (i << 2));
++ }
++ //iapi_memset((void *)&SDMA_CHNPRI_0, 0x00, sizeof(unsigned long) * CH_NUM);
++}
++
++/* ***************************************************************************/
++/** The host enable (HE), hosts override (HO), dsp enable (DE), dsp override
++ * (DO) registers are involved here.
++ * Host and Dsp enable registers are here to signify that the MCU or DSP side
++ * have prepared the appropriate buffers and are now ready. If the channel is
++ * owned by the MCU the override bit for that channel needs to be cleared :
++ * the host allows the channel to be used.\n
++ *
++ * Then the override bits can define (mcuOverride dspOverride):\n
++ * - 0 0 channel is public: transfer to/from MCU to DSP
++ * - 0 1 channel if owned by DSP
++ * - 1 0 channel if owned by MCU
++ * - 1 1 channel zero config
++ *
++ * See also :\n
++ * IAPI Table 1.1 "Channel configuration properties"
++ *
++ * @param channel channel to configure
++ * @param eventOverride event ownership
++ * @param mcuOverride ARM ownership
++ * @param dspOverride DSP ownership
++ *
++ * @return
++ * - -iapi_errno if the 3 override parameters are all set
++ * - IAPI_SUCCESS in other cases (valid cases)
++ */
++int
++iapi_ChannelConfig(unsigned char channel, unsigned eventOverride,
++ unsigned mcuOverride, unsigned dspOverride)
++{
++ int result = IAPI_SUCCESS;
++
++ if (eventOverride &&
++ mcuOverride &&
++ dspOverride) {
++ result = IAPI_ERR_CONFIG_OVERRIDE;
++ iapi_errno = result;
++ return -result;
++ } else {
++ /*
++ * DSP side
++ */
++ if (dspOverride) {
++ __raw_writel(__raw_readl(SDMA_H_DSPOVR) &
++ ~(1 << channel), SDMA_H_DSPOVR);
++ } else {
++ __raw_writel(__raw_readl(SDMA_H_DSPOVR) |
++ (1 << channel), SDMA_H_DSPOVR);
++ }
++ /*
++ * Event
++ */
++ if (eventOverride) {
++ __raw_writel(__raw_readl(SDMA_H_EVTOVR) &
++ ~(1 << channel), SDMA_H_EVTOVR);
++ } else {
++ __raw_writel(__raw_readl(SDMA_H_EVTOVR) |
++ (1 << channel), SDMA_H_EVTOVR);
++ }
++ /*
++ * MCU side
++ */
++ if (mcuOverride) {
++ __raw_writel(__raw_readl(SDMA_H_HOSTOVR) &
++ ~(1 << channel), SDMA_H_HOSTOVR);
++ } else {
++ __raw_writel(__raw_readl(SDMA_H_HOSTOVR) |
++ (1 << channel), SDMA_H_HOSTOVR);
++ }
++ }
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**Load the context data of a channel from SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - Setup BD with appropiate parameters
++ * - Start channel
++ * - Poll for answer
++ *
++ * @param *cd_p channel descriptor for channel 0
++ * @param *buf pointer to receive context data
++ * @param channel channel for which the context data is requested
++ *
++ * @return none
++ */
++void
++iapi_lowGetContext(channelDescriptor *cd_p, void *buf, unsigned char channel)
++{
++ bufferDescriptor *bd_p;
++
++ bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ /* Setup buffer descriptor with channel 0 command */
++ iapi_SetBufferDescriptor(&bd_p[0],
++ C0_GETDM,
++ BD_DONE | BD_INTR | BD_WRAP | BD_EXTD,
++ sizeof(contextData) / 4,
++ buf,
++ CHANNEL_CONTEXT_BASE_ADDRESS + sizeof(contextData) * channel / 4);
++ /* Receive, polling method */
++ iapi_lowStartChannel(cd_p->channelNumber);
++ iapi_lowSynchChannel(cd_p->channelNumber);
++}
++
++/* ***************************************************************************/
++/**Read "size" byte /2 at SDMA address (address) and write them in buf
++ *
++ * <b>Algorithm:</b>\n
++ * - Setup BD with appropiate parameters (C0_GETPM)
++ * - Start channel
++ * - Poll for answer
++ *
++ * <b>Notes</b>\n
++ * - Parameter "size" is in bytes, it represents the size of "buf", e.g.
++ * the size in bytes of the script to be loaded.
++ * - Parameter "address" denotes the RAM address for the script in SDMA
++ *
++ * @param *cd_p channel descriptor for channel 0
++ * @param *buf pointer to receive the data
++ * @param size number of bytes to read
++ * @param address address in SDMA RAM to start reading from
++ *
++ * @return none
++ */
++void
++iapi_lowGetScript(channelDescriptor *cd_p, void *buf, unsigned short size,
++ dma_addr_t address)
++{
++ bufferDescriptor *bd_p;
++
++ bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ /* Setup buffer descriptor with channel 0 command */
++ iapi_SetBufferDescriptor(&bd_p[0],
++ C0_GETPM,
++ BD_DONE | BD_INTR | BD_WRAP | BD_EXTD,
++ size / 2, /* count in shorts */
++ buf,
++ address);
++ /* Receive, polling method*/
++ iapi_lowStartChannel(cd_p->channelNumber);
++ iapi_lowSynchChannel(cd_p->channelNumber);
++}
++
++/* ***************************************************************************/
++/**Load a SDMA script to SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - Setup BD with appropiate parameters (C0_SETPM)
++ * - Start channel
++ * - Poll for answer
++ *
++ * <b>Notes</b>\b
++ * - Parameter "size" is in bytes, it represents the size of "buf", e.g.
++ * the size in bytes of the script to be uploaded.
++ * - Parameter "address" denotes the RAM address for the script in SDMA
++ *
++ * @param *cd_p channel descriptor for channel 0
++ * @param *buf pointer to the script
++ * @param size size of the script, in bytes
++ * @param address address in SDMA RAM to place the script
++ *
++ * @return none
++ */
++void
++iapi_lowSetScript(channelDescriptor *cd_p, void *buf, unsigned short size,
++ dma_addr_t address)
++{
++ bufferDescriptor *bd_p;
++
++ bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ /* Setup buffer descriptor with channel 0 command */
++ iapi_SetBufferDescriptor(&bd_p[0],
++ C0_SETPM,
++ BD_DONE | BD_INTR | BD_WRAP | BD_EXTD,
++ size / 2, /* count in shorts */
++ buf,
++ address);
++ /* Receive, polling method*/
++ iapi_lowStartChannel(cd_p->channelNumber);
++ iapi_lowSynchChannel(cd_p->channelNumber);
++}
++
++/* ***************************************************************************/
++/**Load the context for a channel to SDMA
++ *
++ * <b>Algorithm:</b>\n
++ * - Send context and poll for answer.
++ *
++ * @param *cd_p channel descriptor for channel 0
++ * @param *buf pointer to context data
++ * @param channel channel to place the context for
++ *
++ * @return none
++ */
++void
++iapi_lowSetContext(channelDescriptor *cd_p, void *buf, unsigned char channel)
++{
++
++ bufferDescriptor *local_bd_p;
++#ifdef SDMA_V2
++ local_bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ iapi_SetBufferDescriptor(&local_bd_p[0],
++ (channel << 3) | C0_SETCTX,
++ BD_DONE | BD_INTR | BD_WRAP,
++ sizeof(contextData) / 4,
++ buf,
++ DMA_ADDR_INVALID);
++#else
++
++ local_bd_p = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++
++ iapi_SetBufferDescriptor(&local_bd_p[0],
++ C0_SETDM,
++ BD_DONE | BD_INTR | BD_WRAP | BD_EXTD,
++ sizeof(contextData) / 4,
++ buf,
++ (2048 + (sizeof(contextData) / 4) * channel));
++#endif
++ /* Send */
++ iapi_lowStartChannel(cd_p->channelNumber);
++ iapi_lowSynchChannel(cd_p->channelNumber);
++}
++
++/* ***************************************************************************/
++/**Associate specified channel with the script starting at the
++ * specified address. Channel 0 command is used to load the set-up context
++ * for the channel. The address used must be generated by the GUI tool
++ * used to create RAM images for SDMA.
++ *
++ * <b>Algorithm:</b>\n
++ * - Set-up and load the context.
++ *
++ * @param *cd_p pointer to the channel descriptor of the channel
++ * @param *data_p: pointer to the data identifying the script to be associated
++ * with the channel
++ *
++ * @return
++ * - IAPI_SUCCESS : OK
++ * - -iapi_errno : operation failed, return negated value of iapi_errno
++ */
++
++int
++iapi_lowAssignScript(channelDescriptor *cd_p, script_data *data_p)
++{
++ contextData *chContext; /* context to be loaded for the channel */
++ channelDescriptor *cd0_p; /* pointer to channel descriptor of channel 0 */
++ int result = IAPI_SUCCESS;
++
++ /* Verify passed data */
++ if (cd_p == NULL || data_p == NULL) {
++ result = IAPI_ERR_INVALID_PARAMETER;
++ iapi_errno = result;
++ return -result;
++ }
++
++ /* Allocate context and initialize PC to required script start adress*/
++ chContext = MALLOC(sizeof(contextData));
++ if (chContext == NULL) {
++ result = IAPI_ERR_B_ALLOC_FAILED | cd_p->channelNumber;
++ iapi_errno = result;
++ return -result;
++ }
++
++ iapi_memset(chContext, 0x00, sizeof(contextData));
++ chContext->channelState.pc = data_p->load_address;
++
++ /* Send by context the event mask,base address for peripheral
++ * and watermark level
++ */
++ chContext->gReg[0] = data_p->event_mask2;
++ chContext->gReg[1] = data_p->event_mask1;
++ chContext->gReg[6] = data_p->shp_addr;
++ chContext->gReg[7] = data_p->wml;
++
++ /* Set transmited data to the CD */
++ cd_p->watermarkLevel = data_p->wml;
++ cd_p->eventMask1 = data_p->event_mask1;
++ cd_p->eventMask2 = data_p->event_mask2;
++
++ /* Get the cd0_p */
++ cd0_p = (cd_p->ccb_ptr - cd_p->channelNumber)->channelDescriptor;
++
++ /*load the context*/
++ iapi_lowSetContext(cd0_p, chContext, cd_p->channelNumber);
++
++ /* release allocated memory */
++ FREE(chContext);
++
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/** Set the channels to be triggered by an event. The for every channel that
++ *must be triggered by the event, the corresponding bit from channel_map
++ *parameter must be set to 1. (e.g. for the event to trigger channels 31 and
++ *0 one must pass 0x80000001)
++ *
++ *
++ * <b>Algorithm:</b>\n
++ * - Update the register from Channel Enable RAM with the channel_map
++ *
++ * @param event event for which to set the channel association
++ * @param channel_map channels to be triggered by event. Put the corresponding
++ * bit from this 32-bit value to 1 for every channel that should be
++ * triggered by the event.
++ *
++ * @return
++ * - IAPI_SUCCESS : OK
++ * - -iapi_errno : operation failed, return negated value of iapi_errno
++ */
++int
++iapi_lowSetChannelEventMapping(unsigned char event, unsigned long channel_map)
++{
++ /* Check validity of event*/
++ if (event < EVENTS_NUM) {
++ __raw_writel(channel_map, SDMA_CHNENBL(event));
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | event;
++ return -iapi_errno;
++ }
++ return IAPI_SUCCESS;
++}
++
++#endif /* MCU */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddle.c 2010-12-03 09:51:55.408346904 +0100
+@@ -0,0 +1,577 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiMiddle.c
++ *
++ * $Id iapiMiddle.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the MIDDLE level functions of the I.API.
++ *
++ *
++ *
++ *
++ * $Log iapiMiddle.c $
++ *
++ *****************************************************************************/
++
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <string.h>
++#include <linux/io.h>
++
++#include <epm.h>
++#include <iapiLow.h>
++#include <iapiMiddle.h>
++
++/* ****************************************************************************
++ * Global Variable Section
++ *****************************************************************************/
++
++
++/* ****************************************************************************
++ * Function Section
++ *****************************************************************************/
++
++/* ***************************************************************************/
++/**Allocates one Buffer Descriptor structure using information present in the
++ * channel descriptor.
++ *
++ * @param *ccb_p channel control block used to get the channel descriptor
++ *
++ * @return
++ * - pointer on the new Buffer Descriptor
++ * - NULL if allocation failed
++ *
++ */
++bufferDescriptor *
++iapi_AllocBD(channelControlBlock *ccb_p)
++{
++ bufferDescriptor *ptrBD = NULL;
++ int num_desc = ccb_p->channelDescriptor->bufferDescNumber;
++
++ if (num_desc == 0)
++ return NULL;
++
++ ptrBD = MALLOC(num_desc * sizeof(bufferDescriptor));
++ if (ptrBD == NULL) {
++ DBG(0, "%s: Failed to allocate %u byte for %u BDs\n",
++ __FUNCTION__,
++ num_desc * sizeof(bufferDescriptor),
++ num_desc);
++ return NULL;
++ }
++ ptrBD->mode.command = 0;
++ ptrBD->mode.status = 0;
++ ptrBD->mode.count = 0;
++ ptrBD->bufferAddr = DMA_ADDR_INVALID;
++
++ return ptrBD;
++}
++
++/* ***************************************************************************/
++/**Allocate one channel context data structure.
++ *
++ * @param **ctxd_p pointer to context data to be allocated
++ * @param channel channel number of context data structure
++ *
++ * @return
++ * - IAPI_SUCCESS
++ * - -iapi_errno if allocation failed
++ */
++int
++iapi_AllocContext(contextData **ctxd_p, unsigned char channel)
++{
++ if (*ctxd_p != NULL) {
++ iapi_errno = IAPI_ERR_CC_ALREADY_DEFINED |
++ IAPI_ERR_CH_AVAILABLE | channel;
++ return -iapi_errno;
++ }
++
++ *ctxd_p = MALLOC(sizeof(contextData));
++ if (*ctxd_p == NULL) {
++ iapi_errno = IAPI_ERR_CC_ALLOC_FAILED |
++ IAPI_ERR_CH_AVAILABLE | channel;
++ return -iapi_errno;
++ }
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**Allocates channel description and fill in with default values.
++ *
++ * <b>Algorithm:</b>\n
++ * - Check channel properties.
++ * - Then modifies the properties of the channel description with default
++ *
++ * @param **cd_p pointer to channel descriptor to be allocated
++ * @param channel channel number of channel descriptor
++ *
++ * @return
++ * - IAPI_SUCCESS
++ * - -iapi_errno if allocation failed
++ *
++ */
++int
++iapi_AllocChannelDesc(channelDescriptor **cd_p, unsigned char channel)
++{
++ unsigned int pri;
++
++ if (*cd_p != NULL) {
++ iapi_errno = IAPI_ERR_CD_ALREADY_DEFINED |
++ IAPI_ERR_CH_AVAILABLE | channel;
++ return -iapi_errno;
++ }
++
++ *cd_p = MALLOC(sizeof(channelDescriptor));
++ if (*cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_ALLOC_FAILED |
++ IAPI_ERR_CH_AVAILABLE | channel;
++ return -iapi_errno;
++ }
++
++ iapi_memcpy(*cd_p, &iapi_ChannelDefaults, sizeof(channelDescriptor));
++ (*cd_p)->channelNumber = channel;
++#ifdef MCU
++ pri = __raw_readl(SDMA_CHNPRI(channel));
++ if (pri != 0) {
++ (*cd_p)->priority = pri;
++ } else {
++ __raw_writel((*cd_p)->priority, SDMA_CHNPRI(channel));
++ }
++#endif
++ return IAPI_SUCCESS;
++}
++
++/* ***************************************************************************/
++/**Changes channel description information after performing sanity checks.
++ *
++ * <b>Algorithm:</b>\n
++ * - Check channel properties.
++ * - Then modifies the properties of the channel description.
++ *
++ * @param *cd_p channel descriptor of the channel to change
++ * @param whatToChange control code indicating the desired change
++ * @param newval new value
++ *
++ * @return
++ * - IAPI_SUCCESS
++ * - IAPI_FAILURE if change failed
++ *
++ */
++int
++iapi_ChangeChannelDesc(channelDescriptor *cd_p, unsigned char whatToChange,
++ unsigned long newval)
++{
++ bufferDescriptor *tmpBDptr;
++ unsigned int index;
++
++ DBG(0, "%s: channel %d what=%08x newval=%08lx\n", __FUNCTION__,
++ cd_p->channelNumber, whatToChange, newval);
++ /* verify parameter validity */
++ if (cd_p == NULL) {
++ iapi_errno = IAPI_ERR_CD_UNINITIALIZED;
++ return -iapi_errno;
++ }
++
++ /* verify channel descriptor initialization */
++ if (cd_p->ccb_ptr == NULL) {
++ iapi_errno = IAPI_ERR_CCB_UNINITIALIZED | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++
++ /* verify channel is not in use */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ tmpBDptr = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ for (index = cd_p->bufferDescNumber; index > 0; index--) {
++ if (tmpBDptr->mode.status & BD_DONE) {
++ iapi_errno = IAPI_ERR_CH_IN_USE | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ tmpBDptr++;
++ }
++ }
++
++ /* Select the change accorded to the selector given in parameter */
++ switch (whatToChange) {
++ case IAPI_CHANNELNUMBER:
++ /*
++ * Channel Number
++ */
++ /* Channel number can not be changed (description remains attached) */
++ iapi_errno = IAPI_ERR_CD_CHANGE_CH_NUMBER |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++
++ case IAPI_BUFFERDESCNUMBER:
++ /*
++ * Buffer Descriptor Number
++ */
++ if (newval >= MAX_BD_NUM) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ if (newval == cd_p->bufferDescNumber) {
++ break;
++ }
++ /* Free memory used for previous data */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ tmpBDptr = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if (tmpBDptr->bufferAddr != DMA_ADDR_INVALID) {
++ if (cd_p->trust == FALSE) {
++ FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr));
++ }
++ }
++ tmpBDptr++;
++ }
++ FREE(iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr));
++ cd_p->ccb_ptr->baseBDptr = DMA_ADDR_INVALID;
++ cd_p->ccb_ptr->currentBDptr = DMA_ADDR_INVALID;
++ }
++ /* Allocate and initialize structures */
++ cd_p->bufferDescNumber = newval;
++ cd_p->ccb_ptr->status.openedInit = FALSE;
++ if (IAPI_SUCCESS != iapi_InitializeMemory(cd_p->ccb_ptr)) {
++ iapi_errno = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ cd_p->ccb_ptr->status.openedInit = TRUE;
++ break;
++
++ case IAPI_BUFFERSIZE:
++ /*
++ * Buffer size
++ */
++ if (newval < MAX_BD_SIZE) {
++ if (newval != cd_p->bufferSize) {
++ /* Free memory used for previous old data */
++ if (cd_p->ccb_ptr->baseBDptr != DMA_ADDR_INVALID) {
++ tmpBDptr = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber; index++) {
++ if (cd_p->trust == FALSE) {
++ FREE(iapi_Phys2Virt(tmpBDptr->bufferAddr));
++ }
++ tmpBDptr++;
++ }
++ FREE(iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr));
++ }
++ cd_p->ccb_ptr->baseBDptr = DMA_ADDR_INVALID;
++ cd_p->ccb_ptr->currentBDptr = DMA_ADDR_INVALID;
++ /* Allocate and initialize structures */
++ cd_p->bufferSize = newval;
++ cd_p->ccb_ptr->status.openedInit = FALSE;
++ if (IAPI_SUCCESS != iapi_InitializeMemory(cd_p->ccb_ptr)) {
++ iapi_errno = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ cd_p->ccb_ptr->status.openedInit = TRUE;
++ }
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++
++ case IAPI_BLOCKING:
++ /*
++ * Blocking / non blocking feature
++ */
++ if (newval < MAX_BLOCKING) {
++ cd_p->blocking = newval;
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++
++ case IAPI_CALLBACKSYNCH:
++ /*
++ * Synchronization method
++ */
++ if (newval < MAX_SYNCH) {
++ cd_p->callbackSynch = newval;
++ iapi_ChangeCallbackISR( cd_p, cd_p->callbackISR_ptr);
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++
++ case IAPI_OWNERSHIP:
++ /*
++ * Ownership of the channel
++ */
++#ifdef DSP
++ iapi_errno = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber;
++ return -iapi_errno;
++#endif /* DSP */
++#ifdef MCU
++ if (newval < MAX_OWNERSHIP) {
++ cd_p->ownership = newval;
++ iapi_ChannelConfig(cd_p->channelNumber,
++ (newval >> CH_OWNSHP_OFFSET_EVT) & 1,
++ (newval >> CH_OWNSHP_OFFSET_MCU) & 1,
++ (newval >> CH_OWNSHP_OFFSET_DSP) & 1);
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++#endif /* MCU */
++ case IAPI_PRIORITY:
++ /*
++ * Priority
++ */
++#ifdef DSP
++ iapi_errno = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber;
++ return -iapi_errno;
++#endif /* DSP */
++
++#ifdef MCU
++ if (newval < MAX_CH_PRIORITY) {
++#if 1
++ __raw_writel(newval, SDMA_CHNPRI(cd_p->channelNumber));
++#else
++ volatile unsigned long *ChannelPriorities = &SDMA_CHNPRI_0;
++ ChannelPriorities[cd_p->channelNumber] = newval;
++#endif
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++#endif /* MCU */
++ case IAPI_TRUST:
++ /*
++ * "Trust" property
++ */
++ if (newval < MAX_TRUST) {
++ if (cd_p->trust != newval) {
++ cd_p->trust = newval;
++ if (newval == FALSE) {
++ if (IAPI_SUCCESS !=iapi_InitializeMemory(cd_p->ccb_ptr)) {
++ iapi_errno = IAPI_ERR_BD_ALLOCATION | cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ }
++ }
++ break;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER | IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++
++ case IAPI_CALLBACKISR_PTR:
++ /*
++ * Callback function pointer
++ */
++ if ((void *)newval != NULL) {
++ cd_p->callbackISR_ptr = (void *)newval;
++ iapi_ChangeCallbackISR( cd_p, cd_p->callbackISR_ptr);
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ break;
++
++ case IAPI_CCB_PTR:
++ /*
++ * Channel Control Block pointer
++ */
++ cd_p->ccb_ptr = (channelControlBlock *)newval;
++ cd_p->ccb_ptr->channelDescriptor = cd_p;
++ break;
++
++ case IAPI_BDWRAP:
++ /*
++ * WRAP/UNWRAP
++ */
++ /* pointer to first BD */
++ tmpBDptr = iapi_Phys2Virt(cd_p->ccb_ptr->baseBDptr);
++ /* pointer to last BD */
++ tmpBDptr += cd_p->bufferDescNumber - 1;
++ DBG(0, "%s: newval=%08lx\n", __FUNCTION__, newval);
++ if (newval == TRUE) {
++ /* wrap last BD */
++ DBG(0, "%s: Setting BD_WRAP for channel %d BD[%d/%d]\n",
++ __FUNCTION__, cd_p->channelNumber,
++ cd_p->bufferDescNumber - 1,
++ cd_p->bufferDescNumber);
++ tmpBDptr->mode.status |= BD_WRAP;
++ } else if (newval == FALSE) {
++ /* unwrap last BD */
++ DBG(0, "%s: Clearing BD_WRAP for channel %d BD[%d/%d]\n",
++ __FUNCTION__, cd_p->channelNumber,
++ cd_p->bufferDescNumber - 1,
++ cd_p->bufferDescNumber);
++ tmpBDptr->mode.status &= ~BD_WRAP;
++ } else {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ break;
++
++ case IAPI_WML:
++ /*
++ * Watermark level
++ */
++#ifdef DSP
++ iapi_errno = IAPI_ERR_NOT_ALLOWED | cd_p->channelNumber;
++ return -iapi_errno;
++#endif /* DSP */
++#ifdef MCU
++ if (newval >= MAX_WML) {
++ iapi_errno = IAPI_ERR_INVALID_PARAMETER |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ if (cd_p->watermarkLevel != newval) {
++ cd_p->watermarkLevel = newval;
++ }
++ break;
++#endif /* MCU */
++ default:
++ /*
++ * Detect errors
++ */
++ iapi_errno = IAPI_ERR_CD_CHANGE_UNKNOWN |
++ IAPI_ERR_CH_AVAILABLE |
++ cd_p->channelNumber;
++ return -iapi_errno;
++ }
++ return IAPI_SUCCESS;
++}
++
++
++/* ***************************************************************************/
++/**Initialize a table of function pointers that contain the interrupt Service
++ * Routine callback pointers for the SDMA channels with a default value
++ *
++ * <b>Algorithm:</b>\n
++ * - Loop on each element of the global IAPI variable callbackIsrTable
++ *
++ * @param *func_p default callback functon for all SDMA channels
++ *
++ * @return none
++ */
++void
++iapi_InitializeCallbackISR(void(* func_p)(channelDescriptor *cd_p, void *arg))
++{
++ unsigned long chCnt;
++
++ for (chCnt = 0; chCnt < CH_NUM; chCnt++) {
++ callbackIsrTable[chCnt] = func_p;
++ }
++}
++
++/* ***************************************************************************/
++/**For the specified channel control block, attach the array of buffer
++ * descriptors, the channel description structure and initialize channel's
++ * status using information in the channel descriptor.
++ *
++ * @param *ccb_p pointer to channel control block
++ *
++ * @return none
++ *
++ */
++int
++iapi_InitializeMemory(channelControlBlock *ccb_p)
++{
++ bufferDescriptor *bd_p;
++ unsigned int index;
++ channelDescriptor *cd_p = ccb_p->channelDescriptor;
++
++ /* Attach the array of Buffer descriptors */
++ bd_p = iapi_AllocBD(ccb_p);
++ if (bd_p == NULL)
++ return -IAPI_ERR_BD_ALLOCATION;
++
++ ccb_p->baseBDptr = iapi_Virt2Phys(bd_p);
++ ccb_p->currentBDptr = ccb_p->baseBDptr;
++ DBG(0, "%s: BDptr[%p] of ccb %p set to %08x\n", __FUNCTION__,
++ &ccb_p->baseBDptr, ccb_p, ccb_p->baseBDptr);
++ for (index = 0; index < cd_p->bufferDescNumber - 1; index++) {
++ if (cd_p->trust == TRUE) {
++ iapi_SetBufferDescriptor(bd_p,
++ cd_p->dataSize,
++ BD_CONT | BD_EXTD, cd_p->bufferSize,
++ NULL, DMA_ADDR_INVALID);
++ } else {
++ if (cd_p->bufferSize != 0) {
++ void *buf = MALLOC(cd_p->bufferSize);
++
++ if (buf == NULL)
++ goto cleanup;
++
++ iapi_SetBufferDescriptor(bd_p,
++ cd_p->dataSize,
++ BD_CONT | BD_EXTD,
++ cd_p->bufferSize,
++ buf, DMA_ADDR_INVALID);
++ }
++ }
++ bd_p++;
++ }
++
++ if (cd_p->trust == TRUE) {
++ iapi_SetBufferDescriptor(bd_p,
++ cd_p->dataSize,
++ BD_EXTD | BD_WRAP | BD_INTR,
++ cd_p->bufferSize,
++ NULL, DMA_ADDR_INVALID);
++ } else {
++ if (cd_p->bufferSize != 0) {
++ void *buf = MALLOC(cd_p->bufferSize);
++
++ if (buf == NULL)
++ goto cleanup;
++
++ iapi_SetBufferDescriptor(bd_p,
++ cd_p->dataSize,
++ BD_EXTD | BD_WRAP | BD_INTR,
++ cd_p->bufferSize,
++ buf,
++ DMA_ADDR_INVALID);
++ }
++ }
++ return IAPI_SUCCESS;
++cleanup:
++ WARN_ON(1);
++ while (--index >= 0) {
++
++ }
++}
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiMiddleMcu.c 2010-12-03 09:51:55.408346904 +0100
+@@ -0,0 +1,52 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiMiddleMcu.c
++ *
++ * $Id iapiMiddleMcu.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the MIDDLE level functions of the I.API specific to MCU.
++ *
++ *
++ *
++ *
++ * $Log iapiMiddleMcu.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <epm.h>
++#include <string.h>
++
++#include <iapiLow.h>
++#include <iapiMiddle.h>
++
++/* ****************************************************************************
++ * Global Variable Section
++ *****************************************************************************/
++
++/*extern void * __HEAP_START;
++extern void * __HEAP_END;
++*/
++
++/* ****************************************************************************
++ * Function Section
++ *****************************************************************************/
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/iapiOS.c 2010-12-03 09:51:55.408346904 +0100
+@@ -0,0 +1,64 @@
++/******************************************************************************
++ *
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ *
++ ******************************************************************************
++ *
++ * File: iapiOS.c
++ *
++ * $Id iapiOS.c $
++ *
++ * Description:
++ * This library is written in C to guarantee functionality and integrity in
++ * the usage of SDMA virtual DMA channels. This API (Application Programming
++ * Interface) allow SDMA channels' access in an OPEN, READ, WRITE, CLOSE
++ * fashion.
++ * These are the OS level functions of the I.API - are OS dependant and must
++ * be provided by the user of I.API.
++ *
++ *
++ * /
++ *
++ * $Log iapiOS.c $
++ *
++ *****************************************************************************/
++
++/* ****************************************************************************
++ * Include File Section
++ *****************************************************************************/
++#include <epm.h>
++#include <iapi.h>
++
++/**
++ * Function Section
++ */
++#ifdef CONFIG_SDMA_IRAM
++void* (*iapi_iram_Malloc)(size_t size);
++#endif /*CONFIG_SDMA_IRAM*/
++
++void* (*iapi_Malloc)(size_t size);
++void (*iapi_Free)(void *ptr);
++
++dma_addr_t (*iapi_Virt2Phys) (void *ptr);
++void* (*iapi_Phys2Virt) (dma_addr_t ptr);
++
++void (*iapi_WakeUp)(int);
++void (*iapi_GotoSleep)(int);
++void (*iapi_InitSleep)(int);
++
++void* (*iapi_memcpy)(void *dest, const void *src, size_t count);
++void* (*iapi_memset)(void *dest, int c, size_t count);
++
++void (*iapi_EnableInterrupts)(void);
++void (*iapi_DisableInterrupts)(void);
++
++int (*iapi_GetChannel)(int);
++int (*iapi_ReleaseChannel)(int);
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/Makefile linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/Makefile
+--- linux.35.old/arch/arm/plat-mxc/sdma/iapi/src/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/iapi/src/Makefile 2010-12-03 09:51:55.412348386 +0100
+@@ -0,0 +1,20 @@
++#
++# Makefile for I.API sources.
++#
++
++ifneq ($(KBUILD_SRC),)
++ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \
++ -I$(KBUILD_SRC)/include/linux \
++ -DMCU -DOS=LINUX \
++ -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \
++ -DENDIANNESS=L_I_T_T_L_E_ENDIAN
++else
++ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \
++ -Iinclude/linux \
++ -DMCU -DOS=LINUX \
++ -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \
++ -DENDIANNESS=L_I_T_T_L_E_ENDIAN
++endif
++
++#obj-y += iapiLow.o iapiLowMcu.o iapiMiddle.o iapiMiddleMcu.o iapiHigh.o iapiDefaults.o iapiOS.o
++obj-y += iapiLow.o iapiLowMcu.o iapiMiddle.o iapiHigh.o iapiDefaults.o iapiOS.o
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/Makefile linux.35.new/arch/arm/plat-mxc/sdma/Makefile
+--- linux.35.old/arch/arm/plat-mxc/sdma/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/Makefile 2010-12-03 09:51:55.412348386 +0100
+@@ -0,0 +1,18 @@
++ifneq ($(KBUILD_SRC),)
++ccflags-y += -I$(KBUILD_SRC)/arch/arm/plat-mxc/sdma/iapi/include \
++ -I$(KBUILD_SRC)/include/linux \
++ -DMCU -DOS=LINUX \
++ -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \
++ -DENDIANNESS=L_I_T_T_L_E_ENDIAN
++else
++ccflags-y += -Iarch/arm/plat-mxc/sdma/iapi/include \
++ -Iinclude/linux \
++ -DMCU -DOS=LINUX \
++ -DL_I_T_T_L_E_ENDIAN=0 -DB_I_G_ENDIAN=1 \
++ -DENDIANNESS=L_I_T_T_L_E_ENDIAN
++endif
++
++obj-y += dma_sdma.o
++obj-$(CONFIG_MXC_SDMA_API) += sdma.o
++obj-$(CONFIG_MXC_SDMA_API) += iapi/
++obj-$(CONFIG_MXC_SDMA_API) += sdma_malloc.o
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/sdma.c linux.35.new/arch/arm/plat-mxc/sdma/sdma.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/sdma.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/sdma.c 2010-12-03 09:51:55.416347546 +0100
+@@ -0,0 +1,1653 @@
++/*
++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*
++ * file plat-mxc/sdma/sdma.c
++ * This file contains functions for Smart DMA API
++ *
++ * SDMA (Smart DMA) is used for transferring data between MCU and peripherals
++ *
++ */
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/semaphore.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/proc_fs.h>
++
++#include <asm/uaccess.h>
++#include <asm/irq.h>
++#include <mach/dma.h>
++#include <mach/hardware.h>
++
++#include <iapi.h>
++#include <epm.h>
++#include "sdma.h"
++
++#define M3_BASE_ADDRESS CSD0_BASE_ADDR
++#define CHAD(ch) sdma_data[0].cd->ccb_ptr[ch].channelDescriptor
++
++void __iomem *sdma_base_addr = NULL;
++
++/*
++ * SDMA status mutex
++ */
++static struct semaphore sdma_status_mutex;
++
++/*
++ * SDMA channel sleep queues
++ */
++//static struct semaphore sdma_sleep_mutex[MAX_DMA_CHANNELS];
++static wait_queue_head_t sdma_sleep_queue[MAX_DMA_CHANNELS];
++
++/*
++ * SDMA channel synchronization
++ */
++static struct semaphore sdma_synch_mutex[MAX_DMA_CHANNELS];
++
++struct clk *mxc_sdma_clk;
++
++/*
++ * Structure containing sdma channels information.
++ */
++typedef struct {
++ /* Channel number */
++ int channel;
++ /* Channel usage name */
++ int in_use;
++ /* Name of device using the channel */
++ char devicename[MAX_DEVNAME_LENGTH];
++ /* Transfer type. Needed for setting SDMA script */
++ sdma_transferT transfer_type;
++ /* Peripheral type. Needed for setting SDMA script */
++ sdma_periphT peripheral_type;
++ /* Watermark level of device's fifo */
++ __u32 watermark_level;
++ /* Peripheral event id */
++ int event_id;
++ /* Peripheral event id2 (for channels that use 2 events) */
++ int event_id2;
++ /* Running status (boolean) */
++ int running;
++ /* buffer descriptors number */
++ int bd_number;
++ /* callback function */
++ dma_callback_t callback;
++ /* callback argument */
++ void *arg;
++ /* SDMA data access word size */
++ unsigned long word_size:8;
++ /* channel descriptor pointer */
++ channelDescriptor *cd;
++} sdma_struct;
++
++/*
++ * Used to save the status of channels.
++ */
++static sdma_struct sdma_data[MAX_DMA_CHANNELS];
++
++/*
++ * Stores the start address of the SDMA scripts
++ */
++static sdma_script_start_addrs sdma_script_addrs;
++
++extern void mxc_sdma_get_script_info(sdma_script_start_addrs *sdma_script_add);
++
++/*
++ * Init sleep mutex of the channel
++ *
++ * @param channel channel number
++ */
++static void sdma_init_sleep(int channel)
++{
++ init_waitqueue_head(&sdma_sleep_queue[channel]);
++}
++
++#ifdef DEBUG
++#define SHOW_REG(b, p, r) __show_reg(b, p, r, #r)
++
++static inline void __show_reg(void __iomem *base, unsigned long phys,
++ unsigned int reg, const char *name)
++{
++ DBG(0, "%-12s[%08lx]=%08x\n", name, phys + reg, __raw_readl(base + reg));
++}
++
++void dump_sdma_regs(void)
++{
++ unsigned int reg;
++
++ for (reg = 0; reg < 0x180; reg += 4) {
++ SHOW_REG(sdma_base_addr, SDMA_BASE_ADDR, reg);
++ }
++}
++#endif
++
++/*
++ * Puts channel to sleep
++ *
++ * @param channel channel number
++ */
++#include <linux/delay.h>
++
++static void sdma_sleep_channel(int channel)
++{
++ int ret;
++
++ DBG(1, "%s: Waiting for channel %d to drain\n",
++ __FUNCTION__, channel);
++ BUG_ON(irqs_disabled());
++
++ ret = wait_event_interruptible_timeout(sdma_sleep_queue[channel],
++ iapi_SDMAIntr & (1 << channel), HZ);
++ if (ret == 0 && !(iapi_SDMAIntr & (1 << channel))) {
++ DBG(-1, "%s: Wait for channel %d done timed out: %08lx\n",
++ __FUNCTION__, channel, iapi_SDMAIntr);
++ } else if (ret < 0) {
++ DBG(-1, "%s: Wait for channel %d aborted: %08lx, %d\n",
++ __FUNCTION__, channel, iapi_SDMAIntr, ret);
++ } else {
++ DBG(1, "%s: Wait for channel %d done finished after %u ticks: %08lx\n",
++ __FUNCTION__, channel, HZ - ret, iapi_SDMAIntr);
++ }
++}
++
++/*
++ * Wake up channel from sleep
++ *
++ * @param channel channel number
++ */
++static void sdma_wakeup_channel(int channel)
++{
++ DBG(1, "%s: Waking up channel %d\n", __FUNCTION__, channel);
++ wake_up_interruptible(&sdma_sleep_queue[channel]);
++}
++
++/*
++ * Sdma interrupt handler routine.
++ * Calls channels callback function
++ *
++ * @param irq the interrupt number
++ * @param dev_id driver private data
++ * @return the function returns \b IRQ_RETVAL(1) - interrupt was handled
++ */
++static irqreturn_t sdma_int_handler(int irq, void *dev_id)
++{
++ DBG(2, "%s: IRQ %d\n", __FUNCTION__, irq);
++ IRQ_Handler();
++ DBG(2, "%s: Done\n", __FUNCTION__);
++ return IRQ_HANDLED;
++}
++
++/*
++ * I.API channel callback function
++ *
++ * @param cd channel descriptor structure
++ * @param channel_data SDMA struct of the current channel
++ */
++static void iapi_interrupt_callback(channelDescriptor *cd,
++ sdma_struct *channel_data)
++{
++ int channel;
++ dma_callback_t callback;
++ void *arg;
++
++ DBG(2, "%s: cd=%p\n", __FUNCTION__, cd);
++ channel = channel_data->channel;
++
++ channel_data->running = 0;
++
++ arg = channel_data->arg;
++
++ if (arg == NULL) {
++ arg = &channel;
++ }
++
++ callback = channel_data->callback;
++
++ if (callback != NULL) {
++ DBG(2, "%s: Calling %p\n", __FUNCTION__, callback);
++ callback(arg);
++ }
++}
++
++/*
++ * Returns pc of SDMA script according to peripheral and transfer type
++ *
++ * @param peripheral_type peripheral type
++ * @param transfer_type transfer type
++ *
++ * @return PC of SDMA script
++*/
++static unsigned short sdma_get_pc(sdma_periphT peripheral_type,
++ sdma_transferT transfer_type)
++{
++ int res = 0;
++
++ if (peripheral_type == MEMORY) {
++ switch (transfer_type) {
++ case emi_2_int:
++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr;
++ break;
++ case emi_2_emi:
++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr;
++ break;
++ case int_2_emi:
++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == DSP) {
++ switch (transfer_type) {
++ case emi_2_dsp:
++ res = sdma_script_addrs.mxc_sdma_ap_2_bp_addr;
++ break;
++ case dsp_2_emi:
++ res = sdma_script_addrs.mxc_sdma_bp_2_ap_addr;
++ break;
++ case dsp_2_emi_loop:
++ res =
++ sdma_script_addrs.
++ mxc_sdma_loopback_on_dsp_side_addr;
++ break;
++ case emi_2_dsp_loop:
++ res =
++ sdma_script_addrs.mxc_sdma_mcu_interrupt_only_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == FIRI) {
++ switch (transfer_type) {
++ case per_2_int:
++ res = sdma_script_addrs.mxc_sdma_firi_2_per_addr;
++ break;
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_firi_2_mcu_addr;
++ break;
++ case int_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_firi_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_firi_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == UART) {
++ switch (transfer_type) {
++ case per_2_int:
++ res = sdma_script_addrs.mxc_sdma_uart_2_per_addr;
++ break;
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_uart_2_mcu_addr;
++ break;
++ case int_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_app_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == UART_SP) {
++ switch (transfer_type) {
++ case per_2_int:
++ res = sdma_script_addrs.mxc_sdma_uartsh_2_per_addr;
++ break;
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_uartsh_2_mcu_addr;
++ break;
++ case int_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_shp_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == ATA) {
++ switch (transfer_type) {
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_ata_2_mcu_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_ata_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == CSPI || peripheral_type == EXT ||
++ peripheral_type == SSI) {
++ switch (transfer_type) {
++ case per_2_int:
++ res = sdma_script_addrs.mxc_sdma_app_2_per_addr;
++ break;
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_app_2_mcu_addr;
++ break;
++ case int_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_app_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == SSI_SP || peripheral_type == MMC ||
++ peripheral_type == SDHC || peripheral_type == CSPI_SP ||
++ peripheral_type == ESAI || peripheral_type == MSHC_SP) {
++ switch (transfer_type) {
++ case per_2_int:
++ res = sdma_script_addrs.mxc_sdma_shp_2_per_addr;
++ break;
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr;
++ break;
++ case int_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_shp_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == ASRC) {
++ switch (transfer_type) {
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr;
++ break;
++ case per_2_per:
++ res = sdma_script_addrs.mxc_sdma_per_2_per_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == MSHC) {
++ switch (transfer_type) {
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_mshc_2_mcu_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_mshc_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == CCM) {
++ switch (transfer_type) {
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_dptc_dvfs_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == FIFO_MEMORY) {
++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_fixed_addr;
++ } else if (peripheral_type == SPDIF) {
++ switch (transfer_type) {
++ case per_2_emi:
++ res = sdma_script_addrs.mxc_sdma_spdif_2_mcu_addr;
++ break;
++ case emi_2_per:
++ res = sdma_script_addrs.mxc_sdma_mcu_2_spdif_addr;
++ break;
++ default:
++ res = -EINVAL;
++ }
++ } else if (peripheral_type == IPU_MEMORY) {
++ if (transfer_type == emi_2_per) {
++ res = sdma_script_addrs.mxc_sdma_ext_mem_2_ipu_addr;
++ } else {
++ res = -EINVAL;
++ }
++ }
++
++ if (res < 0) {
++ printk(KERN_ERR "SDMA script not found\n");
++ } else {
++ DBG(1, "%s: PC[%d,%d]=%04x\n", __FUNCTION__,
++ peripheral_type, transfer_type, res);
++ }
++ return res;
++
++}
++
++static inline int sdma_asrc_set_info(dma_channel_params *p,
++ script_data *pcontext, int eflags)
++{
++ dma_channel_ext_params *ep = (dma_channel_ext_params *)p;
++ unsigned int wml, tmp, wml1, wml2;
++ struct dma_channel_asrc_info *info = &ep->info.asrc;
++
++ wml = 0;
++ if (p->transfer_type == per_2_per) {
++ if (!p->ext)
++ return wml;
++ wml1 = p->watermark_level;
++ wml2 = ep->watermark_level2;
++ if (info->channs) {
++ wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) <<
++ SDMA_ASRC_INFO_N_OFF;
++ if (ep->p2p_dir)
++ wml2 *= info->channs & SDMA_ASRC_INFO_N_MASK;
++ else
++ wml1 *= info->channs & SDMA_ASRC_INFO_N_MASK;
++ }
++ if (info->channs & 1) {
++ if (ep->p2p_dir)
++ wml |= SDMA_ASRC_P2P_INFO_PS;
++ else
++ wml |= SDMA_ASRC_P2P_INFO_PA;
++ }
++ if (wml1 > wml2) {
++ tmp = wml2 & SDMA_ASRC_P2P_INFO_LWML_MASK;
++ wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF;
++ tmp = wml1 & SDMA_ASRC_P2P_INFO_HWML_MASK;
++ wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF;
++ if (eflags & (1 << 31))
++ wml |= SDMA_ASRC_P2P_INFO_LWE;
++ if (eflags & (1 << 30))
++ wml |= SDMA_ASRC_P2P_INFO_HWE;
++ } else {
++ tmp = wml1 & SDMA_ASRC_P2P_INFO_LWML_MASK;
++ wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF;
++ tmp = wml2 & SDMA_ASRC_P2P_INFO_HWML_MASK;
++ wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF;
++ wml |= eflags >> 2;
++ tmp = pcontext->event_mask2;
++ pcontext->event_mask2 = pcontext->event_mask1;
++ pcontext->event_mask1 = tmp;
++ }
++ } else {
++ if (p->ext && info->channs) {
++ wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) <<
++ SDMA_ASRC_INFO_N_OFF;
++ tmp = (info->channs * p->watermark_level) &
++ SDMA_ASRC_INFO_WML_MASK;
++ wml |= tmp << SDMA_ASRC_INFO_WML_OFF;
++ } else {
++ tmp = (p->watermark_level & SDMA_ASRC_INFO_WML_MASK);
++ wml |= tmp << SDMA_ASRC_INFO_WML_OFF;
++ }
++
++ if (p->transfer_type == per_2_emi)
++ wml |= SDMA_ASRC_INFO_TXFR_DIR;
++
++ if (p->ext && (info->channs & 1)) {
++ if (p->transfer_type == per_2_emi)
++ wml |= SDMA_ASRC_INFO_PS;
++ else
++ wml |= SDMA_ASRC_INFO_PA;
++ }
++ wml |= eflags;
++ }
++ return wml;
++}
++
++/*
++ * Downloads channel context according to channel parameters
++ *
++ * @param channel channel number
++ * @param p channel parameters
++ */
++static int sdma_load_context(int channel, dma_channel_params *p)
++{
++ script_data context;
++ int res;
++ int event1_greater_than_32;
++ int event2_greater_than_32;
++ dma_channel_ext_params *ep = (dma_channel_ext_params *)p;
++
++ res = 0;
++
++ memset(&context, 0, sizeof(script_data));
++ context.load_address = sdma_get_pc(p->peripheral_type,
++ p->transfer_type);
++
++ if (context.load_address > 0) {
++ if ((p->peripheral_type != MEMORY) &&
++ (p->peripheral_type != DSP)) {
++ /* Handle multiple event channels differently */
++ if (p->event_id2) {
++ if (p->event_id2 < 32) {
++ context.event_mask2 =
++ 0x1 << p->event_id2;
++ event2_greater_than_32 = 0;
++ } else {
++ context.event_mask2 =
++ 0x1 << (p->event_id2 - 32);
++ event2_greater_than_32 = 1 << 31;
++ }
++ if (p->event_id < 32) {
++ context.event_mask1 =
++ 0x1 << p->event_id;
++ event1_greater_than_32 = 0;
++ } else {
++ context.event_mask1 =
++ 0x1 << (p->event_id - 32);
++ event1_greater_than_32 = 1 << 30;
++ }
++ } else {
++ event1_greater_than_32 = 0;
++ event2_greater_than_32 = 0;
++ if (p->event_id < 32) {
++ context.event_mask1 =
++ 0x1 << p->event_id;
++ context.event_mask2 = 0;
++ } else {
++ context.event_mask1 = 0;
++ context.event_mask2 =
++ 0x1 << (p->event_id - 32);
++ }
++ }
++
++ if (p->ext)
++ context.wml = ep->info_bits;
++ /* Watermark Level */
++ if (p->peripheral_type == ASRC) {
++ context.wml |= sdma_asrc_set_info(p,
++ &context,
++ event2_greater_than_32
++ |
++ event1_greater_than_32);
++ } else
++ context.wml |= event2_greater_than_32 |
++ event1_greater_than_32 | p->watermark_level;
++
++ /* Address */
++ context.shp_addr = p->per_address;
++ iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_PERIPHADDR, p->per_address);
++ } else {
++ context.wml = M3_BASE_ADDRESS;
++ }
++
++ sdma_data[channel].transfer_type = p->transfer_type;
++ sdma_data[channel].peripheral_type = p->peripheral_type;
++ sdma_data[channel].watermark_level = p->watermark_level;
++ iapi_AssignScript(sdma_data[channel].cd, &context);
++ } else {
++ res = context.load_address;
++ }
++
++ return res;
++}
++
++/*
++ * Setup channel according to parameters. Must be called once after mxc_request_dma()
++ *
++ * @param channel channel number
++ * @param p channel parameters pointer
++ * @return 0 on success, error code on fail
++ */
++int mxc_dma_setup_channel(int channel, dma_channel_params *p)
++{
++ int err = 0;
++ int i;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ mxc_dma_stop(channel);
++
++ for (i = 0; i < sdma_data[channel].bd_number; i++) {
++ iapi_IoCtl(sdma_data[channel].cd,
++ (i << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_STATUS, 0);
++ }
++
++ DBG(0, "%s: Changing number of BDs for channel %d from %u to %u\n",
++ __FUNCTION__, channel, sdma_data[channel].bd_number,
++ p->bd_number <= 0 ? 1 : p->bd_number);
++ sdma_data[channel].bd_number = (p->bd_number <= 0) ? 1 : p->bd_number;
++
++ sdma_data[channel].word_size = p->word_size;
++
++ sdma_data[channel].event_id = p->event_id;
++ sdma_data[channel].event_id2 = p->event_id2;
++
++ sdma_data[channel].callback = p->callback;
++
++ sdma_data[channel].arg = p->arg;
++
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_BDNUM, sdma_data[channel].bd_number);
++ if (err < 0) {
++ printk(KERN_ERR "Failed to allocate buffer descriptors: %d\n",
++ err);
++ err = -ENOMEM;
++ goto setup_channel_fail;
++ }
++
++ if (channel != 0) {
++ switch (p->transfer_type) {
++ case dsp_2_per:
++ break;
++ case emi_2_per:
++ case int_2_per:
++ case per_2_int:
++ case per_2_emi:
++ case per_2_per:
++ /*
++ * Peripheral <------> Memory
++ * evtOvr = 0 dspOvr = 1
++ */
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_OWNERSHIP,
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ if (err)
++ goto setup_channel_fail;
++ if (p->event_id) {
++ err = iapi_SetChannelEventMapping(p->event_id,
++ 1 << channel);
++ if (err)
++ goto setup_channel_fail;
++ }
++ if (p->event_id2) {
++ err = iapi_SetChannelEventMapping(p->event_id2,
++ 1 << channel);
++ }
++ break;
++ case emi_2_dsp:
++ case int_2_dsp:
++ case dsp_2_int:
++ case dsp_2_emi:
++ case dsp_2_dsp:
++ /*
++ * DSP <-----------> Memory
++ * evtOvr = 1 dspOvr = 0
++ */
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_OWNERSHIP,
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ break;
++ case emi_2_int:
++ case emi_2_emi:
++ case int_2_int:
++ case int_2_emi:
++ case emi_2_dsp_loop:
++ case dsp_2_emi_loop:
++ /* evtOvr = 1 dspOvr = 1 */
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_OWNERSHIP,
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ break;
++ case per_2_dsp:
++ /* evtOvr = 0 dspOvr = 0 */
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_OWNERSHIP,
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ if (err)
++ goto setup_channel_fail;
++ err = iapi_SetChannelEventMapping(p->event_id,
++ 1 << channel);
++ break;
++ default:
++ break;
++ printk(KERN_ERR "Wrong SDMA transfer type\n");
++ err = -EINVAL;
++ }
++ if (err)
++ goto setup_channel_fail;
++
++ err = sdma_load_context(channel, p);
++ if (err)
++ goto setup_channel_fail;
++
++ err = iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY,
++ MXC_SDMA_DEFAULT_PRIORITY);
++ }
++setup_channel_fail:
++ return err;
++}
++EXPORT_SYMBOL(mxc_dma_setup_channel);
++
++/*
++ * Setup the channel priority. This can be used to change the default priority
++ * for the channel.
++ *
++ * @param channel channel number
++ * @param priority priority to be set for the channel
++ *
++ * @return 0 on success, error code on failure
++ */
++int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ if (priority < MXC_SDMA_MIN_PRIORITY
++ || priority > MXC_SDMA_MAX_PRIORITY) {
++ return -EINVAL;
++ }
++ return iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY,
++ priority);
++}
++EXPORT_SYMBOL(mxc_dma_set_channel_priority);
++
++/*
++ * Allocates dma channel.
++ * If channel's value is 0, then the function allocates a free channel
++ * dynamically and sets its value to channel.
++ * Else allocates requested channel if it is free.
++ * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned.
++ *
++ * @param channel pointer to channel number
++ * @param devicename device name
++ * @return 0 on success, error code on fail
++ */
++int mxc_request_dma(int *channel, const char *devicename)
++{
++ int i, res = -EBUSY;
++
++ if (sdma_base_addr == NULL)
++ return -ENOSYS;
++
++ if (channel == NULL || *channel < 0 || *channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ down(&sdma_status_mutex);
++
++ /* Dynamic allocation */
++ if (*channel == 0) {
++ for (i = MAX_DMA_CHANNELS - 1; i > 0; i--) {
++#ifdef CONFIG_SDMA_IRAM
++ /*TODO:It will be removed after DPTC used UDMA interface */
++ if (i >= MXC_DMA_CHANNEL_IRAM)
++ continue;
++#endif /* CONFIG_SDMA_IRAM */
++ if (!sdma_data[i].in_use) {
++ *channel = i;
++ res = 0;
++ break;
++ }
++ }
++ } else {
++ if (sdma_data[*channel].in_use)
++ return -EBUSY;
++ res = 0;
++ }
++ if (res)
++ return res;
++
++ DBG(1, "%s: Opening channel %d\n", __FUNCTION__, *channel);
++
++ res = iapi_Open(sdma_data[0].cd, *channel);
++ if (res < 0) {
++ printk(KERN_ERR "Failed iapi_Open channel %d, 0x%x\n",
++ *channel, res);
++ } else {
++ sdma_data[*channel].in_use = 1;
++ strlcpy(sdma_data[*channel].devicename, devicename,
++ sizeof(sdma_data[*channel].devicename));
++ sdma_data[*channel].cd = CHAD(*channel);
++
++ iapi_IoCtl(sdma_data[*channel].cd, IAPI_CHANGE_SYNCH,
++ CALLBACK_ISR);
++ iapi_IoCtl(sdma_data[*channel].cd,
++ IAPI_CHANGE_CALLBACKFUNC,
++ (unsigned long)iapi_interrupt_callback);
++ iapi_IoCtl(sdma_data[*channel].cd,
++ IAPI_CHANGE_USER_ARG,
++ (unsigned long)&sdma_data[*channel]);
++ }
++
++ up(&sdma_status_mutex);
++
++ return res;
++}
++EXPORT_SYMBOL(mxc_request_dma);
++
++/*
++ * Configures request parameters. Can be called multiple times after
++ * mxc_request_dma() and mxc_dma_setup_channel().
++ *
++ *
++ * @param channel channel number
++ * @param p request parameters pointer
++ * @param bd_index index of buffer descriptor to set
++ * @return 0 on success, error code on fail
++ */
++int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index)
++{
++ int ret;
++ unsigned long param;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ if (!sdma_data[channel].in_use) {
++ return -EINVAL;
++ }
++ DBG(0, "%s: dma_request: src: %08x dst: %08x cont=%d wrap=%d\n",
++ __FUNCTION__, p->sourceAddr, p->destAddr,
++ p->bd_cont, p->bd_wrap);
++
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_TRANSFER_CD, sdma_data[channel].word_size);
++ if (ret < 0)
++ return ret;
++
++ param = BD_DONE | BD_INTR | BD_EXTD;
++
++ if (sdma_data[channel].bd_number > 1 && p->bd_cont) {
++ param |= BD_CONT;
++ }
++
++ if (bd_index == sdma_data[channel].bd_number - 1 || p->bd_wrap) {
++ param |= BD_WRAP;
++ }
++
++ switch (sdma_data[channel].transfer_type) {
++ case emi_2_per:
++ case dsp_2_per:
++ case int_2_per:
++ case emi_2_dsp:
++ case int_2_dsp:
++ case emi_2_dsp_loop:
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_BUFFERADDR,
++ (unsigned long)p->sourceAddr);
++ break;
++ case per_2_int:
++ case per_2_emi:
++ case per_2_dsp:
++ case dsp_2_int:
++ case dsp_2_emi:
++ case dsp_2_dsp:
++ case dsp_2_emi_loop:
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_BUFFERADDR,
++ (unsigned long)p->destAddr);
++ break;
++ case emi_2_int:
++ case emi_2_emi:
++ case int_2_int:
++ case int_2_emi:
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_BUFFERADDR,
++ (unsigned long)p->sourceAddr);
++ if (ret < 0)
++ return ret;
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_EXTDBUFFERADDR,
++ (unsigned long)p->destAddr);
++ break;
++ case per_2_per:
++ case dvfs_pll:
++ case dvfs_pdr:
++ return -EINVAL;
++ }
++ if (ret < 0)
++ return ret;
++
++ /* Change the endianness for DSP to MCU Data transfers */
++ if (sdma_data[channel].transfer_type == dsp_2_emi ||
++ sdma_data[channel].transfer_type == emi_2_dsp) {
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ IAPI_CHANGE_SET_ENDIANNESS,
++ SET_BIT_ALL);
++ if (ret < 0)
++ return ret;
++ }
++
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_COUNT, p->count);
++ if (ret < 0)
++ return ret;
++
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS,
++ param);
++ return ret;
++}
++EXPORT_SYMBOL(mxc_dma_set_config);
++
++/*
++ * Configures the BD_INTR bit on a buffer descriptor parameters.
++ *
++ *
++ * @param channel channel number
++ * @param bd_index index of buffer descriptor to set
++ * @param bd_intr flag to set or clear the BD_INTR bit
++ * @return 0 on success, error code on fail
++ */
++void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr)
++{
++ unsigned long param;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return;
++
++ iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_STATUS, (unsigned long)¶m);
++
++ if (bd_intr) {
++ param |= BD_INTR;
++ } else {
++ param &= ~BD_INTR;
++ }
++ iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param);
++}
++EXPORT_SYMBOL(mxc_dma_set_bd_intr);
++
++/*
++ * Gets the BD_INTR bit on a buffer descriptor.
++ *
++ *
++ * @param channel channel number
++ * @param bd_index index of buffer descriptor to set
++ *
++ * @return returns the BD_INTR bit status
++ */
++int mxc_dma_get_bd_intr(int channel, int bd_index)
++{
++ int ret;
++ unsigned long bd_status = 0;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ ret = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status);
++
++ return ret == 0 ? !!(bd_status & BD_INTR) : ret;
++}
++EXPORT_SYMBOL(mxc_dma_get_bd_intr);
++
++/*
++ * Stop the current transfer
++ *
++ * @param channel channel number
++ * @param buffer_number number of buffers (beginning with 0),
++ * whose done bits should be reset to 0
++ */
++int mxc_dma_reset(int channel, int buffer_number)
++{
++ unsigned char param = 0;
++ int i = 0;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ if (!sdma_data[channel].in_use) {
++ return -EINVAL;
++ }
++
++ /* clear the BD_DONE bits for all the necessary buffers */
++ for (i = 0; i < buffer_number; i++) {
++
++ iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_STATUS, (unsigned long)¶m);
++
++ /* clear the BD_DONE bit of the buffer */
++ param &= ~BD_DONE;
++
++ iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_STATUS, param);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(mxc_dma_reset);
++
++/*
++ * Returns request parameters.
++ *
++ * @param channel channel number
++ * @param p request parameters pointer
++ * @param bd_index index of buffer descriptor to get
++ * @return 0 on success, error code on fail
++ */
++int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index)
++{
++ int err = 0;
++ unsigned long bd_status;
++ unsigned long bd_count;
++ dma_addr_t sourceAddr;
++ dma_addr_t destAddr;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ memset(p, 0, sizeof(*p));
++
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status);
++ if (err)
++ return err;
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_COUNT, (unsigned long)&bd_count);
++ if (err)
++ return err;
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_BUFFERADDR, (unsigned long)&sourceAddr);
++ if (err)
++ return err;
++
++ switch (sdma_data[channel].transfer_type) {
++ case emi_2_per:
++ case dsp_2_per:
++ case int_2_per:
++ case emi_2_dsp:
++ case int_2_dsp:
++ case emi_2_dsp_loop:
++ p->sourceAddr = sourceAddr;
++ break;
++ case per_2_int:
++ case per_2_emi:
++ case per_2_dsp:
++ case dsp_2_int:
++ case dsp_2_emi:
++ case dsp_2_dsp:
++ case dsp_2_emi_loop:
++ p->destAddr = sourceAddr;
++ break;
++ case emi_2_int:
++ case emi_2_emi:
++ case int_2_int:
++ case int_2_emi:
++ p->sourceAddr = sourceAddr;
++ err = iapi_IoCtl(sdma_data[channel].cd,
++ (bd_index << BD_NUM_OFFSET) |
++ IAPI_CHANGE_GET_EXTDBUFFERADDR,
++ (unsigned long)&destAddr);
++ if (err)
++ return err;
++ p->destAddr = destAddr;
++ break;
++ default:
++ break;
++ }
++
++ p->count = bd_count;
++ p->bd_done = !!(bd_status & BD_DONE);
++ p->bd_cont = !!(bd_status & BD_CONT);
++ p->bd_error = !!(bd_status & BD_RROR);
++ p->bd_wrap = !!(bd_status & BD_WRAP);
++
++ return err;
++}
++EXPORT_SYMBOL(mxc_dma_get_config);
++
++/*
++ * This function is used by MXC IPC's write_ex2. It passes the pointer to the
++ * data control structure to iapi_write_ipcv2()
++ *
++ * @param channel SDMA channel number
++ * @param ctrl_ptr Data Control structure pointer
++ */
++int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++ return iapi_Write_ipcv2(sdma_data[channel].cd, ctrl_ptr);
++}
++EXPORT_SYMBOL(mxc_sdma_write_ipcv2);
++
++/*
++ * This function is used by MXC IPC's read_ex2. It passes the pointer to the
++ * data control structure to iapi_read_ipcv2()
++ *
++ * @param channel SDMA channel number
++ * @param ctrl_ptr Data Control structure pointer
++ */
++int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++ return iapi_Read_ipcv2(sdma_data[channel].cd, ctrl_ptr);
++}
++EXPORT_SYMBOL(mxc_sdma_read_ipcv2);
++
++/*
++ * Starts dma channel.
++ *
++ * @param channel channel number
++ */
++int mxc_dma_start(int channel)
++{
++ DBG(1, "%s: Starting DMA channel %d\n", __FUNCTION__, channel);
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ if (!sdma_data[channel].running) {
++ sdma_data[channel].running = 1;
++ iapi_StartChannel(channel);
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(mxc_dma_start);
++
++/*
++ * Stops dma channel.
++ *
++ * @param channel channel number
++ */
++int mxc_dma_stop(int channel)
++{
++ DBG(1, "%s: Stopping DMA channel %d\n", __FUNCTION__, channel);
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ iapi_StopChannel(channel);
++ sdma_data[channel].running = 0;
++
++ return 0;
++}
++EXPORT_SYMBOL(mxc_dma_stop);
++
++/*
++ * Frees dma channel.
++ *
++ * @param channel channel number
++ */
++void mxc_free_dma(int channel)
++{
++ int i;
++
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return;
++
++ mxc_dma_stop(channel);
++
++ if (sdma_data[channel].event_id != 0) {
++ iapi_SetChannelEventMapping(sdma_data[channel].event_id, 0x0);
++ }
++ if (sdma_data[channel].event_id2 != 0) {
++ iapi_SetChannelEventMapping(sdma_data[channel].event_id2, 0x0);
++ }
++
++ sdma_data[channel].event_id = 0;
++
++ iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, 0x0);
++ iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP,
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++
++ for (i = 0; i < sdma_data[channel].bd_number; i++) {
++ iapi_IoCtl(sdma_data[channel].cd,
++ (i << BD_NUM_OFFSET) |
++ IAPI_CHANGE_SET_STATUS, 0);
++ }
++
++ iapi_Close(sdma_data[channel].cd);
++
++ strlcpy(sdma_data[channel].devicename, "not used",
++ sizeof(sdma_data[channel].devicename));
++
++ sdma_data[channel].in_use = 0;
++}
++EXPORT_SYMBOL(mxc_free_dma);
++
++/*
++ * Initializes channel's priorities
++ *
++ */
++static void __init init_priorities(void)
++{
++ iapi_IoCtl(sdma_data[0].cd, IAPI_CHANGE_PRIORITY, 0x7);
++}
++
++/*
++ * Initializes events table
++ */
++static void __init init_event_table(void)
++{
++ int channel;
++
++ for (channel = 0; channel < MAX_DMA_CHANNELS; channel++) {
++ iapi_SetChannelEventMapping(channel, 0);
++ }
++}
++
++/*
++ * Sets callback function. Used with standard dma api
++ * for supporting interrupts
++ *
++ * @param channel channel number
++ * @param callback callback function pointer
++ * @param arg argument for callback function
++ */
++void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return;
++
++ sdma_data[channel].callback = callback;
++ sdma_data[channel].arg = arg;
++}
++EXPORT_SYMBOL(mxc_dma_set_callback);
++
++/*
++ * Synchronization function used by I.API
++ *
++ * @param channel channel number
++ */
++static int getChannel(int channel)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++
++ if (irqs_disabled() || in_atomic()) {
++ if (down_trylock(&sdma_synch_mutex[channel])) {
++ return -EBUSY;
++ }
++ } else {
++ if (down_interruptible(&sdma_synch_mutex[channel])) {
++ return -EBUSY;
++ }
++ }
++
++ return 0;
++}
++
++/*
++ * Synchronization function used by I.API
++ *
++ * @param channel channel number
++ */
++static int releaseChannel(int channel)
++{
++ if (channel < 0 || channel >= MAX_DMA_CHANNELS)
++ return -EINVAL;
++ up(&sdma_synch_mutex[channel]);
++ return 0;
++}
++
++/*
++ * Unmask interrupt function. Used by I.API
++ *
++ */
++//static unsigned long flags;
++static void unmask_sdma_interrupt(void)
++{
++ /* Commented out to take care of the PREEMPT_RT option
++ * local_irq_restore(flags);
++ */
++}
++
++/*
++ * Mask interrupt function. Used by I.API
++ *
++ */
++static void mask_sdma_interrupt(void)
++{
++ /* Commented to take of the PREEMPT_RT option
++ * local_irq_save(flags);
++ */
++}
++
++#ifdef DEBUG
++static void *sdma_memcpy(void *dst, const void *src, size_t len)
++{
++ DBG(1, "%s: Copying %u byte from %p..%p to %p..%p\n", __FUNCTION__,
++ len, src, src + len - 1, dst, dst + len - 1);
++ memcpy(dst, src, len);
++ return dst;
++}
++#endif
++
++/*
++ * Initializes I.API
++ */
++static int __init init_iapi_struct(void)
++{
++ printk(KERN_INFO "Using SDMA I.API\n");
++
++ iapi_Malloc = &sdma_malloc;
++#ifdef CONFIG_SDMA_IRAM
++ iapi_iram_Malloc = &sdma_iram_malloc;
++#endif /* CONFIG_SDMA_IRAM */
++
++ iapi_Free = &sdma_free;
++ iapi_Virt2Phys = sdma_virt_to_phys;
++ iapi_Phys2Virt = sdma_phys_to_virt;
++ iapi_memset = &memset;
++#ifndef DEBUG
++ iapi_memcpy = &memcpy;
++#else
++ iapi_memcpy = &sdma_memcpy;
++#endif
++ iapi_GotoSleep = &sdma_sleep_channel;
++ iapi_WakeUp = &sdma_wakeup_channel;
++ iapi_InitSleep = &sdma_init_sleep;
++ iapi_ReleaseChannel = &releaseChannel;
++ iapi_GetChannel = &getChannel;
++
++ iapi_EnableInterrupts = &unmask_sdma_interrupt;
++ iapi_DisableInterrupts = &mask_sdma_interrupt;
++
++ sdma_data[0].cd = kzalloc(sizeof(channelDescriptor), GFP_KERNEL);
++ if (sdma_data[0].cd == NULL)
++ return -ENOMEM;
++ return 0;
++}
++
++/*
++ * Initializes channel synchronization mutexes
++ */
++static void __init sdma_init_mutexes(void)
++{
++ int i;
++
++ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
++ init_MUTEX(&sdma_synch_mutex[i]);
++ }
++
++ init_MUTEX(&sdma_status_mutex);
++}
++
++/*
++ * Channels status read proc file system function
++ *
++ * @param buf pointer to the buffer the data shuld be written to.
++ * @param start pointer to the pointer where the new data is
++ * written to.
++ * procedure should update the start pointer to point to
++ * where in the buffer the data was written.
++ * @param offset offset from start of the file
++ * @param count number of bytes to read.
++ * @param eof pointer to eof flag. sould be set to 1 when
++ * reaching eof.
++ * @param data driver specific data pointer.
++ *
++ * @return number byte read from the log buffer.
++ */
++static int proc_read_channels(char *buf, char **start, off_t offset, int count,
++ int *eof, void *data)
++{
++ char *log;
++ char *log_ptr;
++ char tmp[48];
++ int i;
++//#define LOG_BUF_SIZE 4096
++
++#ifdef LOG_BUF_SIZE
++ log = kzalloc(LOG_BUF_SIZE, GFP_KERNEL);
++ if (log == NULL) {
++ return -ENOMEM;
++ }
++#else
++ log = buf;
++#endif
++ log_ptr = log;
++
++ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
++ if (sdma_data[i].in_use == 0) {
++ continue;
++ }
++
++ memset(tmp, 0, sizeof(tmp));
++ snprintf(tmp, sizeof(tmp), "Channel %d: %s\n", i,
++ sdma_data[i].devicename);
++#ifndef LOG_BUF_SIZE
++ strlcpy(log_ptr, tmp, PAGE_SIZE - (log_ptr - log));
++#else
++ strlcpy(log_ptr, tmp, LOG_BUF_SIZE - (log_ptr - log));
++#endif
++ log_ptr += strlen(tmp);
++ if (log_ptr - log >= PAGE_SIZE)
++ break;
++ }
++
++ if (offset > (log_ptr - log)) {
++ *eof = 1;
++ count = 0;
++ } else {
++ if (offset + count > (log_ptr - log)) {
++ count = (log_ptr - log) - offset;
++ *eof = 1;
++ } else {
++ *eof = 0;
++ }
++
++ memcpy(buf, log, count);
++ *start = buf;
++ }
++#ifdef LOG_BUF_SIZE
++ kfree(log);
++#endif
++ return count;
++}
++
++/*
++ * SDMA proc file system read function
++ */
++static int __init init_proc_fs(void)
++{
++ struct proc_dir_entry *sdma_proc_dir;
++ int res;
++
++ res = 0;
++
++ sdma_proc_dir = proc_mkdir("sdma", NULL);
++ create_proc_read_entry("channels", 0, sdma_proc_dir,
++ proc_read_channels, NULL);
++
++ if (res < 0) {
++ printk(KERN_WARNING "Failed create SDMA proc entry\n");
++ }
++
++ return res;
++}
++
++/*
++ * Initializes SDMA private data
++ */
++static void __init init_sdma_data(void)
++{
++ int i;
++
++ sdma_data[0].in_use = 1;
++ strcpy(sdma_data[0].devicename, "MCU");
++
++ for (i = 0; i < MAX_DMA_CHANNELS; i++) {
++ sdma_data[i].channel = i;
++ }
++}
++
++#if defined(CONFIG_MXC_SUPER_GEM)
++/*
++ * Initialize the Super GEM SDMA channel
++ *
++ * @return returns NO FUCKING -1 on error, 0 on success.
++ */
++static int __init init_super_gem(void)
++{
++ channelDescriptor *cd;
++ script_data context;
++ int res = 0;
++
++ res = iapi_Open(sdma_data[0].cd, MXC_DMA_CHANNEL_GEM);
++ if (res < 0) {
++ return res;
++ }
++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 1;
++ cd = CHAD(MXC_DMA_CHANNEL_GEM);
++ memset(&context, 0, sizeof(script_data));
++ context.load_address = sdma_script_addrs.mxc_sdma_utra_addr;
++ context.wml = M3_BASE_ADDRESS;
++ res = iapi_AssignScript(cd, &context);
++ if (res < 0) {
++ iapi_Close(cd);
++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0;
++ return res;
++ }
++ res = iapi_IoCtl(cd, IAPI_CHANGE_OWNERSHIP,
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) |
++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) |
++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP));
++ if (res < 0) {
++ iapi_Close(cd);
++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0;
++ return res;
++ }
++ /* Set EP=1, which is required to start SuperGem script the first time */
++ /* This can be done only on the AP side */
++ SDMA_H_EVTPEND |= 1 << MXC_DMA_CHANNEL_GEM;
++
++ res = iapi_SetChannelEventMapping(DMA_REQ_GEM,
++ 1 << MXC_DMA_CHANNEL_GEM);
++ if (res < 0) {
++ iapi_Close(cd);
++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0;
++ return res;
++ }
++
++ return 0;
++}
++#endif
++
++/*
++ * Initializes dma
++ */
++int __init sdma_init(void)
++{
++ int res;
++ configs_data confreg_data;
++ struct clk *ahb_clk;
++
++ sdma_base_addr = ioremap(SDMA_BASE_ADDR, SZ_16K);
++ if (sdma_base_addr == NULL)
++ return -ENOMEM;
++
++ /* Initialize to the default values */
++ confreg_data = iapi_ConfigDefaults;
++
++#ifdef MXC_SDMA_DSPDMA
++ confreg_data.dspdma = MXC_SDMA_DSPDMA;
++#endif
++ /* Set ACR bit */
++ mxc_sdma_clk = clk_get_sys(NULL, "sdma");
++ if (IS_ERR(mxc_sdma_clk)) {
++ res = PTR_ERR(mxc_sdma_clk);
++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res);
++ goto clk_fail;
++ }
++
++ ahb_clk = clk_get_sys(NULL, "ahb");
++ if (IS_ERR(ahb_clk)) {
++ res = PTR_ERR(ahb_clk);
++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res);
++ goto clk_fail;
++ }
++ clk_enable(mxc_sdma_clk);
++ clk_enable(ahb_clk);
++ printk(KERN_INFO "AHB clock rate: %lu.%03luMHz SDMA clock rate: %lu.%03luMHz\n",
++ clk_get_rate(ahb_clk) / 1000000,
++ clk_get_rate(ahb_clk) / 1000 % 1000,
++ clk_get_rate(mxc_sdma_clk) / 1000000,
++ clk_get_rate(mxc_sdma_clk) / 1000 % 1000);
++ if (clk_get_rate(ahb_clk) / clk_get_rate(mxc_sdma_clk) != 2) {
++ printk(KERN_INFO "Setting SDMA ACR\n");
++ confreg_data.acr = 1;
++ }
++ clk_disable(ahb_clk);
++ clk_put(ahb_clk);
++
++ init_sdma_data();
++
++ init_sdma_pool();
++
++ res = request_irq(MXC_INT_SDMA, sdma_int_handler, 0, "mxc-sdma", NULL);
++ if (res) {
++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res);
++ goto sdma_init_fail;
++ }
++
++ sdma_init_mutexes();
++
++ res = init_iapi_struct();
++ if (res)
++ goto free_irq;
++
++ mxc_sdma_get_script_info(&sdma_script_addrs);
++
++ res = iapi_Init(sdma_data[0].cd, &confreg_data,
++ sdma_script_addrs.mxc_sdma_start_addr,
++ sdma_script_addrs.mxc_sdma_ram_code_size * 2,
++ sdma_script_addrs.mxc_sdma_ram_code_start_addr, 0x50);
++ if (res < 0) {
++ printk(KERN_EMERG "Failed to init SDMA API: %d\n", res);
++ goto free_mem;
++ }
++
++ init_priorities();
++
++ init_event_table();
++
++#if defined(CONFIG_MXC_SUPER_GEM)
++ res = init_super_gem();
++ if (res < 0) {
++ goto free_mem;
++ }
++#endif
++
++ init_proc_fs();
++
++ printk(KERN_INFO "MXC SDMA API initialized\n");
++
++ clk_disable(mxc_sdma_clk);
++ return res;
++free_mem:
++ kfree(sdma_data[0].cd);
++free_irq:
++ free_irq(MXC_INT_SDMA, NULL);
++sdma_init_fail:
++ clk_disable(mxc_sdma_clk);
++ clk_put(mxc_sdma_clk);
++clk_fail:
++ iounmap(sdma_base_addr);
++ sdma_base_addr = NULL;
++ printk(KERN_ERR "Error %d in sdma_init\n", res);
++ return res;
++}
++arch_initcall(sdma_init);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC Linux SDMA API");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/sdma.h linux.35.new/arch/arm/plat-mxc/sdma/sdma.h
+--- linux.35.old/arch/arm/plat-mxc/sdma/sdma.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/sdma.h 2010-12-03 09:51:55.416347546 +0100
+@@ -0,0 +1,13 @@
++#ifndef __SDMA_H
++#define __SDMA_H
++
++extern struct clk *mxc_sdma_clk;
++extern void __iomem *sdma_base_addr;
++
++/*
++ * SDMA buffers pool initialization function
++ */
++extern void init_sdma_pool(void);
++
++
++#endif /* __SDMA_H */
+diff -urN linux.35.old/arch/arm/plat-mxc/sdma/sdma_malloc.c linux.35.new/arch/arm/plat-mxc/sdma/sdma_malloc.c
+--- linux.35.old/arch/arm/plat-mxc/sdma/sdma_malloc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/sdma/sdma_malloc.c 2010-12-03 09:51:55.416347546 +0100
+@@ -0,0 +1,404 @@
++/*
++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file plat-mxc/sdma/sdma_malloc.c
++ * @brief This file contains functions for SDMA non-cacheable buffers allocation
++ *
++ * SDMA (Smart DMA) is used for transferring data between MCU and peripherals
++ *
++ * @ingroup SDMA
++ */
++
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/slab.h>
++#include <linux/mm.h>
++#include <linux/device.h>
++#include <linux/dma-mapping.h>
++#include <linux/dmapool.h>
++
++#include <asm/dma.h>
++#include <asm/mach/dma.h>
++#include <mach/hardware.h>
++#include <mach/sdma.h>
++
++#include <epm.h>
++#include "sdma.h"
++
++#ifdef CONFIG_SDMA_IRAM
++#define IRAM_VIRT_BASE IRAM_BASE_ADDR_VIRT
++#define IRAM_PHYS_BASE IRAM_BASE_ADDR
++#if (CONFIG_SDMA_IRAM_SIZE & 0x3FF)
++#error "IRAM size of SDMA should be multiple of 1Kbytes"
++#else
++#define IRAM_SDMA_SIZE CONFIG_SDMA_IRAM_SIZE /* 4K */
++#endif
++#define IRAM_UNIT_SIZE 512
++#define IRAM_POOL_SIZE (IRAM_SDMA_SIZE/IRAM_UNIT_SIZE)
++
++#define IS_IRAM_VIRT(x) (((x) < IRAM_VIRT_BASE) ? 0 : \
++ (((x) - IRAM_VIRT_BASE) > IRAM_SDMA_SIZE) ? 0 : 1)
++
++#define IS_IRAM_PHYS(x) (((x) < IRAM_PHYS_BASE) ? 0: \
++ (((x) - IRAM_PHYS_BASE) > IRAM_SDMA_SIZE) ? 0 : 1)
++#endif /*CONFIG_SDMA_IRAM */
++
++/*!
++ * Defines SDMA non-cacheable buffers pool
++ */
++static struct dma_pool *pool;
++
++#ifdef CONFIG_SDMA_IRAM
++typedef struct iram_head_s {
++ struct list_head list;
++} iram_head_t;
++
++static spinlock_t iram_pool_lock = SPIN_LOCK_UNLOCKED;
++static struct list_head iram_free_list;
++static unsigned char iram_pool_flag[IRAM_POOL_SIZE];
++
++static void sdma_iram_free(void *buf);
++#endif /*CONFIG_SDMA_IRAM */
++
++/*!
++ * SDMA memory conversion hashing structure
++ */
++typedef struct {
++ struct list_head node;
++ int use_count;
++ /*! Virtual address */
++ void *virt;
++ /*! Physical address */
++ unsigned long phys;
++} virt_phys_struct;
++
++static struct list_head buf_map;
++
++/*!
++ * Defines the size of each buffer in SDMA pool.
++ * The size must be at least 512 bytes, because
++ * sdma channel control blocks array size is 512 bytes
++ */
++#define SDMA_POOL_SIZE 1024
++
++/*!
++ * Adds new buffer structure into conversion hash tables
++ *
++ * @param vf SDMA memory conversion hashing structure
++ *
++ * @return 1 on success, 0 on fail
++ */
++static int add_entry(virt_phys_struct *vf)
++{
++ virt_phys_struct *p;
++
++ BUG_ON(in_atomic());
++ vf->phys &= PAGE_MASK;
++ vf->virt = (void *)((unsigned long)vf->virt & PAGE_MASK);
++
++ list_for_each_entry(p, &buf_map, node) {
++ if (p->virt == vf->virt) {
++ p->use_count++;
++ return 0;
++ }
++ }
++
++ p = kzalloc(sizeof(virt_phys_struct), GFP_KERNEL);
++ if (p == NULL) {
++ return -ENOMEM;
++ }
++
++ p->phys = vf->phys & PAGE_MASK;
++ p->virt = (void *)((unsigned long)vf->virt & PAGE_MASK);
++ p->use_count = 1;
++ list_add_tail(&p->node, &buf_map);
++
++ DBG(2, "added vaddr 0x%p, paddr 0x%08lX to list\n", p->virt, p->phys);
++ return 0;
++}
++
++/*!
++ * Deletes buffer stracture from conversion hash tables
++ *
++ * @param buf SDMA memory buffer virtual addr
++ *
++ * @return 0 on success, -1 on fail
++ */
++static int delete_entry(void *buf)
++{
++ virt_phys_struct *p;
++
++ buf = (void *)((unsigned long)buf & PAGE_MASK);
++
++ list_for_each_entry(p, &buf_map, node) {
++ if (p->virt == buf) {
++ p->use_count--;
++ break;
++ }
++ }
++
++ if (p->use_count == 0) {
++ list_del(&p->node);
++ kfree(p);
++ }
++
++ return 0;
++}
++
++/*!
++ * Virtual to physical address conversion functio
++ *
++ * @param buf pointer to virtual address
++ *
++ * @return physical address
++ */
++dma_addr_t sdma_virt_to_phys(void *buf)
++{
++ unsigned long offset = (unsigned long)buf & ~PAGE_MASK;
++ virt_phys_struct *p;
++
++ DBG(2, "searching for vaddr 0x%p offs=%08lx\n", buf, offset);
++
++#ifdef CONFIG_SDMA_IRAM
++ if (IS_IRAM_VIRT(buf)) {
++ if ((unsigned long)buf & (IRAM_UNIT_SIZE - 1)) {
++ printk(KERN_WARNING "%s buffer offset = %ld\n",
++ __FUNCTION__, (unsigned long)buf);
++ }
++ return (unsigned long)buf + IRAM_PHYS_BASE -
++ (unsigned long)IRAM_VIRT_BASE;
++ }
++#endif /* CONFIG_SDMA_IRAM */
++
++ list_for_each_entry(p, &buf_map, node) {
++ if ((unsigned long)p->virt == ((unsigned long)buf & PAGE_MASK)) {
++ return p->phys | offset;
++ }
++ }
++
++ if (virt_addr_valid(buf)) {
++ return virt_to_phys(buf);
++ }
++
++ printk(KERN_ERR "SDMA malloc: could not translate virt address 0x%p\n",
++ buf);
++ __backtrace();
++ return 0;
++}
++EXPORT_SYMBOL(sdma_virt_to_phys);
++
++/*!
++ * Physical to virtual address conversion function
++ *
++ * @param buf pointer to physical address
++ *
++ * @return virtual address
++ */
++void *sdma_phys_to_virt(dma_addr_t buf)
++{
++ unsigned long offset = buf & ~PAGE_MASK;
++ virt_phys_struct *p;
++
++ DBG(1, "%s: phys=%08x\n", __FUNCTION__, buf);
++
++#ifdef CONFIG_SDMA_IRAM
++ if (IS_IRAM_PHYS(buf)) {
++ if (buf & (IRAM_UNIT_SIZE - 1)) {
++ printk(KERN_WARNING "%s buffer offset = %ld\n",
++ __FUNCTION__, (unsigned long)buf);
++ }
++ return buf + IRAM_VIRT_BASE - IRAM_PHYS_BASE;
++ }
++#endif /* CONFIG_SDMA_IRAM */
++
++ list_for_each_entry(p, &buf_map, node) {
++ if (p->phys == (buf & PAGE_MASK)) {
++ void *ptr = (void *)((unsigned long)p->virt | offset);
++
++ DBG(1, "%s: virt: %08lx phys: %08lx\n", __FUNCTION__,
++ (unsigned long)p->virt | offset, p->phys);
++#if 0
++ print_hex_dump(KERN_DEBUG, "sdma: ", DUMP_PREFIX_ADDRESS, 4, 4,
++ ptr, 32 * 16, 0);
++#endif
++ return ptr;
++ }
++ }
++
++ printk(KERN_ERR "SDMA malloc: could not translate phys address 0x%08x\n",
++ buf);
++ __backtrace();
++ return NULL;
++}
++EXPORT_SYMBOL(sdma_phys_to_virt);
++
++/*!
++ * Allocates uncacheable buffer
++ *
++ * @param size size of allocated buffer
++ * @return pointer to buffer
++ */
++void *sdma_malloc(size_t size)
++{
++ void *buf;
++ dma_addr_t dma_addr;
++ virt_phys_struct vf;
++
++ if (size > SDMA_POOL_SIZE) {
++ printk(KERN_ERR "size in sdma_malloc is more than %d bytes\n",
++ SDMA_POOL_SIZE);
++ return NULL;
++ } else {
++ buf = dma_pool_alloc(pool, GFP_KERNEL, &dma_addr);
++ if (buf != NULL) {
++ vf.virt = buf;
++ vf.phys = dma_addr;
++
++ if (add_entry(&vf) < 0) {
++ dma_pool_free(pool, buf, dma_addr);
++ buf = NULL;
++ }
++ }
++ }
++
++ DBG(2, "allocated vaddr 0x%p..%p phys: %08x..%08x\n",
++ buf, buf + size - 1, dma_addr, dma_addr + size - 1);
++ return buf;
++}
++EXPORT_SYMBOL(sdma_malloc);
++
++/*!
++ * Frees uncacheable buffer
++ *
++ * @param buf buffer pointer for deletion
++ */
++void sdma_free(void *buf)
++{
++#ifdef CONFIG_SDMA_IRAM
++ if (IS_IRAM_VIRT(buf)) {
++ sdma_iram_free(buf);
++ return;
++ }
++#endif /* CONFIG_SDMA_IRAM */
++
++ dma_pool_free(pool, buf, sdma_virt_to_phys(buf));
++ delete_entry(buf);
++}
++EXPORT_SYMBOL(sdma_free);
++
++#ifdef CONFIG_SDMA_IRAM
++/*!
++ * Allocates uncacheable buffer from IRAM
++ */
++void *sdma_iram_malloc(size_t size)
++{
++ void *buf = NULL;
++ int index = -1;
++ unsigned long flags;
++
++ if (size > IRAM_UNIT_SIZE) {
++ printk(KERN_WARNING
++ "size in sdma_iram_malloc is more than %d bytes\n",
++ IRAM_UNIT_SIZE);
++ } else {
++ spin_lock_irqsave(&iram_pool_lock, flags);
++ if (!list_empty(&iram_free_list)) {
++ buf =
++ list_entry(iram_free_list.next, iram_head_t, list);
++ list_del(iram_free_list.next);
++ index = ((unsigned long)(buf - IRAM_VIRT_BASE)) /
++ IRAM_UNIT_SIZE;
++ if (index < 0 || index >= IRAM_POOL_SIZE) {
++ spin_unlock_irqrestore(&iram_pool_lock, flags);
++ printk(KERN_ERR "The iram pool has crashed\n");
++ return NULL;
++ }
++ if (iram_pool_flag[index]) {
++ spin_unlock_irqrestore(&iram_pool_lock, flags);
++ printk(KERN_WARNING
++ "iram block %d already has been allocated \n",
++ index);
++ }
++ iram_pool_flag[index] = 1;
++ }
++ spin_unlock_irqrestore(&iram_pool_lock, flags);
++ if ((unsigned long)buf & (IRAM_UNIT_SIZE - 1)) {
++ printk(KERN_WARNING
++ "the start address is not align of %d, buffer offset %ld\n",
++ IRAM_UNIT_SIZE, (unsigned long)buf);
++
++ buf = PTR_ALIGN(buf, IRAM_UNIT_SIZE);
++ }
++ }
++ return buf;
++}
++
++/*!
++ * Free uncacheable buffer into IRAM.
++ */
++static void sdma_iram_free(void *buf)
++{
++ iram_head_t *p;
++ int index;
++ unsigned long flags;
++
++ /* The check of parameter will be done in sdma_free */
++ index = ((unsigned long)(buf - IRAM_VIRT_BASE)) / IRAM_UNIT_SIZE;
++ spin_lock_irqsave(&iram_pool_lock, flags);
++ p = (iram_head_t *)((unsigned long)buf & ~(IRAM_UNIT_SIZE - 1));
++ list_add_tail(&(p->list), &iram_free_list);
++ if (iram_pool_flag[index]) {
++ iram_pool_flag[index] = 0;
++ } else {
++ printk(KERN_WARNING
++ "Free %p which IRAM block %d is already freed\n", buf,
++ index);
++ }
++ spin_unlock_irqrestore(&iram_pool_lock, flags);
++}
++
++/*!
++ * Initialized the free list of IRAM.
++ */
++static void iram_pool_init(void)
++{
++ int i;
++ iram_head_t *p;
++
++ memset(iram_pool_flag, 0, IRAM_POOL_SIZE);
++ INIT_LIST_HEAD(&iram_free_list);
++ for (i = 0; i < IRAM_POOL_SIZE; i++) {
++ p = (iram_head_t *)(IRAM_VIRT_BASE + i * IRAM_UNIT_SIZE);
++ list_add_tail(&(p->list), &iram_free_list);
++ }
++}
++#endif /* CONFIG_SDMA_IRAM */
++
++/*!
++ * SDMA buffers pool initialization function
++ */
++void __init init_sdma_pool(void)
++{
++#ifdef CONFIG_SDMA_IRAM
++ iram_pool_init();
++#endif /* CONFIG_SDMA_IRAM */
++
++ pool = dma_pool_create("SDMA", NULL, SDMA_POOL_SIZE, 0, 0);
++
++ INIT_LIST_HEAD(&buf_map);
++}
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC Linux SDMA API");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/arch/arm/plat-mxc/ssi.c linux.35.new/arch/arm/plat-mxc/ssi.c
+--- linux.35.old/arch/arm/plat-mxc/ssi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/arch/arm/plat-mxc/ssi.c 2010-12-03 09:51:55.420348302 +0100
+@@ -0,0 +1,228 @@
++/*
++ * Copyright (C) 2008 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * 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
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ */
++
++#include <linux/kernel.h>
++#include <linux/mutex.h>
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/ioport.h>
++#include <mach/hardware.h>
++
++#include <mach/dma.h>
++#include <mach/ssi_port.h>
++
++#ifdef DEBUG
++static int debug = 1;
++#define dbg_lvl(n) ((n) < debug)
++module_param(debug, int, S_IRUGO | S_IWUSR);
++#else
++#define dbg_lvl(n) 0
++static int debug;
++module_param(debug, int, 0);
++#endif
++
++#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++
++static DEFINE_MUTEX(mxc_ssi_lock);
++
++static struct resource mxc_ssi_resources[][4] = {
++ {
++ {
++ .start = SSI1_BASE_ADDR,
++ .end = SSI1_BASE_ADDR + 0xff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = MX25_INT_SSI1,
++ .end = MX25_INT_SSI1,
++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
++ },
++ {
++ .start = MXC_DMA_SSI1_16BIT_TX0,
++ .end = MXC_DMA_SSI1_16BIT_TX0,
++ .flags = IORESOURCE_DMA,
++ },
++ {
++ .start = MXC_DMA_SSI1_16BIT_RX0,
++ .end = MXC_DMA_SSI1_16BIT_RX0,
++ .flags = IORESOURCE_DMA,
++ },
++ },
++ {
++ {
++ .start = SSI2_BASE_ADDR,
++ .end = SSI2_BASE_ADDR + 0xff,
++ .flags = IORESOURCE_MEM,
++ },
++ {
++ .start = MX25_INT_SSI2,
++ .end = MX25_INT_SSI2,
++ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
++ },
++ {
++ .start = MXC_DMA_SSI2_16BIT_TX0,
++ .end = MXC_DMA_SSI2_16BIT_TX0,
++ .flags = IORESOURCE_DMA,
++ },
++ {
++ .start = MXC_DMA_SSI2_16BIT_RX0,
++ .end = MXC_DMA_SSI2_16BIT_RX0,
++ .flags = IORESOURCE_DMA,
++ },
++ },
++};
++#define NUM_SSI_PORTS ARRAY_SIZE(mxc_ssi_ports)
++
++static struct mxc_ssi_port mxc_ssi_ports[] = {
++ {
++ .num = 0,
++ .owner = THIS_MODULE,
++ .res = mxc_ssi_resources[0],
++ },
++ {
++ .num = 1,
++ .owner = THIS_MODULE,
++ .res = mxc_ssi_resources[1],
++ },
++};
++
++static int _mxc_ssi_init_port(int index, struct platform_device *parent,
++ struct mxc_ssi_port **ssi_port)
++{
++ int ret = -EBUSY;
++ struct mxc_ssi_port *port = &mxc_ssi_ports[index];
++ struct platform_device *pdev;
++ struct resource *res;
++
++ BUG_ON(index < 0 || index >= NUM_SSI_PORTS);
++
++ pdev = platform_device_register_simple("mxc-ssi", index,
++ port->res,
++ ARRAY_SIZE(mxc_ssi_resources[index]));
++ if (pdev == NULL) {
++ return -ENOMEM;
++ }
++ DBG(0, "%s: Added platform_device %s\n", __FUNCTION__, pdev->name);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ ret = -ENODEV;
++ goto pdev_free;
++ }
++
++ DBG(0, "%s: Requesting mem region %08lx..%08lx\n", __FUNCTION__,
++ (unsigned long)res->start, (unsigned long)res->end);
++ if (!request_mem_region(res->start, resource_size(res), parent->name)) {
++ ret = -EBUSY;
++ goto pdev_free;
++ }
++
++ port->ssi_clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(port->ssi_clk)) {
++ ret = PTR_ERR(port->ssi_clk);
++ dev_err(&pdev->dev, "Failed to get SSI clock: %d\n", ret);
++ goto pdev_free;
++ }
++ port->in_use = 1;
++ port->parent = pdev;
++ *ssi_port = port;
++ return 0;
++
++pdev_free:
++ DBG(0, "%s: Unregistering %s\n", __FUNCTION__, pdev->name);
++ platform_device_unregister(pdev);
++ return ret;
++}
++
++static inline void mxc_ssi_reserve_port(int index)
++{
++ mxc_ssi_ports[index].in_use++;
++ BUG_ON(mxc_ssi_ports[index].in_use != 1);
++}
++
++static inline void mxc_ssi_unreserve_port(int index)
++{
++ mxc_ssi_ports[index].in_use--;
++ BUG_ON(mxc_ssi_ports[index].in_use);
++}
++
++static inline int mxc_ssi_port_in_use(int index)
++{
++ return mxc_ssi_ports[index].in_use;
++}
++
++int mxc_ssi_request_port(int index, struct platform_device *parent,
++ struct mxc_ssi_port **ssi_port)
++{
++ int ret = -EBUSY;
++
++ if (index > 0 && index >= NUM_SSI_PORTS) {
++ dev_err(&parent->dev, "Bad SSI port index %d; valid range: 0..%d or <0 for any port\n",
++ index, NUM_SSI_PORTS - 1);
++ return -EINVAL;
++ }
++
++ if (ssi_port == NULL) {
++ dev_err(&parent->dev, "No pointer for return value\n");
++ return -EINVAL;
++ }
++
++ mutex_lock(&mxc_ssi_lock);
++ if (index >= 0 && !mxc_ssi_port_in_use(index)) {
++ ret = 0;
++ } else {
++ for (index = 0; index < NUM_SSI_PORTS; index++) {
++ if (!mxc_ssi_port_in_use(index)) {
++ ret = 0;
++ break;
++ }
++ }
++ }
++ if (ret != 0) {
++ dev_dbg(&parent->dev, "All SSI ports are in use\n");
++ goto unlock;
++ }
++ mxc_ssi_reserve_port(index);
++
++ ret = _mxc_ssi_init_port(index, parent, ssi_port);
++ if (ret)
++ goto err;
++
++ ret = index;
++ goto unlock;
++
++err:
++ mxc_ssi_unreserve_port(index);
++unlock:
++ mutex_unlock(&mxc_ssi_lock);
++ return ret;
++}
++EXPORT_SYMBOL(mxc_ssi_request_port);
++
++void mxc_ssi_release_port(struct mxc_ssi_port *ssi_port)
++{
++ if (ssi_port != NULL) {
++ WARN_ON(!ssi_port->in_use);
++ clk_put(ssi_port->ssi_clk);
++ ssi_port->in_use = 0;
++ platform_device_unregister(ssi_port->parent);
++ }
++}
++EXPORT_SYMBOL(mxc_ssi_release_port);
+diff -urN linux.35.old/drivers/input/touchscreen/ads7846.c linux.35.new/drivers/input/touchscreen/ads7846.c
+--- linux.35.old/drivers/input/touchscreen/ads7846.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/input/touchscreen/ads7846.c 2011-01-12 08:13:18.592488310 +0100
+@@ -604,6 +604,9 @@
+ if (ts->swap_xy)
+ swap(x, y);
+
++ if (1/*ts->mirror_x*/)
++ x = 4096 - x;
++
+ input_report_abs(input, ABS_X, x);
+ input_report_abs(input, ABS_Y, y);
+ input_report_abs(input, ABS_PRESSURE, ts->pressure_max - Rt);
+diff -urN linux.35.old/drivers/input/touchscreen/imx_adc_ts.c linux.35.new/drivers/input/touchscreen/imx_adc_ts.c
+--- linux.35.old/drivers/input/touchscreen/imx_adc_ts.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/input/touchscreen/imx_adc_ts.c 2010-12-03 09:51:55.420348302 +0100
+@@ -0,0 +1,162 @@
++/*
++ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file imx_adc_ts.c
++ *
++ * @brief Driver for the Freescale Semiconductor i.MX ADC touchscreen.
++ *
++ * This touchscreen driver is designed as a standard input driver. It is a
++ * wrapper around the low level ADC driver. Much of the hardware configuration
++ * and touchscreen functionality is implemented in the low level ADC driver.
++ * During initialization, this driver creates a kernel thread. This thread
++ * then calls the ADC driver to obtain touchscreen values continously. These
++ * values are then passed to the input susbsystem.
++ *
++ * @ingroup touchscreen
++ */
++
++#include <linux/kernel.h>
++#include <linux/kthread.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/input.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/freezer.h>
++#include <linux/imx_adc.h>
++
++#define IMX_ADC_TS_NAME "imx_adc_ts"
++
++static struct input_dev *imx_inputdev;
++static u32 input_ts_installed;
++
++static int cal[7] = {1,0,0,0,1,0,1};
++module_param_array(cal, int, NULL, 0);
++MODULE_PARM_DESC(cal, "Touchscreen calibration values as reported by \
++ts_calibrate");
++
++static int dim[4] = { 190, 3960, 60, 4000};
++module_param_array(dim, int, NULL, 0);
++MODULE_PARM_DESC(dim, "Maximum touchscreen range (x-left, x-right, y-top, \
++y-bottom)");
++
++static int axis_swap = 0;
++module_param(axis_swap, int, 0);
++MODULE_PARM_DESC(axis_swap, "Swap X and Y axis");
++
++static void imx_adc_ts_calibrate(struct input_dev *idev, u32 *pressure,
++u32 *x, u32 *y)
++{
++ int xtemp,ytemp;
++
++ if (!cal[6])
++ cal[6] = 1;
++
++ xtemp = *x; ytemp = *y;
++ *x = ( cal[2] +
++ cal[0]*xtemp +
++ cal[1]*ytemp ) / cal[6];
++ *y = ( cal[5] +
++ cal[3]*xtemp +
++ cal[4]*ytemp ) / cal[6];
++
++}
++
++
++static int ts_thread(void *arg)
++{
++ struct t_touch_screen ts_sample;
++ int wait = 0;
++ daemonize("imx_adc_ts");
++ while (input_ts_installed) {
++ try_to_freeze();
++
++ memset(&ts_sample, 0, sizeof(ts_sample));
++ if (0 != imx_adc_get_touch_sample(&ts_sample, !wait))
++ continue;
++
++ if (axis_swap)
++ swap(ts_sample.x_position, ts_sample.y_position);
++
++ if (!(dim[0] || dim[1] || dim[2] || dim[3]))
++ imx_adc_ts_calibrate(imx_inputdev, &ts_sample.contact_resistance, &ts_sample.x_position, &ts_sample.y_position);
++
++ input_report_abs(imx_inputdev, ABS_X, ts_sample.x_position);
++ input_report_abs(imx_inputdev, ABS_Y, ts_sample.y_position);
++ input_report_abs(imx_inputdev, ABS_PRESSURE,
++ ts_sample.contact_resistance);
++ input_sync(imx_inputdev);
++ wait = ts_sample.contact_resistance;
++ msleep(10);
++ }
++
++ return 0;
++}
++
++static int __init imx_adc_ts_init(void)
++{
++ int retval;
++
++ if (!is_imx_adc_ready())
++ return -ENODEV;
++
++ imx_inputdev = input_allocate_device();
++ if (!imx_inputdev) {
++ pr_err("imx_ts_init: not enough memory for input device\n");
++ return -ENOMEM;
++ }
++
++ imx_inputdev->name = IMX_ADC_TS_NAME;
++ imx_inputdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
++ imx_inputdev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
++ imx_inputdev->absbit[0] =
++ BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | BIT_MASK(ABS_PRESSURE);
++
++
++ if (axis_swap) {
++ swap(dim[0], dim[2]);
++ swap(dim[1], dim[3]);
++ }
++
++ input_set_abs_params(imx_inputdev, ABS_X, dim[0], dim[1], 0, 0);
++ input_set_abs_params(imx_inputdev, ABS_Y, dim[2], dim[3], 0, 0);
++
++ retval = input_register_device(imx_inputdev);
++ if (retval < 0) {
++ input_free_device(imx_inputdev);
++ return retval;
++ }
++
++ input_ts_installed = 1;
++ kthread_run(ts_thread, NULL, "ts_thread");
++ pr_info("i.MX ADC input touchscreen loaded.\n");
++ return 0;
++}
++
++static void __exit imx_adc_ts_exit(void)
++{
++ input_ts_installed = 0;
++ input_unregister_device(imx_inputdev);
++// if (imx_inputdev) { // input_free_device() must not be used after calling input_unregister_device()
++// input_free_device(imx_inputdev);
++ imx_inputdev = NULL;
++// }
++}
++
++late_initcall(imx_adc_ts_init);
++module_exit(imx_adc_ts_exit);
++
++MODULE_DESCRIPTION("i.MX ADC input touchscreen driver");
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/drivers/input/touchscreen/Kconfig linux.35.new/drivers/input/touchscreen/Kconfig
+--- linux.35.old/drivers/input/touchscreen/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/input/touchscreen/Kconfig 2010-12-03 09:51:55.420348302 +0100
+@@ -268,6 +268,18 @@
+ To compile this driver as a module, choose M here: the
+ module will be called jornada720_ts.
+
++config TOUCHSCREEN_IMX_ADC
++ tristate "Freescale i.MX ADC touchscreen input driver"
++ depends on IMX_ADC
++ help
++ Say Y here if you have a Freescale i.MX based board with a
++ touchscreen interfaced to the processor's integrated ADC.
++
++ If unsure, say N.
++
++ To compile this driver as a module, choose M here: the
++ module will be called imx_adc_ts.
++
+ config TOUCHSCREEN_HTCPEN
+ tristate "HTC Shift X9500 touchscreen"
+ depends on ISA
+@@ -339,6 +351,13 @@
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_tsadcc.
+
++config TOUCHSCREEN_MXC_TSC
++ tristate "i.MX25 Touchscreen Interface"
++ depends on ARCH_MX25
++ help
++ Say Y here if you have a 4-wire touchscreen connected to the
++ ADC Controller on your Freescale i.MX25 SoC.
++
+ config TOUCHSCREEN_UCB1400
+ tristate "Philips UCB1400 touchscreen"
+ depends on AC97_BUS
+diff -urN linux.35.old/drivers/input/touchscreen/Makefile linux.35.new/drivers/input/touchscreen/Makefile
+--- linux.35.old/drivers/input/touchscreen/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/input/touchscreen/Makefile 2010-12-03 09:51:55.420348302 +0100
+@@ -27,6 +27,8 @@
+ obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+ obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
++obj-$(CONFIG_TOUCHSCREEN_MXC_TSC) += mxc_tsc.o
++obj-$(CONFIG_TOUCHSCREEN_IMX_ADC) += imx_adc_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
+ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+diff -urN linux.35.old/drivers/input/touchscreen/mxc_tsc.c linux.35.new/drivers/input/touchscreen/mxc_tsc.c
+--- linux.35.old/drivers/input/touchscreen/mxc_tsc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/input/touchscreen/mxc_tsc.c 2010-12-03 09:51:55.424347282 +0100
+@@ -0,0 +1,1162 @@
++/*
++ * Freescale i.MX25 Touch Screen Driver
++ *
++ * Copyright (c) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * Based on atmel_tsadcc.c
++ * Copyright (c) 2008 ATMEL et. al.
++ * and code from Freescale BSP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#define DEBUG
++
++/* FIXME: pressure values, calculated according to the formula
++ * found in the i.MX25 Reference Manual, seem rather bogus
++ */
++#define REPORT_PRESSURE
++
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/input.h>
++#include <linux/timer.h>
++#include <linux/interrupt.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/io.h>
++#include <linux/slab.h>
++#include <mach/mxc_tsc.h>
++
++#include "mxc_tsc.h"
++
++#define TSC_NUM_SAMPLES 4 /* 1..16 */
++#define ADC_NUM_SAMPLES 16 /* 1..16 */
++
++/* Default settling times */
++#define SETTLE_PCHG 0 /* 0..255 */
++#define SETTLE_DET 16
++#define SETTLE_MEAS 32
++
++
++#if (TSC_NUM_SAMPLES <= 0) || (TSC_NUM_SAMPLES > 16)
++#error Invalid value for TSC_NUM_SAMPLES
++#endif
++
++#if (ADC_NUM_SAMPLES <= 0) || (ADC_NUM_SAMPLES > 16)
++#error Invalid value for ADC_NUM_SAMPLES
++#endif
++
++#ifdef DEBUG
++static int debug = 1;
++#define dbg_lvl(n) ((n) < debug)
++module_param(debug, int, S_IRUGO | S_IWUSR);
++
++#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++static int debug;
++#define dbg_lvl(n) 0
++module_param(debug, int, 0);
++
++#define DBG(lvl, fmt...) do { } while (0)
++#endif
++
++static unsigned int settle_detect;
++static unsigned int settle_measure;
++static unsigned int settle_precharge;
++module_param(settle_detect, int, S_IRUGO);
++module_param(settle_measure, int, S_IRUGO);
++module_param(settle_precharge, int, S_IRUGO);
++
++
++#define DEFAULT_ADC_CLOCK 1666667
++#define DEFAULT_RX_VALUE 360
++
++struct mxc_tsc_fifo_entry {
++ unsigned int id:4,
++ data:12;
++};
++
++/* The layout of this structure depends on the setup created by mxc_tsc_config() */
++struct mxc_tsc_ts_data {
++ struct mxc_tsc_fifo_entry pendown[TSC_NUM_SAMPLES];
++ struct mxc_tsc_fifo_entry pos_x[TSC_NUM_SAMPLES];
++ struct mxc_tsc_fifo_entry pos_y[TSC_NUM_SAMPLES];
++#ifdef REPORT_PRESSURE
++ struct mxc_tsc_fifo_entry yn[TSC_NUM_SAMPLES];
++ struct mxc_tsc_fifo_entry xp[TSC_NUM_SAMPLES];
++#endif
++ struct mxc_tsc_fifo_entry pendown2[TSC_NUM_SAMPLES];
++};
++
++struct mxc_tsc_adc_data {
++ struct mxc_tsc_fifo_entry data[ADC_NUM_SAMPLES];
++};
++
++typedef union {
++ unsigned int fifo[sizeof(struct mxc_tsc_adc_data) / sizeof(int)];
++ struct mxc_tsc_adc_data data;
++} mxc_tsc_adc_fifo;
++
++typedef union {
++ unsigned int fifo[sizeof(struct mxc_tsc_ts_data) / sizeof(int)];
++ struct mxc_tsc_ts_data data;
++ struct mxc_tsc_fifo_entry raw[sizeof(struct mxc_tsc_ts_data) / sizeof(int)];
++} mxc_tsc_ts_fifo;
++
++struct mxc_tsc_irqbuf {
++ wait_queue_head_t wq;
++ long timeout;
++ unsigned long reg_base;
++ unsigned int *data;
++ unsigned short reqcount;
++ unsigned short irqcount;
++ unsigned short chunk_size;
++};
++
++struct mxc_tsc {
++ struct input_dev *input;
++ char phys[32];
++ void __iomem *reg_base;
++ struct clk *clk;
++ int irq;
++ struct work_struct work;
++ struct timer_list timer;
++ spinlock_t irq_lock;
++ wait_queue_head_t wq;
++ unsigned int pendown:1,
++ clk_enabled:1,
++ attrs:1,
++ active:1;
++ struct mxc_tsc_irqbuf adc_buf;
++ struct mxc_tsc_irqbuf tsc_buf;
++ mxc_tsc_ts_fifo *tsc_data;
++ mxc_tsc_adc_fifo *adc_data;
++ struct mutex tsc_mutex;
++ struct mutex adc_mutex;
++
++ /* parameters from platform_data or module_param */
++ mxc_tsc_mode tsc_mode;
++ unsigned int r_xplate;
++ unsigned int settle_pchg;
++ unsigned int settle_meas;
++ unsigned int settle_det;
++
++ /* conversion clock rate in kHz */
++ unsigned long clkrate;
++ unsigned short pressure;
++ unsigned short prev_absx;
++ unsigned short prev_absy;
++};
++
++static inline u32 mxc_tsc_read(struct mxc_tsc *ts_dev, int reg)
++{
++ return __raw_readl(ts_dev->reg_base + reg);
++}
++
++static inline void mxc_tsc_write(struct mxc_tsc *ts_dev, int reg, u32 val)
++{
++ __raw_writel(val, ts_dev->reg_base + reg);
++}
++
++static inline void mxc_tsc_set_mask(struct mxc_tsc *ts_dev, int reg, u32 mask)
++{
++ u32 val = mxc_tsc_read(ts_dev, reg);
++ val |= mask;
++ mxc_tsc_write(ts_dev, reg, val);
++}
++
++static inline void mxc_tsc_clr_mask(struct mxc_tsc *ts_dev, int reg, u32 mask)
++{
++ u32 val = mxc_tsc_read(ts_dev, reg);
++ val &= ~mask;
++ mxc_tsc_write(ts_dev, reg, val);
++}
++
++static void tsc_clk_enable(struct mxc_tsc *ts_dev)
++{
++ if (!ts_dev->clk_enabled) {
++ clk_enable(ts_dev->clk);
++ mxc_tsc_set_mask(ts_dev, TGCR, TGCR_IPG_CLK_EN);
++ ts_dev->clk_enabled = 1;
++ }
++}
++
++static void tsc_clk_disable(struct mxc_tsc *ts_dev)
++{
++ if (ts_dev->clk_enabled) {
++ mxc_tsc_clr_mask(ts_dev, TGCR, TGCR_IPG_CLK_EN);
++ clk_disable(ts_dev->clk);
++ ts_dev->clk_enabled = 0;
++ }
++}
++
++static inline int mxc_tsc_pendown(struct mxc_tsc *ts_dev)
++{
++ return ts_dev->pendown;
++}
++
++static inline void mxc_tsc_read_fifo(struct mxc_tsc *ts_dev,
++ struct mxc_tsc_irqbuf *irqbuf)
++{
++ int start = irqbuf->irqcount;
++ int cqsr = mxc_tsc_read(ts_dev, irqbuf->reg_base + CQSR);
++ int num_items = irqbuf->chunk_size;
++ int i;
++
++ for (i = 0; i < num_items && !(cqsr & CQSR_EMPT); i++) {
++ u32 reg = mxc_tsc_read(ts_dev, irqbuf->reg_base + CQFIFO);
++
++ BUG_ON(irqbuf->irqcount < 0);
++ if (likely(irqbuf->irqcount < irqbuf->reqcount)) {
++ BUG_ON(irqbuf->data == NULL);
++ irqbuf->data[irqbuf->irqcount] = reg;
++ } else {
++ DBG(0, "%s: Dropping spurious data sample[%d/%d] on %s queue: %08x\n",
++ __FUNCTION__, irqbuf->irqcount,
++ irqbuf->reqcount,
++ irqbuf == &ts_dev->adc_buf ? "ADC" : "TSC",
++ reg);
++ }
++ irqbuf->irqcount++;
++ cqsr = mxc_tsc_read(ts_dev, irqbuf->reg_base + CQSR);
++ }
++
++ if (irqbuf->irqcount == irqbuf->reqcount) {
++ WARN_ON(!(mxc_tsc_read(ts_dev, irqbuf->reg_base + CQSR) &
++ CQSR_EMPT));
++ wake_up(&irqbuf->wq);
++ }
++ DBG(1, "%s: Read %u items [%d..%d] from fifo\n", __FUNCTION__,
++ irqbuf->irqcount - start, start, irqbuf->irqcount - 1);
++}
++
++static int mxc_tsc_wait_data(struct mxc_tsc *ts_dev,
++ struct mxc_tsc_irqbuf *irqbuf)
++{
++ int ret;
++
++ ret = wait_event_timeout(irqbuf->wq,
++ irqbuf->irqcount >= irqbuf->reqcount,
++ irqbuf->timeout);
++
++ if (ret == 0 && irqbuf->irqcount < irqbuf->reqcount) {
++ DBG(0, "%s: Timeout waiting for %s data: got %u of %u samples\n",
++ __FUNCTION__, irqbuf == &ts_dev->adc_buf ?
++ "ADC" : "TSC", irqbuf->irqcount, irqbuf->reqcount);
++
++ mxc_tsc_set_mask(ts_dev, irqbuf->reg_base + CQCR,
++ CQCR_FRST | CQCR_QRST);
++ mxc_tsc_clr_mask(ts_dev, irqbuf->reg_base + CQCR,
++ CQCR_FRST | CQCR_QRST);
++ return -ETIME;
++ }
++ return 0;
++}
++
++static int mxc_tsc_read_adc(struct mxc_tsc *ts_dev, int chan)
++{
++ int ret;
++ u32 reg;
++ int i;
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->adc_buf;
++ struct mxc_tsc_adc_data *adc_data = &ts_dev->adc_data->data;
++
++ mutex_lock(&ts_dev->adc_mutex);
++
++ memset(adc_data, 0, sizeof(*adc_data));
++ if (WARN_ON(irqbuf->irqcount)) {
++ irqbuf->irqcount = 0;
++ }
++ irqbuf->reqcount = ADC_NUM_SAMPLES;
++
++ reg = mxc_tsc_read(ts_dev, GCC0);
++ reg = (reg & ~CC_SELIN_MASK) | chan;
++ mxc_tsc_write(ts_dev, GCC0, reg);
++
++ /* enable data ready and end of conversion interrupt */
++ mxc_tsc_clr_mask(ts_dev, GCQMR,
++ CQMR_EOQ_IRQ_MSK |
++ CQMR_FDRY_IRQ_MSK |
++ CQMR_FOR_IRQ_MSK |
++ CQMR_FER_IRQ_MSK);
++ /* start conversion */
++ mxc_tsc_set_mask(ts_dev, GCQCR, CQCR_FQS);
++
++ ret = mxc_tsc_wait_data(ts_dev, irqbuf);
++ if (ret) {
++ goto exit;
++ }
++ irqbuf->irqcount = 0;
++
++ DBG(2, "%s: Read %u words from fifo\n", __FUNCTION__, irqbuf->reqcount);
++ for (i = 0; i < irqbuf->reqcount; i++) {
++ DBG(2, "%s: data[0x%x]=%4d\n", __FUNCTION__, i,
++ adc_data->data[i].data);
++ }
++exit:
++ mxc_tsc_set_mask(ts_dev, GCQMR, CQMR_EOQ_IRQ_MSK | CQMR_FDRY_IRQ_MSK);
++ mutex_unlock(&ts_dev->adc_mutex);
++
++ return ret;
++}
++
++static int mxc_tsc_data_valid(struct mxc_tsc_fifo_entry *data, int num_samples)
++{
++ int valid = 0;
++ int i;
++
++ for (i = 0; i < num_samples; i++) {
++ DBG(2, "%s: data[%d]=%d:%d\n", __FUNCTION__, i,
++ data[i].id, data[i].data);
++ valid |= data[i].data != 0;
++ }
++ return valid;
++}
++
++static int mxc_tsc_get_data(struct mxc_tsc_fifo_entry *data, int num_samples)
++{
++ int value = 0;
++ int count = 0;
++ int i;
++
++ for (i = 0; i < num_samples; i++) {
++ DBG(3, "%s: data[%d]=%d:%d\n", __FUNCTION__, i,
++ data[i].id, data[i].data);
++ if (data[i].data == 0) {
++ DBG(2, "%s: Skipping value %d\n", __FUNCTION__, i);
++ continue;
++ }
++ if (count == 0) {
++ value = data[i].data;
++ } else {
++ value = (value * count + data[i].data) / (count + 1);
++ }
++ count++;
++ }
++ data[0].data = value;
++ return value;
++}
++
++struct mxc_tsc_attr {
++ struct device_attribute attr;
++ unsigned int chan;
++};
++
++#define to_mxc_tsc_attr(a) container_of(a, struct mxc_tsc_attr, attr)
++
++#define MXC_TSC_DEV_ATTR(_name, _mode, _chan, _read) \
++ struct mxc_tsc_attr mxc_tsc_attr_##_name = { \
++ .attr = __ATTR(_name,_mode,_read, NULL), \
++ .chan = _chan, \
++ }
++
++static ssize_t mxc_tsc_attr_get(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ ssize_t ret;
++ struct mxc_tsc *ts_dev = dev_get_drvdata(dev);
++ struct mxc_tsc_attr *mxc_tsc_attr = to_mxc_tsc_attr(attr);
++ struct mxc_tsc_adc_data *adc_data = &ts_dev->adc_data->data;
++
++ ret = mxc_tsc_read_adc(ts_dev, mxc_tsc_attr->chan);
++ if (ret != 0) {
++ dev_err(dev, "%s: Failed to read ADC%d\n", __FUNCTION__,
++ ((mxc_tsc_attr->chan & CC_SELIN_MASK) >>
++ CC_SELIN_SHIFT) - 5);
++ return ret;
++ }
++ ret = sprintf(buf, "%d\n", mxc_tsc_get_data(adc_data->data,
++ ADC_NUM_SAMPLES));
++ return ret;
++}
++
++MXC_TSC_DEV_ATTR(inaux0, S_IRUGO, CC_SELIN_INAUX0, mxc_tsc_attr_get);
++MXC_TSC_DEV_ATTR(inaux1, S_IRUGO, CC_SELIN_INAUX1, mxc_tsc_attr_get);
++MXC_TSC_DEV_ATTR(inaux2, S_IRUGO, CC_SELIN_INAUX2, mxc_tsc_attr_get);
++
++static struct attribute *mxc_tsc_attrs[] = {
++ &mxc_tsc_attr_inaux0.attr.attr,
++ &mxc_tsc_attr_inaux1.attr.attr,
++ &mxc_tsc_attr_inaux2.attr.attr,
++ NULL
++};
++
++static const struct attribute_group mxc_tsc_attr_group = {
++ .attrs = mxc_tsc_attrs,
++};
++
++static void mxc_tsc_start_measure(struct mxc_tsc *ts_dev)
++{
++ u32 reg;
++ struct mxc_tsc_ts_data *tsc_data = &ts_dev->tsc_data->data;
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->tsc_buf;
++ mxc_tsc_ts_fifo *fifo_data = ts_dev->tsc_data;
++ unsigned long flags;
++
++ spin_lock_irqsave(&ts_dev->irq_lock, flags);
++ if (ts_dev->active) {
++ goto out;
++ }
++ ts_dev->active = 1;
++
++ memset(tsc_data, 0xee, sizeof(*tsc_data));
++ irqbuf->irqcount = 0;
++ irqbuf->reqcount = ARRAY_SIZE(fifo_data->fifo);
++
++ reg = mxc_tsc_read(ts_dev, TCQSR);
++ if (WARN_ON(!(reg & CQSR_EMPT))) {
++ DBG(0, "%s: Clearing TSC FIFO\n", __FUNCTION__);
++ mxc_tsc_set_mask(ts_dev, TCQCR, CQCR_FRST | CQCR_QRST);
++ mxc_tsc_clr_mask(ts_dev, TCQCR, CQCR_FRST | CQCR_QRST);
++ }
++ mxc_tsc_write(ts_dev, TCQSR, reg);
++
++ if (mxc_tsc_pendown(ts_dev)) {
++ /* change configuration for FQS mode */
++ reg = (0x1 << CC_YPLLSW_SHIFT) | (0x1 << CC_XNURSW_SHIFT) |
++ CC_XPULSW;
++ mxc_tsc_write(ts_dev, TICR, reg);
++
++ /* FQS */
++ reg = mxc_tsc_read(ts_dev, TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_FQS;
++ mxc_tsc_write(ts_dev, TCQCR, reg);
++ mxc_tsc_write(ts_dev, TCQCR, reg | CQCR_FQS);
++
++ /* enable end of conversion interrupt */
++ mxc_tsc_clr_mask(ts_dev, TCQMR, CQMR_EOQ_IRQ_MSK |
++ CQMR_FDRY_IRQ_MSK);
++ } else {
++ /* Config idle for 4-wire */
++ mxc_tsc_write(ts_dev, TICR, TSC_4WIRE_TOUCH_DETECT);
++
++ /* Pen interrupt starts new conversion queue */
++ reg = mxc_tsc_read(ts_dev, TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_PEN;
++ mxc_tsc_write(ts_dev, TCQCR, reg);
++
++ /* PDEN and PDBEN */
++ mxc_tsc_set_mask(ts_dev, TGCR, TGCR_PDB_EN | TGCR_PD_EN);
++
++ /* enable end of conversion interrupt */
++ mxc_tsc_clr_mask(ts_dev, TCQMR,
++ CQMR_EOQ_IRQ_MSK |
++ CQMR_FOR_IRQ_MSK |
++ CQMR_FER_IRQ_MSK |
++ CQMR_FDRY_IRQ_MSK);
++ }
++out:
++ spin_unlock_irqrestore(&ts_dev->irq_lock, flags);
++}
++
++#define LOCK_WORK
++static int mxc_tsc_read_ts(struct mxc_tsc *ts_dev, int force)
++{
++ int ret;
++ mxc_tsc_ts_fifo *fifo_data = ts_dev->tsc_data;
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->tsc_buf;
++ struct mxc_tsc_ts_data *tsc_data = &ts_dev->tsc_data->data;
++
++#ifndef LOCK_WORK
++ mutex_lock(&ts_dev->tsc_mutex);
++#endif
++ ret = mxc_tsc_wait_data(ts_dev, irqbuf);
++ if (ret) {
++ DBG(1, "%s: Failed to get data\n", __FUNCTION__);
++ goto exit;
++ }
++
++ for (ret = 0; ret < irqbuf->reqcount; ret++) {
++ struct mxc_tsc_fifo_entry *data = &fifo_data->raw[ret];
++ DBG(2, "%s: data[%02x]@%p=%d:%03x (%08x)\n", __FUNCTION__, ret,
++ data, data->id, data->data, fifo_data->fifo[ret]);
++ }
++
++ ret = tsc_data->pendown[0].data <= 0x600 &&
++ tsc_data->pendown2[0].data <= 0x600;
++ if (ret) {
++ int pos_x = mxc_tsc_get_data(tsc_data->pos_x, TSC_NUM_SAMPLES);
++ int pos_y = mxc_tsc_get_data(tsc_data->pos_y, TSC_NUM_SAMPLES);
++#ifdef REPORT_PRESSURE
++ int xp = mxc_tsc_get_data(tsc_data->xp, TSC_NUM_SAMPLES);
++ int yn = mxc_tsc_get_data(tsc_data->yn, TSC_NUM_SAMPLES);
++#endif
++
++ DBG(1, "%s: pos_x=%4d pos_y=%4d pd=%d\n",
++ __FUNCTION__, pos_x, pos_y, ts_dev->pendown);
++ if (pos_x) {
++#ifdef REPORT_PRESSURE
++ if (mxc_tsc_data_valid(tsc_data->xp, TSC_NUM_SAMPLES)) {
++ ts_dev->pressure = ts_dev->r_xplate *
++ pos_x * (yn - xp) / xp / 4096;
++ DBG(2, "%s: xp=%4d yn=%4d p=%d\n", __FUNCTION__,
++ xp, yn, ts_dev->pressure);
++ if (ts_dev->pressure > 4095) {
++ ts_dev->pressure = 4095;
++ }
++ } else {
++ DBG(0, "%s: Invalid pressure data\n",
++ __FUNCTION__);
++ ret = -EINVAL;
++ }
++#else
++ ts_dev->pressure = 4095;
++#endif
++ DBG(1, "%s: Detected PEN DOWN with pressure %4d\n",
++ __FUNCTION__, ts_dev->pressure);
++ } else {
++ DBG(0, "%s: Discarding measurement\n", __FUNCTION__);
++ ret = -EINVAL;
++ }
++ } else {
++ DBG(1, "%s: Detected PEN UP\n", __FUNCTION__);
++ ts_dev->pendown = 0;
++ }
++exit:
++ ts_dev->active = 0;
++#ifndef LOCK_WORK
++ mutex_unlock(&ts_dev->tsc_mutex);
++#endif
++ return ret;
++}
++
++static void mxc_tsc_work(struct work_struct *w)
++{
++ struct mxc_tsc *ts_dev = container_of(w, struct mxc_tsc, work);
++ struct input_dev *input_dev = ts_dev->input;
++ struct mxc_tsc_ts_data *tsc_data = &ts_dev->tsc_data->data;
++ int ret;
++#ifdef LOCK_WORK
++ mutex_lock(&ts_dev->tsc_mutex);
++#endif
++ ret = mxc_tsc_read_ts(ts_dev, 0);
++ DBG(1, "%s: mxc_tsc_read_ts() returned %d\n", __FUNCTION__, ret);
++ if (ret > 0) {
++ DBG(1, "%s: Got sample pd=%d\n", __FUNCTION__,
++ ts_dev->pendown);
++ if (mxc_tsc_pendown(ts_dev)) {
++ DBG(2, "%s: Reporting PD event %4d @ %4d,%4d\n",
++ __FUNCTION__, ts_dev->pressure,
++ tsc_data->pos_x[0].data,
++ tsc_data->pos_y[0].data);
++
++ input_report_abs(input_dev, ABS_X,
++ tsc_data->pos_x[0].data);
++ input_report_abs(input_dev, ABS_Y,
++ tsc_data->pos_y[0].data);
++#ifdef REPORT_PRESSURE
++ input_report_abs(input_dev, ABS_PRESSURE,
++ ts_dev->pressure);
++#endif
++ input_report_key(input_dev, BTN_TOUCH, 1);
++ input_sync(input_dev);
++
++ ts_dev->prev_absx = tsc_data->pos_x[0].data;
++ ts_dev->prev_absy = tsc_data->pos_y[0].data;
++
++ mod_timer(&ts_dev->timer, jiffies +
++ msecs_to_jiffies(5));
++#ifdef LOCK_WORK
++ goto out;
++#endif
++ return;
++ }
++ } else if (ret == 0) {
++ DBG(2, "%s: Reporting PU event: %4d,%4d\n", __FUNCTION__,
++ ts_dev->prev_absx, ts_dev->prev_absy);
++ input_report_abs(input_dev, ABS_X,
++ ts_dev->prev_absx);
++ input_report_abs(input_dev, ABS_Y,
++ ts_dev->prev_absy);
++#ifdef REPORT_PRESSURE
++ input_report_abs(input_dev, ABS_PRESSURE, 0);
++#endif
++ input_report_key(input_dev, BTN_TOUCH, 0);
++ input_sync(input_dev);
++ }
++ mxc_tsc_start_measure(ts_dev);
++#ifdef LOCK_WORK
++out:
++ mutex_unlock(&ts_dev->tsc_mutex);
++#endif
++}
++
++static void mxc_tsc_timer(unsigned long data)
++{
++ struct mxc_tsc *ts_dev = (void *)data;
++ struct mxc_tsc_ts_data *tsc_data = &ts_dev->tsc_data->data;
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->tsc_buf;
++
++ /* trigger a new conversion */
++ memset(tsc_data, 0xed, sizeof(*tsc_data));
++ irqbuf->irqcount = 0;
++
++ mxc_tsc_start_measure(ts_dev);
++}
++
++static irqreturn_t mxc_tsc_interrupt(int irq, void *dev)
++{
++ struct mxc_tsc *ts_dev = dev;
++ //struct input_dev *input_dev = ts_dev->input;
++ u32 reg;
++ u32 status = mxc_tsc_read(ts_dev, TGSR);
++
++ DBG(4, "%s: TGSR=%08x\n", __FUNCTION__, status);
++
++ if (status & TGSR_TCQ_INT) {
++ u32 mask = mxc_tsc_read(ts_dev, TCQMR);
++ u32 tcqsr;
++
++ reg = mxc_tsc_read(ts_dev, TCQSR);
++ tcqsr = reg;
++ DBG(3, "%s: TCQSR=%08x TCQMR=%08x:%08x\n", __FUNCTION__,
++ reg, mask, reg & ~mask);
++ reg &= ~mask;
++ mxc_tsc_write(ts_dev, TCQSR, reg);
++ if (reg & (CQSR_FOR | CQSR_FER)) {
++ DBG(-1, "%s: Fifo overrun on TSC queue\n",
++ __FUNCTION__);
++ mxc_tsc_set_mask(ts_dev, TCQCR, CQCR_FRST | CQCR_QRST);
++ mxc_tsc_clr_mask(ts_dev, TCQCR, CQCR_FRST | CQCR_QRST);
++ } else if (reg & CQSR_FDRY) {
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->tsc_buf;
++
++ mxc_tsc_clr_mask(ts_dev, TCQCR, CQCR_FQS);
++ if (!(reg & CQSR_EMPT)) {
++ mxc_tsc_read_fifo(ts_dev, irqbuf);
++ }
++ }
++ if (reg & CQSR_PD) {
++ ts_dev->pendown = 1;
++
++ /* disable pen down detect */
++ mxc_tsc_clr_mask(ts_dev, TGCR, TGCR_PD_EN);
++
++ /* schedule new measurement */
++ schedule_work(&ts_dev->work);
++ }
++ if (reg & CQSR_EOQ) {
++ mxc_tsc_clr_mask(ts_dev, TCQCR, CQCR_FQS);
++
++ /* disable end of conversion interrupt */
++ mxc_tsc_set_mask(ts_dev, TCQMR, CQMR_EOQ_IRQ_MSK);
++
++ DBG(1, "%s: Got EOQ interrupt TCQSR=%08x:%08x\n", __FUNCTION__,
++ tcqsr, mxc_tsc_read(ts_dev, TCQSR));
++ schedule_work(&ts_dev->work);
++ }
++ }
++ if (status & TGSR_GCQ_INT) {
++ u32 mask = mxc_tsc_read(ts_dev, GCQMR);
++
++ reg = mxc_tsc_read(ts_dev, GCQSR);
++ DBG(3, "%s: GCQSR=%08x GCQMR=%08x:%08x\n", __FUNCTION__,
++ reg, mask, reg & ~mask);
++ reg &= ~mask;
++ mxc_tsc_write(ts_dev, GCQSR, reg);
++ if (reg & (CQSR_FOR | CQSR_FER)) {
++ DBG(-1, "%s: Fifo overrun on ADC queue\n",
++ __FUNCTION__);
++ mxc_tsc_set_mask(ts_dev, GCQCR, CQCR_FRST | CQCR_QRST);
++ mxc_tsc_clr_mask(ts_dev, GCQCR, CQCR_FRST | CQCR_QRST);
++ } else if (reg & CQSR_FDRY) {
++ struct mxc_tsc_irqbuf *irqbuf = &ts_dev->adc_buf;
++
++ mxc_tsc_clr_mask(ts_dev, GCQCR, CQCR_FQS);
++ if (!(reg & CQSR_EMPT)) {
++ mxc_tsc_read_fifo(ts_dev, irqbuf);
++ }
++ }
++ if (reg & CQSR_EOQ) {
++ mxc_tsc_clr_mask(ts_dev, GCQCR, CQCR_FQS);
++
++ /* disable end of conversion interrupt */
++ mxc_tsc_set_mask(ts_dev, GCQMR, CQMR_EOQ_IRQ_MSK);
++ }
++ }
++ return IRQ_HANDLED;
++}
++
++static void mxc_tsc_4wire_config(struct mxc_tsc *ts_dev)
++{
++ u32 reg;
++ int lastitemid;
++
++ /* Configure 4-wire */
++ reg = TSC_4WIRE_PRECHARGE;
++ reg |= CC_IGS;
++ mxc_tsc_write(ts_dev, TCC0, reg);
++
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT;
++ reg |= ts_dev->settle_det << CC_SETTLING_TIME_SHIFT;
++ mxc_tsc_write(ts_dev, TCC1, reg);
++
++ reg = TSC_4WIRE_X_MEASURE;
++ reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT;
++ reg |= ts_dev->settle_meas << CC_SETTLING_TIME_SHIFT;
++ mxc_tsc_write(ts_dev, TCC2, reg);
++
++ reg = TSC_4WIRE_Y_MEASURE;
++ reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT;
++ reg |= ts_dev->settle_meas << CC_SETTLING_TIME_SHIFT;
++ mxc_tsc_write(ts_dev, TCC3, reg);
++
++ reg = TSC_4WIRE_YN_MEASURE;
++ reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT;
++ reg |= ts_dev->settle_meas << CC_SETTLING_TIME_SHIFT;
++ mxc_tsc_write(ts_dev, TCC4, reg);
++
++ reg = TSC_4WIRE_XP_MEASURE;
++ reg |= (TSC_NUM_SAMPLES - 1) << CC_NOS_SHIFT;
++ reg |= ts_dev->settle_meas << CC_SETTLING_TIME_SHIFT;
++ mxc_tsc_write(ts_dev, TCC5, reg);
++
++#ifdef REPORT_PRESSURE
++ reg = (TCQ_ITEM_TCC0 << CQ_ITEM0_SHIFT) |
++ (TCQ_ITEM_TCC1 << CQ_ITEM1_SHIFT) |
++ (TCQ_ITEM_TCC2 << CQ_ITEM2_SHIFT) |
++ (TCQ_ITEM_TCC3 << CQ_ITEM3_SHIFT) |
++ (TCQ_ITEM_TCC4 << CQ_ITEM4_SHIFT) |
++ (TCQ_ITEM_TCC5 << CQ_ITEM5_SHIFT) |
++ (TCQ_ITEM_TCC0 << CQ_ITEM6_SHIFT) |
++ (TCQ_ITEM_TCC1 << CQ_ITEM7_SHIFT);
++ lastitemid = 7;
++ ts_dev->tsc_buf.chunk_size = 6;
++
++ /* ADC conversion requires 14 clock cycles per sample
++ * plus the settling time programmed in the TICR registers.
++ * Add 1 extra jiffy to make sure the timeout is > 0
++ */
++ ts_dev->tsc_buf.timeout = msecs_to_jiffies(
++ ((6 * TSC_NUM_SAMPLES * 14) +
++ (2 * (ts_dev->settle_pchg * 8 + 1)) +
++ (5 * (ts_dev->settle_meas * 8 + 1)) +
++ (2 * (ts_dev->settle_det * 8 + 1))) /
++ ts_dev->clkrate) + 10;
++#else
++ reg = (TCQ_ITEM_TCC0 << CQ_ITEM0_SHIFT) |
++ (TCQ_ITEM_TCC1 << CQ_ITEM1_SHIFT) |
++ (TCQ_ITEM_TCC2 << CQ_ITEM2_SHIFT) |
++ (TCQ_ITEM_TCC3 << CQ_ITEM3_SHIFT) |
++ (TCQ_ITEM_TCC0 << CQ_ITEM4_SHIFT) |
++ (TCQ_ITEM_TCC1 << CQ_ITEM5_SHIFT);
++ lastitemid = 5;
++ ts_dev->tsc_buf.chunk_size = 4;
++
++ /* ADC conversion requires 14 clock cycles per sample
++ * plus the settling time programmed in the TICR registers.
++ * Add 1 extra jiffy to make sure the timeout is > 0
++ */
++ ts_dev->tsc_buf.timeout = msecs_to_jiffies(
++ ((5 * TSC_NUM_SAMPLES * 14) +
++ (2 * (ts_dev->settle_pchg * 8 + 1)) +
++ (4 * (ts_dev->settle_meas * 8 + 1)) +
++ (2 * (ts_dev->settle_det * 8 + 1))) /
++ ts_dev->clkrate + (1000 / HZ - 1)) + 1;
++#endif
++ DBG(0, "%s: TSC timeout set to %lu jiffies %lums (%u ADC clock cycles) clock: %lu\n",
++ __FUNCTION__, ts_dev->tsc_buf.timeout,
++ ((6 * TSC_NUM_SAMPLES * 14) +
++ (2 * (ts_dev->settle_pchg * 8 + 1)) +
++ (5 * (ts_dev->settle_meas * 8 + 1)) +
++ (2 * (ts_dev->settle_det * 8 + 1))) / ts_dev->clkrate + (1000 / HZ - 1),
++ (6 * TSC_NUM_SAMPLES * 14) +
++ (2 * (ts_dev->settle_pchg * 8 + 1)) +
++ (5 * (ts_dev->settle_meas * 8 + 1)) +
++ (2 * (ts_dev->settle_det * 8 + 1)), ts_dev->clkrate);
++ mxc_tsc_write(ts_dev, TCQ_ITEM_7_0, reg);
++
++ reg = mxc_tsc_read(ts_dev, TCQCR);
++ reg &= ~(CQCR_FIFOWATERMARK_MASK | CQCR_LAST_ITEM_ID_MASK);
++ reg |= (ts_dev->tsc_buf.chunk_size - 1) << CQCR_FIFOWATERMARK_SHIFT;
++ reg |= lastitemid << CQCR_LAST_ITEM_ID_SHIFT;
++ reg &= ~CQCR_PD_MSK;
++ mxc_tsc_write(ts_dev, TCQCR, reg);
++ DBG(0, "%s: TSC FIFO watermark set to %u\n", __FUNCTION__,
++ ((reg & CQCR_FIFOWATERMARK_MASK) >> CQCR_FIFOWATERMARK_SHIFT) + 1);
++
++ /* clear status bits */
++ reg = mxc_tsc_read(ts_dev, TCQSR);
++ mxc_tsc_write(ts_dev, TCQSR, reg);
++
++ mxc_tsc_clr_mask(ts_dev, TCQMR,
++ CQMR_PD_IRQ_MSK |
++ CQMR_EOQ_IRQ_MSK |
++ CQMR_FDRY_IRQ_MSK |
++ CQMR_FOR_IRQ_MSK |
++ CQMR_FER_IRQ_MSK);
++
++ /* Config idle for 4-wire */
++ mxc_tsc_write(ts_dev, TICR, TSC_4WIRE_TOUCH_DETECT);
++}
++
++static void mxc_tsc_adc_config(struct mxc_tsc *ts_dev)
++{
++ u32 reg;
++
++ ts_dev->adc_buf.chunk_size = ADC_NUM_SAMPLES % 32;
++ reg = ((ts_dev->adc_buf.chunk_size - 1) << CQCR_FIFOWATERMARK_SHIFT) |
++ (0 << CQCR_LAST_ITEM_ID_SHIFT) |
++ CQCR_QSM_FQS;
++ mxc_tsc_write(ts_dev, GCQCR, reg);
++ DBG(0, "%s: ADC FIFO watermark set to %u\n", __FUNCTION__,
++ ((reg & CQCR_FIFOWATERMARK_MASK) >> CQCR_FIFOWATERMARK_SHIFT) + 1);
++
++ reg = ((ADC_NUM_SAMPLES - 1) << CC_NOS_SHIFT) |
++ (ts_dev->settle_meas << CC_SETTLING_TIME_SHIFT) |
++ CC_YPLLSW_OFF | CC_XNURSW_OFF | CC_XPULSW |
++ CC_SEL_REFP_INT | CC_SEL_REFN_AGND;
++ mxc_tsc_write(ts_dev, GCC0, reg);
++
++ /* ADC conversion requires 14 clock cycles per sample
++ * plus the settling time programmed in the TICR registers.
++ * Add 1 extra jiffy to make sure the timeout is > 0
++ */
++ ts_dev->adc_buf.timeout = msecs_to_jiffies(
++ ((ADC_NUM_SAMPLES * 14) +
++ (ts_dev->settle_meas * 8 + 1)) /
++ ts_dev->clkrate) + 1;
++ DBG(0, "%s: ADC timeout set to %lu jiffies\n", __FUNCTION__,
++ ts_dev->adc_buf.timeout);
++}
++
++static void mxc_tsc_config(struct platform_device *pdev)
++{
++ struct mxc_tsc *ts_dev = platform_get_drvdata(pdev);
++ struct mxc_tsc_pdata *pdata = pdev->dev.platform_data;
++ unsigned int tgcr;
++ unsigned int pdbt = TGCR_PDBTIME128;
++ unsigned int pdben = 1;
++ unsigned int intref = 1;
++ unsigned int adc_clk = DEFAULT_ADC_CLOCK;
++ unsigned long ipg_clk;
++ unsigned int clkdiv;
++ unsigned int hsync_en = 0;
++ unsigned int hsync_pol = 0;
++
++ /* setup default settling times */
++ ts_dev->settle_det = SETTLE_DET;
++ ts_dev->settle_meas = SETTLE_MEAS;
++ ts_dev->settle_pchg = SETTLE_PCHG;
++
++ if (pdata) {
++ pdbt = pdata->pen_debounce_time - 1;
++ if (pdbt > 31) {
++ dev_dbg(&pdev->dev, "Pen debounce time %d out of range[0..32]; using max. value\n",
++ pdata->pen_debounce_time);
++ }
++ pdben = pdata->pen_debounce_time > 0;
++ intref = pdata->intref;
++ if (pdata->adc_clk > 0) {
++ adc_clk = pdata->adc_clk;
++ }
++ ts_dev->r_xplate = pdata->r_xplate;
++ hsync_en = pdata->hsyncen;
++ hsync_pol = pdata->hsyncpol;
++ if (pdata->settle_detect > 0 &&
++ pdata->settle_detect < 256)
++ ts_dev->settle_det = pdata->settle_detect;
++ if (pdata->settle_measure > 0 &&
++ pdata->settle_measure < 256)
++ ts_dev->settle_meas = pdata->settle_measure;
++ if (pdata->settle_precharge > 0 &&
++ pdata->settle_precharge < 256)
++ ts_dev->settle_pchg = pdata->settle_precharge;
++ DBG(0, "%s: pdbt=%d intref=%d r_xplate=%d hsync_en=%d hsync_pol=%d\n",
++ __FUNCTION__, pdbt + 1, intref, ts_dev->r_xplate,
++ hsync_en, hsync_pol);
++ } else {
++ dev_dbg(&pdev->dev, "No platform_data; using defaults\n");
++ }
++ if (settle_detect > 0 && settle_detect < 256)
++ ts_dev->settle_det = settle_detect;
++ if (settle_measure > 0 && settle_measure < 256)
++ ts_dev->settle_meas = settle_measure;
++ if (settle_precharge > 0 && settle_precharge < 256)
++ ts_dev->settle_pchg = settle_precharge;
++
++
++ if (ts_dev->r_xplate == 0) {
++ ts_dev->r_xplate = DEFAULT_RX_VALUE;
++ DBG(0, "%s: Assuming default Rx value of %u Ohms\n",
++ __FUNCTION__, ts_dev->r_xplate);
++ }
++ ipg_clk = clk_get_rate(ts_dev->clk);
++ dev_info(&pdev->dev, "Master clock is: %lu.%06luMHz requested ADC clock: %u.%06uMHz\n",
++ ipg_clk / 1000000, ipg_clk % 1000000,
++ adc_clk / 1000000, adc_clk % 1000000);
++ /*
++ * adc_clk = ipg_clk / (2 * clkdiv + 2)
++ * The exact formula for the clock divider would be:
++ * clkdiv = ipg_clk / (2 * adc_clk) - 1
++ * but we drop the '- 1' due to integer truncation
++ * and to make sure the actual clock is always less or equal
++ * to the designated clock.
++ */
++ clkdiv = ipg_clk / (2 * adc_clk + 1);
++ if (clkdiv > 31) {
++ clkdiv = 31;
++ dev_warn(&pdev->dev,
++ "cannot accomodate designated clock of %u.%06uMHz; using %lu.%06luMHz\n",
++ adc_clk / 1000000, adc_clk % 1000000,
++ ipg_clk / (2 * clkdiv + 2) / 1000000,
++ ipg_clk / (2 * clkdiv + 2) % 1000000);
++ }
++ /* calculate the actual ADC clock rate in kHz */
++ if (clkdiv < 4)
++ ts_dev->clkrate = ipg_clk / 10000;
++ else
++ ts_dev->clkrate = ipg_clk / (2 * clkdiv + 2) / 1000;
++ dev_dbg(&pdev->dev, "clkdiv=%u actual ADC clock: %lukHz\n",
++ clkdiv, ts_dev->clkrate);
++
++ tgcr = ((pdbt << TGCR_PDBTIME_SHIFT) & TGCR_PDBTIME_MASK) | /* pen debounce time */
++ (pdben * TGCR_PDB_EN) | /* pen debounce enable */
++ (intref * TGCR_INTREFEN) | /* pen debounce enable */
++ (hsync_en * TGCR_HSYNC_EN) | /* sync conversion with hsync */
++ (hsync_pol * TGCR_HSYNC_POL) | /* HSYNC polarity */
++ TGCR_POWER_SAVE | /* Switch TSC on */
++ TGCR_PD_EN | /* Enable Pen Detect */
++ ((clkdiv << TGCR_ADCCLKCFG_SHIFT) & TGCR_ADCCLKCFG_MASK);
++
++ /* reset TSC */
++ mxc_tsc_write(ts_dev, TGCR, TGCR_TSC_RST);
++ while (mxc_tsc_read(ts_dev, TGCR) & TGCR_TSC_RST) {
++ cpu_relax();
++ }
++ mxc_tsc_write(ts_dev, TGCR, tgcr);
++
++ tsc_clk_enable(ts_dev);
++ mxc_tsc_4wire_config(ts_dev);
++ mxc_tsc_adc_config(ts_dev);
++
++ mxc_tsc_start_measure(ts_dev);
++}
++
++static int __devinit mxc_tsc_probe(struct platform_device *pdev)
++{
++ int err;
++ struct mxc_tsc *ts_dev;
++ struct input_dev *input_dev;
++ struct resource *res;
++ int irq;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(&pdev->dev, "No mmio resource defined\n");
++ return -ENODEV;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "No IRQ assigned\n");
++ return -ENODEV;
++ }
++
++ if (!request_mem_region(res->start, resource_size(res),
++ "mxc tsc regs")) {
++ return -EBUSY;
++ }
++
++ /* Allocate memory for device */
++ ts_dev = kzalloc(sizeof(struct mxc_tsc), GFP_KERNEL);
++ if (!ts_dev) {
++ dev_err(&pdev->dev, "Failed to allocate memory\n");
++ err = -ENOMEM;
++ goto err_release_mem;
++ }
++
++ /* allocate conversion buffers separately to prevent
++ * cacheline alignment issues if using DMA */
++ ts_dev->tsc_data = kzalloc(sizeof(mxc_tsc_ts_fifo), GFP_KERNEL);
++ ts_dev->adc_data = kzalloc(sizeof(mxc_tsc_adc_fifo), GFP_KERNEL);
++ if (ts_dev->tsc_data == NULL || ts_dev->adc_data == NULL) {
++ err = -ENOMEM;
++ goto err_free_mem;
++ }
++ ts_dev->irq = irq;
++ INIT_WORK(&ts_dev->work, mxc_tsc_work);
++ mutex_init(&ts_dev->tsc_mutex);
++ mutex_init(&ts_dev->adc_mutex);
++ spin_lock_init(&ts_dev->irq_lock);
++ setup_timer(&ts_dev->timer, mxc_tsc_timer, (unsigned long)ts_dev);
++ init_waitqueue_head(&ts_dev->wq);
++ init_waitqueue_head(&ts_dev->tsc_buf.wq);
++ init_waitqueue_head(&ts_dev->adc_buf.wq);
++
++ ts_dev->tsc_buf.reg_base = TCQ_REG_BASE;
++ ts_dev->adc_buf.reg_base = GCQ_REG_BASE;
++ ts_dev->tsc_buf.data = ts_dev->tsc_data->fifo;
++ ts_dev->adc_buf.data = ts_dev->adc_data->fifo;
++
++ platform_set_drvdata(pdev, ts_dev);
++
++ input_dev = input_allocate_device();
++ if (!input_dev) {
++ dev_err(&pdev->dev, "Failed to allocate input device\n");
++ err = -ENOMEM;
++ goto err_free_mem;
++ }
++
++ ts_dev->reg_base = ioremap(res->start, resource_size(res));
++ if (!ts_dev->reg_base) {
++ dev_err(&pdev->dev, "Failed to map registers\n");
++ err = -ENOMEM;
++ goto err_free_dev;
++ }
++
++ err = request_irq(ts_dev->irq, mxc_tsc_interrupt, 0,
++ pdev->dev.driver->name, ts_dev);
++ if (err) {
++ dev_err(&pdev->dev, "Failed to install irq handler: %d\n", err);
++ goto err_unmap_regs;
++ }
++
++ ts_dev->clk = clk_get(&pdev->dev, "tsc_clk");
++ if (IS_ERR(ts_dev->clk)) {
++ dev_err(&pdev->dev, "Failed to get tsc_clk\n");
++ err = PTR_ERR(ts_dev->clk);
++ goto err_free_irq;
++ }
++
++ ts_dev->input = input_dev;
++
++ snprintf(ts_dev->phys, sizeof(ts_dev->phys),
++ "%s/input0", dev_name(&pdev->dev));
++
++ input_dev->name = "mxc touch screen controller";
++ input_dev->phys = ts_dev->phys;
++ input_dev->dev.parent = &pdev->dev;
++
++ __set_bit(EV_KEY, input_dev->evbit);
++ __set_bit(EV_ABS, input_dev->evbit);
++ __set_bit(BTN_TOUCH, input_dev->keybit);
++ __set_bit(ABS_X, input_dev->absbit);
++ __set_bit(ABS_Y, input_dev->absbit);
++ input_set_abs_params(input_dev, ABS_X, 0, 0xFFF, 0, 0);
++ input_set_abs_params(input_dev, ABS_Y, 0, 0xFFF, 0, 0);
++#ifdef REPORT_PRESSURE
++ __set_bit(ABS_PRESSURE, input_dev->absbit);
++ input_set_abs_params(input_dev, ABS_PRESSURE, 0, 0xFFF, 0, 0);
++#endif
++ mxc_tsc_config(pdev);
++
++ /* All went ok, so register to the input system */
++ err = input_register_device(input_dev);
++ if (err)
++ goto err_fail;
++
++ err = sysfs_create_group(&pdev->dev.kobj, &mxc_tsc_attr_group);
++ if (err) {
++ dev_warn(&pdev->dev, "Failed to create sysfs attributes: %d\n",
++ err);
++ }
++ ts_dev->attrs = !err;
++
++ return 0;
++
++err_fail:
++ clk_disable(ts_dev->clk);
++ clk_put(ts_dev->clk);
++err_free_irq:
++ free_irq(ts_dev->irq, ts_dev);
++err_unmap_regs:
++ iounmap(ts_dev->reg_base);
++err_free_dev:
++ input_free_device(ts_dev->input);
++err_free_mem:
++ kfree(ts_dev->tsc_data);
++ kfree(ts_dev->adc_data);
++ kfree(ts_dev);
++err_release_mem:
++ release_mem_region(res->start, resource_size(res));
++ return err;
++}
++
++static int __devexit mxc_tsc_remove(struct platform_device *pdev)
++{
++ struct mxc_tsc *ts_dev = platform_get_drvdata(pdev);
++ struct resource *res;
++
++ if (ts_dev->attrs) {
++ DBG(0, "%s: Removing sysfs attributes\n", __FUNCTION__);
++ sysfs_remove_group(&pdev->dev.kobj, &mxc_tsc_attr_group);
++ }
++ del_timer_sync(&ts_dev->timer);
++ input_unregister_device(ts_dev->input);
++
++ clk_disable(ts_dev->clk);
++ clk_put(ts_dev->clk);
++
++ free_irq(ts_dev->irq, ts_dev);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ iounmap(ts_dev->reg_base);
++ release_mem_region(res->start, resource_size(res));
++
++ kfree(ts_dev->tsc_data);
++ kfree(ts_dev->adc_data);
++ kfree(ts_dev);
++ return 0;
++}
++
++#ifdef CONFIG_SUSPEND
++static int mxc_tsc_suspend(struct device *dev)
++{
++ struct mxc_tsc *ts_dev = dev_get_drvdata(dev);
++
++ if (ts_dev->clk_enabled) {
++ tsc_clk_disable(ts_dev);
++ ts_dev->clk_enabled = 1;
++ }
++ return 0;
++}
++
++static int mxc_tsc_resume(struct device *dev)
++{
++ struct mxc_tsc *ts_dev = dev_get_drvdata(dev);
++
++ if (ts_dev->clk_enabled) {
++ ts_dev->clk_enabled = 0;
++ tsc_clk_enable(ts_dev);
++ }
++ return 0;
++}
++
++static struct dev_pm_ops mxc_tsc_pm_ops = {
++ .suspend = mxc_tsc_suspend,
++ .resume = mxc_tsc_resume,
++};
++#endif
++
++static struct platform_driver mxc_tsc_driver = {
++ .driver = {
++ .name = "imx-tsc",
++// .pm = __dev_pm_ops_p(mxc_tsc_pm_ops),
++ },
++ .probe = mxc_tsc_probe,
++ .remove = __devexit_p(mxc_tsc_remove),
++};
++
++static int __init mxc_tsc_init(void)
++{
++ return platform_driver_register(&mxc_tsc_driver);
++}
++
++static void __exit mxc_tsc_exit(void)
++{
++ platform_driver_unregister(&mxc_tsc_driver);
++}
++
++module_init(mxc_tsc_init);
++module_exit(mxc_tsc_exit);
++
++
++MODULE_LICENSE("GPL");
++MODULE_DESCRIPTION("i.MX25 TouchScreen Driver");
++MODULE_AUTHOR("Lothar Wassmann <LW@KARO-electronics.de>");
++MODULE_ALIAS("platform:imx-tsc");
+diff -urN linux.35.old/drivers/input/touchscreen/mxc_tsc.h linux.35.new/drivers/input/touchscreen/mxc_tsc.h
+--- linux.35.old/drivers/input/touchscreen/mxc_tsc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/input/touchscreen/mxc_tsc.h 2010-12-03 09:51:55.428348260 +0100
+@@ -0,0 +1,327 @@
++/*
++ * Freescale i.MX25 Touch Screen Driver
++ *
++ * Copyright (c) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * Based on code from Freescale BSP
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++/* TSC General Config Register */
++#define TGCR 0x000
++#define TGCR_IPG_CLK_EN (1 << 0)
++#define TGCR_TSC_RST (1 << 1)
++#define TGCR_FUNC_RST (1 << 2)
++#define TGCR_SLPC (1 << 4)
++#define TGCR_STLC (1 << 5)
++#define TGCR_HSYNC_EN (1 << 6)
++#define TGCR_HSYNC_POL (1 << 7)
++#define TGCR_POWERMODE_SHIFT 8
++#define TGCR_POWER_OFF (0x0 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_SAVE (0x1 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_ON (0x3 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_MASK (0x3 << TGCR_POWERMODE_SHIFT)
++#define TGCR_INTREFEN (1 << 10)
++#define TGCR_ADCCLKCFG_SHIFT 16
++#define TGCR_ADCCLKCFG_MASK (0x1f << TGCR_ADCCLKCFG_SHIFT)
++#define TGCR_PD_EN (1 << 23)
++#define TGCR_PDB_EN (1 << 24)
++#define TGCR_PDBTIME_SHIFT 25
++#define TGCR_PDBTIME128 (0x3f << TGCR_PDBTIME_SHIFT)
++#define TGCR_PDBTIME_MASK (0x7f << TGCR_PDBTIME_SHIFT)
++
++/* TSC General Status Register */
++#define TGSR 0x004
++#define TGSR_TCQ_INT (1 << 0)
++#define TGSR_GCQ_INT (1 << 1)
++#define TGSR_SLP_INT (1 << 2)
++#define TGSR_TCQ_DMA (1 << 16)
++#define TGSR_GCQ_DMA (1 << 17)
++
++/* TSC IDLE Config Register */
++#define TICR 0x008
++
++/* queue dependent register offsets wrt *_REG_BASE */
++#define CQFIFO 0x00
++#define CQCR 0x04
++#define CQSR 0x08
++#define CQMR 0x0c
++#define CQ_ITEM_7_0 0x20
++#define CQ_ITEM_15_8 0x24
++
++/* TouchScreen Convert Queue FIFO Register */
++#define TCQ_REG_BASE 0x400
++#define TCQFIFO (TCQ_REG_BASE + CQFIFO)
++/* TouchScreen Convert Queue Control Register */
++#define TCQCR (TCQ_REG_BASE + CQCR)
++#define CQCR_QSM_SHIFT 0
++#define CQCR_QSM_STOP (0x0 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_PEN (0x1 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_FQS (0x2 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_FQS_PEN (0x3 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_MASK (0x3 << CQCR_QSM_SHIFT)
++#define CQCR_FQS (1 << 2)
++#define CQCR_RPT (1 << 3)
++#define CQCR_LAST_ITEM_ID_SHIFT 4
++#define CQCR_LAST_ITEM_ID_MASK (0xf << CQCR_LAST_ITEM_ID_SHIFT)
++#define CQCR_FIFOWATERMARK_SHIFT 8
++#define CQCR_FIFOWATERMARK_MASK (0xf << CQCR_FIFOWATERMARK_SHIFT)
++#define CQCR_REPEATWAIT_SHIFT 12
++#define CQCR_REPEATWAIT_MASK (0xf << CQCR_REPEATWAIT_SHIFT)
++#define CQCR_QRST (1 << 16)
++#define CQCR_FRST (1 << 17)
++#define CQCR_PD_MSK (1 << 18)
++#define CQCR_PD_CFG (1 << 19)
++
++/* TouchScreen Convert Queue Status Register */
++#define TCQSR (TCQ_REG_BASE + CQSR)
++#define CQSR_PD (1 << 0)
++#define CQSR_EOQ (1 << 1)
++#define CQSR_FOR (1 << 4)
++#define CQSR_FUR (1 << 5)
++#define CQSR_FER (1 << 6)
++#define CQSR_EMPT (1 << 13)
++#define CQSR_FULL (1 << 14)
++#define CQSR_FDRY (1 << 15)
++
++/* TouchScreen Convert Queue Mask Register */
++#define TCQMR (TCQ_REG_BASE + CQMR)
++#define CQMR_PD_IRQ_MSK (1 << 0)
++#define CQMR_EOQ_IRQ_MSK (1 << 1)
++#define CQMR_FOR_IRQ_MSK (1 << 4)
++#define CQMR_FUR_IRQ_MSK (1 << 5)
++#define CQMR_FER_IRQ_MSK (1 << 6)
++#define CQMR_FDRY_IRQ_MSK (1 << 15)
++#define CQMR_PD_DMA_MSK (1 << 16)
++#define CQMR_EOQ_DMA_MSK (1 << 17)
++#define CQMR_FOR_DMA_MSK (1 << 20)
++#define CQMR_FUR_DMA_MSK (1 << 21)
++#define CQMR_FER_DMA_MSK (1 << 22)
++#define CQMR_FDRY_DMA_MSK (1 << 31)
++
++/* TouchScreen Convert Queue ITEM 7~0 */
++#define TCQ_ITEM_7_0 (TCQ_REG_BASE + CQ_ITEM_7_0)
++
++/* TouchScreen Convert Queue ITEM 15~8 */
++#define TCQ_ITEM_15_8 (TCQ_REG_BASE + CQ_ITEM_15_8)
++
++#define TCQ_ITEM_TCC0 0x0
++#define TCQ_ITEM_TCC1 0x1
++#define TCQ_ITEM_TCC2 0x2
++#define TCQ_ITEM_TCC3 0x3
++#define TCQ_ITEM_TCC4 0x4
++#define TCQ_ITEM_TCC5 0x5
++#define TCQ_ITEM_TCC6 0x6
++#define TCQ_ITEM_TCC7 0x7
++#define TCQ_ITEM_GCC7 0x8
++#define TCQ_ITEM_GCC6 0x9
++#define TCQ_ITEM_GCC5 0xa
++#define TCQ_ITEM_GCC4 0xb
++#define TCQ_ITEM_GCC3 0xc
++#define TCQ_ITEM_GCC2 0xd
++#define TCQ_ITEM_GCC1 0xe
++#define TCQ_ITEM_GCC0 0xf
++
++/* TouchScreen Convert Config 0-7 */
++#define TCC0 (TCQ_REG_BASE + 0x40)
++#define TCC1 (TCQ_REG_BASE + 0x44)
++#define TCC2 (TCQ_REG_BASE + 0x48)
++#define TCC3 (TCQ_REG_BASE + 0x4c)
++#define TCC4 (TCQ_REG_BASE + 0x50)
++#define TCC5 (TCQ_REG_BASE + 0x54)
++#define TCC6 (TCQ_REG_BASE + 0x58)
++#define TCC7 (TCQ_REG_BASE + 0x5c)
++#define CC_PEN_IACK (1 << 1)
++#define CC_SEL_REFN_SHIFT 2
++#define CC_SEL_REFN_XNUR (0x0 << CC_SEL_REFN_SHIFT)
++#define CC_SEL_REFN_YNLR (0x1 << CC_SEL_REFN_SHIFT)
++#define CC_SEL_REFN_AGND (0x3 << CC_SEL_REFN_SHIFT)
++#define CC_SEL_REFN_MASK (0x3 << CC_SEL_REFN_SHIFT)
++#define CC_SELIN_SHIFT 4
++#define CC_SELIN_XPUL (0x0 << CC_SELIN_SHIFT)
++#define CC_SELIN_YPLL (0x1 << CC_SELIN_SHIFT)
++#define CC_SELIN_XNUR (0x2 << CC_SELIN_SHIFT)
++#define CC_SELIN_YNLR (0x3 << CC_SELIN_SHIFT)
++#define CC_SELIN_WIPER (0x4 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX0 (0x5 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX1 (0x6 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX2 (0x7 << CC_SELIN_SHIFT)
++#define CC_SELIN_MASK (0x7 << CC_SELIN_SHIFT)
++#define CC_SEL_REFP_SHIFT 7
++#define CC_SEL_REFP_YPLL (0x0 << CC_SEL_REFP_SHIFT)
++#define CC_SEL_REFP_XPUL (0x1 << CC_SEL_REFP_SHIFT)
++#define CC_SEL_REFP_EXT (0x2 << CC_SEL_REFP_SHIFT)
++#define CC_SEL_REFP_INT (0x3 << CC_SEL_REFP_SHIFT)
++#define CC_SEL_REFP_MASK (0x3 << CC_SEL_REFP_SHIFT)
++#define CC_XPULSW (1 << 9)
++#define CC_XNURSW_SHIFT 10
++#define CC_XNURSW_HIGH (0x0 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_OFF (0x1 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_LOW (0x3 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_MASK (0x3 << CC_XNURSW_SHIFT)
++#define CC_YPLLSW_SHIFT 12
++#define CC_YPLLSW_HIGH (0x0 << CC_YPLLSW_SHIFT)
++#define CC_YPLLSW_OFF (0x1 << CC_YPLLSW_SHIFT)
++#define CC_YPLLSW_LOW (0x3 << CC_YPLLSW_SHIFT)
++#define CC_YPLLSW_MASK (0x3 << CC_YPLLSW_SHIFT)
++#define CC_YNLRSW (1 << 14)
++#define CC_WIPERSW (1 << 15)
++#define CC_NOS_SHIFT 16
++#define CC_NOS_MASK (0xf << CC_NOS_SHIFT)
++#define CC_IGS (1 << 20)
++#define CC_SETTLING_TIME_SHIFT 24
++#define CC_SETTLING_TIME_MASK (0xff << CC_SETTLING_TIME_SHIFT)
++
++#define TSC_4WIRE_PRECHARGE ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_XPUL | \
++ CC_SEL_REFP_INT | \
++ CC_XNURSW_OFF | \
++ CC_YPLLSW_OFF | \
++ 0) \
++/*0x158c*/
++#define TSC_4WIRE_TOUCH_DETECT ( \
++ CC_PEN_IACK | \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_XPUL | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_XNURSW_OFF | \
++ CC_YPLLSW_OFF | \
++ CC_YNLRSW | \
++ 0) \
++/*0x578e*/
++
++#define TSC_4WIRE_X_MEASURE ( \
++ CC_SEL_REFN_XNUR | \
++ CC_SELIN_YPLL | \
++ CC_SEL_REFP_XPUL | \
++ CC_XNURSW_LOW | \
++ CC_YPLLSW_OFF | \
++ 0) \
++/*0x1c90*/
++#define TSC_4WIRE_Y_MEASURE ( \
++ CC_SEL_REFN_YNLR | \
++ CC_SELIN_XPUL | \
++ CC_SEL_REFP_YPLL | \
++ CC_XPULSW | \
++ CC_XNURSW_OFF | \
++ CC_YNLRSW | \
++ 0) \
++/*0x4604*/
++#define TSC_4WIRE_XP_MEASURE ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_XPUL | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_YPLLSW_HIGH | \
++ CC_XNURSW_LOW | \
++ 0) \
++/*0x0f8c*/
++#define TSC_4WIRE_YN_MEASURE ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_YNLR | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_YPLLSW_HIGH | \
++ CC_XNURSW_LOW | \
++ 0) \
++/*0x0fbc*/
++
++#define TSC_GENERAL_ADC_GCC0 ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_INAUX0 | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_XNURSW_OFF | \
++ CC_YPLLSW_OFF | \
++ 0) \
++/*0x17dc*/
++#define TSC_GENERAL_ADC_GCC1 ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_INAUX0 | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_XNURSW_OFF | \
++ CC_YPLLSW_OFF | \
++ 0) \
++/*0x17ec*/
++#define TSC_GENERAL_ADC_GCC2 ( \
++ CC_SEL_REFN_AGND | \
++ CC_SELIN_INAUX0 | \
++ CC_SEL_REFP_INT | \
++ CC_XPULSW | \
++ CC_XNURSW_OFF | \
++ CC_YPLLSW_OFF | \
++ 0) \
++/*0x17fc*/
++
++/* GeneralADC Convert Queue FIFO Register */
++#define GCQ_REG_BASE 0x800
++#define GCQFIFO (GCQ_REG_BASE + CQFIFO)
++#define GCQFIFO_ADCOUT_SHIFT 4
++#define GCQFIFO_ADCOUT_MASK (0xfff << GCQFIFO_ADCOUT_SHIFT)
++
++/* GeneralADC Convert Queue Control Register */
++#define GCQCR (GCQ_REG_BASE + CQCR)
++
++/* GeneralADC Convert Queue Status Register */
++#define GCQSR (GCQ_REG_BASE + CQSR)
++
++/* GeneralADC Convert Queue Mask Register */
++#define GCQMR (GCQ_REG_BASE + CQMR)
++
++/* GeneralADC Convert Queue ITEM 7~0 */
++#define GCQ_ITEM_7_0 (GCQ_REG_BASE + CQ_ITEM_7_0)
++
++/* GeneralADC Convert Queue ITEM 15~8 */
++#define GCQ_ITEM_15_8 (GCQ_REG_BASE + CQ_ITEM_15_8)
++
++#define CQ_ITEM7_SHIFT 28
++#define CQ_ITEM6_SHIFT 24
++#define CQ_ITEM5_SHIFT 20
++#define CQ_ITEM4_SHIFT 16
++#define CQ_ITEM3_SHIFT 12
++#define CQ_ITEM2_SHIFT 8
++#define CQ_ITEM1_SHIFT 4
++#define CQ_ITEM0_SHIFT 0
++
++#define CQ_ITEM8_SHIFT 28
++#define CQ_ITEM9_SHIFT 24
++#define CQ_ITEM10_SHIFT 20
++#define CQ_ITEM11_SHIFT 16
++#define CQ_ITEM12_SHIFT 12
++#define CQ_ITEM13_SHIFT 8
++#define CQ_ITEM14_SHIFT 4
++#define CQ_ITEM15_SHIFT 0
++
++#define GCQ_ITEM_GCC0 0x0
++#define GCQ_ITEM_GCC1 0x1
++#define GCQ_ITEM_GCC2 0x2
++#define GCQ_ITEM_GCC3 0x3
++
++/* GeneralADC Convert Config 0-7 */
++#define GCC0 (GCQ_REG_BASE + 0x40)
++#define GCC1 (GCQ_REG_BASE + 0x44)
++#define GCC2 (GCQ_REG_BASE + 0x48)
++#define GCC3 (GCQ_REG_BASE + 0x4c)
++#define GCC4 (GCQ_REG_BASE + 0x50)
++#define GCC5 (GCQ_REG_BASE + 0x54)
++#define GCC6 (GCQ_REG_BASE + 0x58)
++#define GCC7 (GCQ_REG_BASE + 0x5c)
++
++/* TSC Test Register R/W */
++#define TTR 0xc00
++/* TSC Monitor Register 1, 2 */
++#define MNT1 0xc04
++#define MNT2 0xc04
++
++#define DETECT_ITEM_ID_1 1
++#define DETECT_ITEM_ID_2 5
++#define TS_X_ITEM_ID 2
++#define TS_Y_ITEM_ID 3
++#define TSI_DATA 1
++#define FQS_DATA 0
+diff -urN linux.35.old/drivers/Kconfig linux.35.new/drivers/Kconfig
+--- linux.35.old/drivers/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/Kconfig 2010-12-03 09:51:55.428348260 +0100
+@@ -2,6 +2,8 @@
+
+ source "drivers/base/Kconfig"
+
++source "drivers/mxc/Kconfig"
++
+ source "drivers/connector/Kconfig"
+
+ source "drivers/mtd/Kconfig"
+diff -urN linux.35.old/drivers/Makefile linux.35.new/drivers/Makefile
+--- linux.35.old/drivers/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/Makefile 2010-12-03 09:51:55.428348260 +0100
+@@ -92,6 +92,7 @@
+ obj-y += lguest/
+ obj-$(CONFIG_CPU_FREQ) += cpufreq/
+ obj-$(CONFIG_CPU_IDLE) += cpuidle/
++obj-$(CONFIG_ARCH_MXC) += mxc/
+ obj-$(CONFIG_MMC) += mmc/
+ obj-$(CONFIG_MEMSTICK) += memstick/
+ obj-$(CONFIG_NEW_LEDS) += leds/
+diff -urN linux.35.old/drivers/media/radio/Kconfig linux.35.new/drivers/media/radio/Kconfig
+--- linux.35.old/drivers/media/radio/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/media/radio/Kconfig 2010-12-03 09:51:55.428348260 +0100
+@@ -452,4 +452,14 @@
+ found behind the Timberdale FPGA on the Russellville board.
+ Enabling this driver will automatically select the DSP and tuner.
+
++config RADIO_SI4705
++ tristate "SI4705 I2C FM radio support"
++ depends on I2C && VIDEO_V4L2
++ ---help---
++ Say Y here if you want to use the SI4705 FM chip found in
++ voipac dev kits. This FM chip is connected to I2C bus.
++
++ To compile this driver as a module, choose M here: the
++ module will be called radio-si4705.
++
+ endif # RADIO_ADAPTERS
+diff -urN linux.35.old/drivers/media/radio/Makefile linux.35.new/drivers/media/radio/Makefile
+--- linux.35.old/drivers/media/radio/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/media/radio/Makefile 2010-12-03 09:51:55.428348260 +0100
+@@ -26,5 +26,6 @@
+ obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
+ obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
+ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
++obj-$(CONFIG_RADIO_SI4705) += radio-si4705.o
+
+ EXTRA_CFLAGS += -Isound
+diff -urN linux.35.old/drivers/media/radio/radio-si4705.c linux.35.new/drivers/media/radio/radio-si4705.c
+--- linux.35.old/drivers/media/radio/radio-si4705.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/media/radio/radio-si4705.c 2010-12-03 09:51:55.432349520 +0100
+@@ -0,0 +1,1008 @@
++/*
++ * driver/media/radio/radio-si4705.c
++ *
++ * Driver for SI4705 radio chip for linux 2.6.
++ * This driver is for SI4705 chip from Silicon Labs.
++ * The I2C protocol is used for communicate with chip.
++ *
++ * Based in radio-tea5764.c Copyright (C) 2008 Fabio Belavenuto
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * History:
++ * 2010-11-10 masu <support@voipac.com>
++ * initial code
++ *
++ * TODO:
++ * add RDS support - partialy
++ * add power on/off detection test in fuctions ?
++ */
++
++#include <linux/kernel.h>
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/init.h> /* Initdata */
++#include <linux/videodev2.h> /* kernel radio structs */
++#include <linux/i2c.h> /* I2C */
++#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
++#include <linux/version.h> /* for KERNEL_VERSION MACRO */
++
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/jiffies.h>
++#include <linux/interrupt.h>
++
++#include "radio-si4705.h"
++
++/* Module Parameters */
++/* Radio Nr */
++static int radio_nr = -1;
++module_param(radio_nr, int, 0444);
++MODULE_PARM_DESC(radio_nr, "Video4linux device number to use");
++
++/* RDS buffer blocks */
++static unsigned int rds_buf = 80;
++module_param(rds_buf, uint, 0444);
++MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*");
++
++/* RDS maximum block errors */
++static unsigned short max_rds_errors = 1;
++/* 0 means 0 errors requiring correction */
++/* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */
++/* 2 means 3-5 errors requiring correction */
++/* 3 means 6+ errors or errors in checkword, correction not possible */
++module_param(max_rds_errors, ushort, 0644);
++MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
++
++/* I2C code related */
++static unsigned i2c_timeout = 125;
++
++struct si4705_device {
++ struct i2c_client *i2c_client;
++ struct video_device *videodev;
++ struct si4705_reg reg;
++ struct si4705_property reg_property;
++ struct mutex mutex;
++ int users;
++
++ /* RDS receive buffer */
++ wait_queue_head_t read_queue;
++ unsigned char *buffer;
++ unsigned int buf_size;
++ unsigned int rd_index;
++ unsigned int wr_index;
++
++ struct work_struct radio_work;
++};
++
++/*
++ * si4705_do_i2c_cmd - read register
++ */
++int si4705_do_i2c_cmd(struct si4705_device *radio, u8 * txdata, u8 txsize, u8 * rxdata, u8 rxsize)
++{
++ int status = 0;
++ unsigned long timeout, read_time;
++// struct i2c_msg msgs[2] = {
++// { radio->i2c_client->addr, 0, txsize, (u8 *) txdata },
++// { radio->i2c_client->addr, I2C_M_RD, rxsize, (u8 *) rxdata },
++// };
++ struct i2c_msg tmsgs[1] = {
++ { radio->i2c_client->addr, 0, txsize, (u8 *) txdata },
++ };
++ struct i2c_msg rmsgs[1] = {
++ { radio->i2c_client->addr, I2C_M_RD, rxsize, (u8 *) rxdata },
++ };
++
++ // write
++ timeout = jiffies + msecs_to_jiffies(i2c_timeout);
++ do {
++ read_time = jiffies;
++ status = i2c_transfer(radio->i2c_client->adapter, tmsgs, 1);
++
++ // REVISIT: at HZ=100, this is sloooow
++ msleep(1);
++ } while (time_before(read_time, timeout) && status != 1);
++
++ if (status != 1)
++ return -EIO;
++
++ //read
++ timeout = jiffies + msecs_to_jiffies(i2c_timeout);
++ do {
++ read_time = jiffies;
++ status = i2c_transfer(radio->i2c_client->adapter, rmsgs, 1);
++
++ // REVISIT: at HZ=100, this is sloooow
++ msleep(1);
++ } while (time_before(read_time, timeout) && !(rxdata[0] & SI4705_STS_CTS));
++
++ if (status != 1)
++ return -EIO;
++
++ return 0;
++}
++
++int si4705_get_property(struct si4705_device * radio, u16 prop_cmd, u16 * property) {
++ u8 txdata[4];
++ u8 rxdata[4] = {0, 0, 0, 0};
++ u8 txsize = 0, rxsize = 4;
++ int ret;
++
++ txdata[txsize++] = si4705_cmd.GET_PROPERTY;
++ txdata[txsize++] = 0;
++ txdata[txsize++] = prop_cmd >> 8;
++ txdata[txsize++] = prop_cmd;
++
++ ret = si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize);
++
++ *property = (rxdata[2] << 8) + rxdata[3];
++
++ return ret;
++}
++
++int si4705_set_property(struct si4705_device * radio, u16 prop_cmd, u16 property) {
++ u8 txdata[6];
++ u8 rxdata[1] = {0};
++ u8 txsize = 0, rxsize = 1;
++ int ret;
++
++ txdata[txsize++] = si4705_cmd.SET_PROPERTY;
++ txdata[txsize++] = 0;
++ txdata[txsize++] = prop_cmd >> 8;
++ txdata[txsize++] = prop_cmd;
++ txdata[txsize++] = property >> 8;
++ txdata[txsize++] = property;
++
++ ret = si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize);
++
++ return ret;
++}
++
++int si4705_get_all_properties(struct si4705_device *radio) {
++ int ret = 0;
++
++ ret |= si4705_get_property(radio, si4705_prop_cmd.GPO_IEN, &(radio->reg_property.gpo_ien));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.DIGITAL_OUTPUT_FORMAT, &(radio->reg_property.digital_output_format));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.DIGITAL_OUTPUT_SAMPLE_RATE, &(radio->reg_property.digital_output_sample_rate));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.REFCLK_FREQ, &(radio->reg_property.refclk_freq));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.REFCLK_PRESCALE, &(radio->reg_property.refclk_prescale));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_DEEMPHASIS, &(radio->reg_property.fm_deemphasis));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_BLEND_STEREO_THRESHOLD, &(radio->reg_property.fm_blend_stereo_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_BLEND_MONO_THRESHOLD, &(radio->reg_property.fm_blend_mono_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_ANTENNA_INPUT, &(radio->reg_property.fm_antena_input));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_MAX_TUNE_ERROR, &(radio->reg_property.fm_max_tune_error));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RSQ_INT_SOURCE, &(radio->reg_property.fm_rsq_int_source));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RSQ_SNR_HI_THRESHOLD, &(radio->reg_property.fm_rsq_snr_hi_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RSQ_SNR_LO_THRESHOLD, &(radio->reg_property.fm_rsq_snr_lo_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RSQ_RSSI_HI_THRESHOLD, &(radio->reg_property.fm_rsq_rssi_hi_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RSQ_RSSI_LO_THRESHOLD, &(radio->reg_property.fm_rsq_rssi_lo_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_RQS_BLEND_THRESHOLD, &(radio->reg_property.fm_rsq_blend_threshold));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SOFT_MUTE_RATE, &(radio->reg_property.fm_soft_mute_rate));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SOFT_MUTE_MAX_ATTENUATION, &(radio->reg_property.fm_soft_mute_max_attenuation));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SOFT_MUTE_SNR_THRESHOLD, &(radio->reg_property.fm_soft_mute_snr_threshold));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_BAND_BOTTOM, &(radio->reg_property.fm_seek_band_bottom));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_BAND_TOP, &(radio->reg_property.fm_seek_band_top));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_FREQ_SPACING, &(radio->reg_property.fm_seek_freq_spacing));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_TUNE_SNR_THRESHOLD, &(radio->reg_property.fm_seek_tune_snr_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_TUNE_RSSI_TRESHOLD, &(radio->reg_property.fm_seek_tune_rssi_threshold));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.RDS_INT_SOURCE, &(radio->reg_property.rds_int_source));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.RDS_INT_FIFO_COUNT, &(radio->reg_property.rds_int_fifo_count));
++// ret |= si4705_get_property(radio, si4705_prop_cmd.RDS_CONFIG, &(radio->reg_property.rds_config));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.RX_VOLUME, &(radio->reg_property.rx_volume));
++ ret |= si4705_get_property(radio, si4705_prop_cmd.RX_HARD_MUTE, &(radio->reg_property.rx_hard_mute));
++
++ return ret;
++}
++
++/* V4L2 code related */
++static struct v4l2_queryctrl radio_qctrl[] = {
++ {
++ .id = V4L2_CID_AUDIO_MUTE,
++ .name = "Mute",
++ .minimum = 0,
++ .maximum = 1,
++ .default_value = 1,
++ .type = V4L2_CTRL_TYPE_BOOLEAN,
++ },{
++ .id = V4L2_CID_AUDIO_VOLUME,
++ .name = "Volume",
++ .minimum = 0,
++ .maximum = 0x3f,
++ .step = 1,
++ .default_value = 0x20,
++ .type = V4L2_CTRL_TYPE_INTEGER,
++ }
++
++};
++
++static int si4705_power_up(struct si4705_device *radio)
++{
++ u8 txdata[3];
++ u8 rxdata[1] = {0};
++ u8 txsize = 0, rxsize = 1;
++
++ txdata[txsize++] = si4705_cmd.POWER_UP;
++ txdata[txsize++] = SI4705_PU_INT_ENABLE;
++ txdata[txsize++] = SI4705_PU_MODE_AN;
++
++ return si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize);
++}
++
++static int si4705_power_down(struct si4705_device *radio)
++{
++ u8 txdata[1];
++ u8 rxdata[1] = {0};
++ u8 txsize = 0, rxsize = 1;
++
++ txdata[txsize++] = si4705_cmd.POWER_DOWN;
++
++ return si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize);
++}
++
++/* tune an frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
++static void si4705_tune(struct si4705_device *radio, int freq)
++{
++ u8 txdata[5];
++ u8 rxdata[1] = {0};
++ u8 txsize = 0, rxsize = 1;
++
++ radio->reg.tunned_freq = freq / 10000;
++
++ txdata[txsize++] = si4705_cmd.FM_TUNE_FREQ;
++ txdata[txsize++] = 0x00;
++ txdata[txsize++] = radio->reg.tunned_freq >> 8;
++ txdata[txsize++] = radio->reg.tunned_freq;
++ txdata[txsize++] = 0x00;
++
++ if(si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize)) {
++ printk(KERN_INFO "%s Error setting the frequency\n", __func__);
++ }
++}
++
++static void si4705_rds(struct si4705_device *radio, u8 cmd, u8 * data)
++{
++ u8 txdata[2];
++ u8 txsize = 0;
++
++ txdata[txsize++] = si4705_cmd.FM_RDS_STATUS;
++ txdata[txsize++] = cmd;
++
++ if(si4705_do_i2c_cmd(radio, txdata, txsize, data, 13)) {
++ printk(KERN_INFO "%s Error reading RDS data\n", __func__);
++ }
++
++//printk(KERN_INFO "Status 0x%02x '%c'\n", rxdata[0], rxdata[0]);
++//printk(KERN_INFO "Resp 1 0x%02x '%c'\n", rxdata[1], rxdata[1]);
++//printk(KERN_INFO "Resp 2 0x%02x '%c'\n", rxdata[2], rxdata[2]);
++//printk(KERN_INFO "Used 0x%02x '%c'\n", rxdata[3], rxdata[3]);
++//printk(KERN_INFO "BLOCKA 0x%02x '%c'\n", rxdata[4], rxdata[4]);
++//printk(KERN_INFO "BLOCKA 0x%02x '%c'\n", rxdata[5], rxdata[5]);
++//printk(KERN_INFO "BLOCKB 0x%02x '%c'\n", rxdata[6], rxdata[6]);
++//printk(KERN_INFO "BLOCKB 0x%02x '%c'\n", rxdata[7], rxdata[7]);
++//printk(KERN_INFO "BLOCKC 0x%02x '%c'\n", rxdata[8], rxdata[8]);
++//printk(KERN_INFO "BLOCKC 0x%02x '%c'\n", rxdata[9], rxdata[9]);
++//printk(KERN_INFO "BLOCKD 0x%02x '%c'\n", rxdata[10], rxdata[10]);
++//printk(KERN_INFO "BLOCKD 0x%02x '%c'\n", rxdata[11], rxdata[11]);
++//printk(KERN_INFO "Errors 0x%02x '%c'\n", rxdata[12], rxdata[12]);
++
++}
++
++static void si4705_status(struct si4705_device *radio, u8 * data)
++{
++ u8 txdata[1];
++ u8 rxdata[1] = {0};
++ u8 txsize = 0, rxsize = 1;
++
++ txdata[txsize++] = si4705_cmd.GET_INT_STATUS;
++
++ memset(rxdata, 0, sizeof(rxdata));
++
++ if(si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize)) {
++ printk(KERN_INFO "%s Error reading RDS data\n", __func__);
++ }
++ *data = rxdata[0];
++}
++
++static void si4705_set_audout_mode(struct si4705_device *radio, int audmode)
++{
++// struct si4705_regs *r = &radio->regs;
++// int tnctrl = r->tnctrl;
++//
++// if (audmode == V4L2_TUNER_MODE_MONO)
++// r->tnctrl |= TEA5764_TNCTRL_MST;
++// else
++// r->tnctrl &= ~TEA5764_TNCTRL_MST;
++// if (tnctrl != r->tnctrl)
++// tea5764_i2c_write(radio);
++}
++
++static int si4705_get_audout_mode(struct si4705_device *radio)
++{
++// struct tea5764_regs *r = &radio->regs;
++//
++// if (r->tnctrl & TEA5764_TNCTRL_MST)
++// return V4L2_TUNER_MODE_MONO;
++// else
++ return V4L2_TUNER_MODE_STEREO;
++}
++
++/* V4L2 vidioc */
++static int vidioc_querycap(struct file *file, void *priv,
++ struct v4l2_capability *v)
++{
++ struct si4705_device *radio = video_drvdata(file);
++ struct video_device *dev = radio->videodev;
++
++ strlcpy(v->driver, dev->dev.driver->name, sizeof(v->driver));
++ strlcpy(v->card, dev->name, sizeof(v->card));
++ snprintf(v->bus_info, sizeof(v->bus_info),
++ "I2C:%s", dev_name(&dev->dev));
++ v->version = RADIO_VERSION;
++ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | \
++ V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_RDS_CAPTURE;
++ return 0;
++}
++
++static int vidioc_g_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *v)
++{
++ u8 txdata[2];
++ u8 rxdata[8] = {0};
++ u8 txsize = 0, rxsize = 8;
++ struct si4705_device *radio = video_drvdata(file);
++
++ if (v->index > 0)
++ return -EINVAL;
++
++ memset(v, 0, sizeof(*v));
++ strcpy(v->name, "FM");
++ v->type = V4L2_TUNER_RADIO;
++
++// MASU complete this
++// si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_BAND_BOTTOM, &(radio->reg_property.fm_seek_band_bottom));
++// si4705_get_property(radio, si4705_prop_cmd.FM_SEEK_BAND_TOP, &(radio->reg_property.fm_seek_band_top));
++
++// MASU FIXME Get signal quality
++
++ txdata[txsize++] = si4705_cmd.FM_TUNE_STATUS;
++ txdata[txsize++] = 0x00;
++
++ si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize);
++
++ v->rangelow = FREQ_MIN * FREQ_MUL;
++ v->rangehigh = FREQ_MAX * FREQ_MUL;
++ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
++// if (r->tunchk & TEA5764_TUNCHK_STEREO)
++ v->rxsubchans = V4L2_TUNER_SUB_STEREO;
++// else
++// v->rxsubchans = V4L2_TUNER_SUB_MONO;
++ v->audmode = si4705_get_audout_mode(radio);
++ v->signal = rxdata[5] * 0xffff / 0xf; // MASU fix me
++// v->afc = TEA5764_TUNCHK_IFCNT(r->tunchk);
++
++ return 0;
++}
++
++static int vidioc_s_tuner(struct file *file, void *priv,
++ struct v4l2_tuner *v)
++{
++ struct si4705_device *radio = video_drvdata(file);
++
++ if (v->index > 0)
++ return -EINVAL;
++
++ si4705_set_audout_mode(radio, v->audmode);
++ return 0;
++}
++
++static int vidioc_s_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *f)
++{
++ struct si4705_device *radio = video_drvdata(file);
++
++ if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
++ return -EINVAL;
++ if (f->frequency == 0) {
++ /* We special case this as a power down control. */
++ si4705_power_down(radio);
++ }
++ if (f->frequency < (FREQ_MIN * FREQ_MUL))
++ return -EINVAL;
++ if (f->frequency > (FREQ_MAX * FREQ_MUL))
++ return -EINVAL;
++ si4705_power_up(radio);
++ si4705_tune(radio, (f->frequency * 125) / 2);
++
++ return 0;
++}
++
++static int vidioc_g_frequency(struct file *file, void *priv,
++ struct v4l2_frequency *f)
++{
++ struct si4705_device *radio = video_drvdata(file);
++
++ if (f->tuner != 0)
++ return -EINVAL;
++
++ memset(f, 0, sizeof(*f));
++ f->type = V4L2_TUNER_RADIO;
++// if (r->tnctrl & TEA5764_TNCTRL_PUPD0)
++ f->frequency = (radio->reg.tunned_freq * 10000 * 2) / 125;
++// else
++// f->frequency = 0;
++
++ return 0;
++}
++
++static int vidioc_queryctrl(struct file *file, void *priv,
++ struct v4l2_queryctrl *qc)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
++ if (qc->id && qc->id == radio_qctrl[i].id) {
++ memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
++ return 0;
++ }
++ }
++ return -EINVAL;
++}
++
++static int vidioc_g_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct si4705_device *radio = video_drvdata(file);
++
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ si4705_get_property(radio, si4705_prop_cmd.RX_VOLUME, &(radio->reg_property.rx_volume));
++ ctrl->value = radio->reg_property.rx_volume;
++ return 0;
++ case V4L2_CID_AUDIO_MUTE:
++ si4705_get_property(radio, si4705_prop_cmd.RX_HARD_MUTE, &(radio->reg_property.rx_hard_mute));
++ ctrl->value = (radio->reg_property.rx_hard_mute & SI4705_RHM_MUTE_ALL) ? 1 : 0;
++ return 0;
++ }
++ return -EINVAL;
++}
++
++static int vidioc_s_ctrl(struct file *file, void *priv,
++ struct v4l2_control *ctrl)
++{
++ struct si4705_device *radio = video_drvdata(file);
++ switch (ctrl->id) {
++ case V4L2_CID_AUDIO_VOLUME:
++ si4705_set_property(radio, si4705_prop_cmd.RX_VOLUME, ctrl->value);
++ return 0;
++ case V4L2_CID_AUDIO_MUTE:
++ if (ctrl->value)
++ si4705_set_property(radio, si4705_prop_cmd.RX_HARD_MUTE, SI4705_RHM_MUTE_ALL);
++ else
++ si4705_set_property(radio, si4705_prop_cmd.RX_HARD_MUTE, SI4705_RHM_MUTE_NONE);
++ return 0;
++ }
++ return -EINVAL;
++}
++
++static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
++{
++ *i = 0;
++ return 0;
++}
++
++static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
++{
++ if (i != 0)
++ return -EINVAL;
++ return 0;
++}
++
++static int vidioc_g_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ if (a->index > 1)
++ return -EINVAL;
++
++ strcpy(a->name, "Radio");
++ a->capability = V4L2_AUDCAP_STEREO;
++ return 0;
++}
++
++static int vidioc_s_audio(struct file *file, void *priv,
++ struct v4l2_audio *a)
++{
++ if (a->index != 0)
++ return -EINVAL;
++
++ return 0;
++}
++
++static int si4705_open(struct file *file)
++{
++ struct si4705_device *radio = video_drvdata(file);
++ int ret = 0;
++ unsigned short cerr = 0x0000;
++
++ mutex_lock(&radio->mutex);
++ radio->users++;
++
++ if (radio->users == 1) {
++ /* start radio */
++#ifndef USE_LEGACY_ONOFF
++ ret = si4705_power_up(radio);
++
++ if (ret)
++ goto done;
++#endif
++#ifdef DISSABLE_RDS
++ switch(max_rds_errors) {
++ case 0: cerr = 0x0000; break;
++ case 1:
++ case 2: cerr = 0x5500; break;
++ case 3:
++ case 4:
++ case 5: cerr = 0xaa00; break;
++ default : cerr = 0xff00; break;
++ }
++
++ /* enable RDS interrupt */
++ ret = si4705_set_property(radio, si4705_prop_cmd.GPO_IEN, SI4705_GI_RDSIEN);
++ // GPIO2 int configuret at power up
++ ret |= si4705_set_property(radio, si4705_prop_cmd.RDS_INT_SOURCE, 0x0001); // enable fifo filled interrupts
++ ret |= si4705_set_property(radio, si4705_prop_cmd.RDS_INT_FIFO_COUNT, 0x0004);
++ ret |= si4705_set_property(radio, si4705_prop_cmd.RDS_CONFIG, cerr |0x0001); // enable interrupt
++ if (ret)
++ goto done;
++#endif
++ }
++
++done:
++ mutex_unlock(&radio->mutex);
++ return ret;
++}
++
++static int si4705_close(struct file *file)
++{
++ struct si4705_device *radio = video_drvdata(file);
++ int ret = 0;
++
++ if (!radio)
++ return -ENODEV;
++ mutex_lock(&radio->mutex);
++ radio->users--;
++ if (radio->users == 0)
++ /* stop radio */
++#ifndef USE_LEGACY_ONOFF
++ ret = si4705_power_down(radio);
++#endif
++ mutex_unlock(&radio->mutex);
++
++ return ret;
++}
++
++/*
++ * si4705_fops_read - read RDS data
++ */
++static ssize_t si4705_fops_read(struct file *file, char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ struct si4705_device *radio = video_drvdata(file);
++ int retval = 0;
++ unsigned int block_count = 0;
++
++ /* switch on rds reception */
++// if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
++// si470x_rds_on(radio);
++
++ /* block if no new data available */
++/* while (radio->wr_index == radio->rd_index) {
++ if (file->f_flags & O_NONBLOCK) {
++ retval = -EWOULDBLOCK;
++ goto done;
++ }
++ if (wait_event_interruptible(radio->read_queue,
++ radio->wr_index != radio->rd_index) < 0) {
++ retval = -EINTR;
++ goto done;
++ }
++ }
++*/
++ /* calculate block count from byte count */
++ count /= 3;
++
++ /* copy RDS block out of internal buffer and to user buffer */
++ mutex_lock(&radio->mutex);
++/* while (block_count < count) {
++ if (radio->rd_index == radio->wr_index)
++ break;
++
++ // always transfer rds complete blocks
++ if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3))
++ // retval = -EFAULT;
++ break;
++
++ // increment and wrap read pointer
++ radio->rd_index += 3;
++ if (radio->rd_index >= radio->buf_size)
++ radio->rd_index = 0;
++
++ // increment counters
++ block_count++;
++ buf += 3;
++ retval += 3;
++ }
++*/
++ mutex_unlock(&radio->mutex);
++
++//done:
++ return retval;
++}
++
++/* File system interface */
++static const struct v4l2_file_operations si4705_fops = {
++ .owner = THIS_MODULE,
++ .open = si4705_open,
++ .release = si4705_close,
++ .ioctl = video_ioctl2,
++ .read = si4705_fops_read,
++};
++
++static const struct v4l2_ioctl_ops si4705_ioctl_ops = {
++ .vidioc_querycap = vidioc_querycap,
++ .vidioc_g_tuner = vidioc_g_tuner,
++ .vidioc_s_tuner = vidioc_s_tuner,
++ .vidioc_g_audio = vidioc_g_audio,
++ .vidioc_s_audio = vidioc_s_audio,
++ .vidioc_g_input = vidioc_g_input,
++ .vidioc_s_input = vidioc_s_input,
++ .vidioc_g_frequency = vidioc_g_frequency,
++ .vidioc_s_frequency = vidioc_s_frequency,
++ .vidioc_queryctrl = vidioc_queryctrl,
++ .vidioc_g_ctrl = vidioc_g_ctrl,
++ .vidioc_s_ctrl = vidioc_s_ctrl,
++};
++
++/* V4L2 interface */
++static struct video_device si4705_radio_template = {
++ .name = "SI4705 FM-Radio",
++ .fops = &si4705_fops,
++ .ioctl_ops = &si4705_ioctl_ops,
++ .release = video_device_release,
++};
++
++
++/*
++ * si470x_i2c_interrupt_work - rds processing function
++ */
++#ifndef DISSABLE_RDS
++static void si4705_i2c_interrupt_work(struct work_struct *work)
++{
++ struct si4705_device *radio = container_of(work,
++ struct si4705_device, radio_work);
++// unsigned char regnr;
++// unsigned char blocknum;
++// unsigned short bler; // rds block errors
++ unsigned char tmpbuf[13];
++// unsigned char finbuf[13];
++// int retval = 0;
++ u8 status;
++
++ // safety checks
++ si4705_status(radio, &status);
++ if ((status & SI4705_GIS_RDSINT) == 0) // not a rds interrupt
++ return;
++
++ // Update RDS registers
++ do {
++ si4705_rds(radio, SI4705_FRS_INTACK, tmpbuf);
++ } while (tmpbuf[3] != 0x00);
++
++
++
++//printk(KERN_INFO "Status 0x%02x '%c'\n", rxdata[0], rxdata[0]);
++//printk(KERN_INFO "Resp 1 0x%02x '%c'\n", rxdata[1], rxdata[1]);
++//printk(KERN_INFO "Resp 2 0x%02x '%c'\n", rxdata[2], rxdata[2]);
++//printk(KERN_INFO "Used 0x%02x '%c'\n", rxdata[3], rxdata[3]);
++//printk(KERN_INFO "BLOCKA 0x%02x '%c'\n", rxdata[4], rxdata[4]);
++//printk(KERN_INFO "BLOCKA 0x%02x '%c'\n", rxdata[5], rxdata[5]);
++//printk(KERN_INFO "BLOCKB 0x%02x '%c'\n", rxdata[6], rxdata[6]);
++//printk(KERN_INFO "BLOCKB 0x%02x '%c'\n", rxdata[7], rxdata[7]);
++//printk(KERN_INFO "BLOCKC 0x%02x '%c'\n", rxdata[8], rxdata[8]);
++//printk(KERN_INFO "BLOCKC 0x%02x '%c'\n", rxdata[9], rxdata[9]);
++//printk(KERN_INFO "BLOCKD 0x%02x '%c'\n", rxdata[10], rxdata[10]);
++//printk(KERN_INFO "BLOCKD 0x%02x '%c'\n", rxdata[11], rxdata[11]);
++//printk(KERN_INFO "Errors 0x%02x '%c'\n", rxdata[12], rxdata[12]);
++/* switch (blocknum) {
++ default:
++ bler = (radio->registers[STATUSRSSI] &
++ STATUSRSSI_BLERA) >> 9;
++ rds = radio->registers[RDSA];
++ break;
++ case 1:
++ bler = (radio->registers[READCHAN] &
++ READCHAN_BLERB) >> 14;
++ rds = radio->registers[RDSB];
++ break;
++ case 2:
++ bler = (radio->registers[READCHAN] &
++ READCHAN_BLERC) >> 12;
++ rds = radio->registers[RDSC];
++ break;
++ case 3:
++ bler = (radio->registers[READCHAN] &
++ READCHAN_BLERD) >> 10;
++ rds = radio->registers[RDSD];
++ break;
++ };
++
++ // Fill the V4L2 RDS buffer
++ put_unaligned_le16(rds, &tmpbuf);
++ tmpbuf[2] = blocknum; // offset name
++ tmpbuf[2] |= blocknum << 3; // received offset
++ if (bler > max_rds_errors)
++ tmpbuf[2] |= 0x80; // uncorrectable errors
++ else if (bler > 0)
++ tmpbuf[2] |= 0x40; // corrected error(s)
++
++ // copy RDS block to internal buffer
++ memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3);
++ radio->wr_index += 3;
++
++ // wrap write pointer
++ if (radio->wr_index >= radio->buf_size)
++ radio->wr_index = 0;
++
++ // check for overflow
++ if (radio->wr_index == radio->rd_index) {
++ // increment and wrap read pointer
++ radio->rd_index += 3;
++ if (radio->rd_index >= radio->buf_size)
++ radio->rd_index = 0;
++ }
++ }
++
++ if (radio->wr_index != radio->rd_index)
++ wake_up_interruptible(&radio->read_queue);
++*/
++}
++#else
++static void si4705_i2c_interrupt_work(struct work_struct *work) {
++ ;
++}
++#endif // DISSABLE_RDS
++
++/*
++ * si470x_i2c_interrupt - interrupt handler
++ */
++static irqreturn_t si4705_i2c_interrupt(int irq, void *dev_id)
++{
++ struct si4705_device *radio = dev_id;
++
++ if (!work_pending(&radio->radio_work))
++ schedule_work(&radio->radio_work);
++
++ return IRQ_HANDLED;
++}
++
++/* I2C probe: check if the device exists and register with v4l if it is */
++static int __devinit si4705_i2c_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct si4705_device *radio;
++ u8 txdata[2];
++ u8 rxdata[8];
++ u8 txsize = 0, rxsize = 0;
++ int ret;
++
++ memset(txdata, 0, sizeof(txdata));
++ memset(rxdata, 0, sizeof(rxdata));
++
++ /* private data allocation and initialization */
++ radio = kzalloc(sizeof(struct si4705_device), GFP_KERNEL);
++ if (!radio) {
++ ret = -ENOMEM;
++ goto err_initial;
++ }
++
++ INIT_WORK(&radio->radio_work, si4705_i2c_interrupt_work);
++ radio->users = 0;
++ radio->i2c_client = client;
++ mutex_init(&radio->mutex);
++
++ /* video device allocation and initialization */
++ radio->videodev = video_device_alloc();
++ if (!(radio->videodev)) {
++ ret = -ENOMEM;
++ goto err_radio;
++ }
++ memcpy(radio->videodev, &si4705_radio_template,
++ sizeof(si4705_radio_template));
++ video_set_drvdata(radio->videodev, radio);
++
++ /* Detect the chip in power off mode */
++ txdata[txsize++] = si4705_cmd.POWER_UP; // Library ID
++ txdata[txsize++] = 0x0F;
++
++ rxsize = 8;
++ memset(rxdata, 0, sizeof(rxdata));
++
++ if (si4705_do_i2c_cmd(radio, txdata, txsize, rxdata, rxsize)) {
++ ret = -EIO;
++ goto errrel;
++ }
++
++ radio->reg.part_number = rxdata[1];
++ radio->reg.fw_major = rxdata[2];
++ radio->reg.fw_minor = rxdata[3];
++ radio->reg.revision = rxdata[6];
++
++
++ dev_info(&client->dev, "ChipID=si47%02d%c Firmware %c%c\n",
++ radio->reg.part_number, radio->reg.revision, \
++ radio->reg.fw_major, radio->reg.fw_minor);
++ if ((((radio->reg.fw_major - '0') * 10) + (radio->reg.fw_minor - '0')) \
++ < RADIO_FW_VERSION) {
++ dev_warn(&client->dev,
++ "This driver is known to work with "
++ "firmware version %hu,\n", RADIO_FW_VERSION);
++ dev_warn(&client->dev,
++ "but the device has older firmware version.\n");
++ }
++
++ /* Power on */
++ if (si4705_power_up(radio)) {
++ ret = -EIO;
++ goto errrel;
++ }
++
++ /* Get all properties */
++// if (si4705_get_all_properties(radio)) {
++// ret = -EIO;
++// goto errrel;
++// }
++
++ /* rds buffer allocation */
++ radio->buf_size = rds_buf;
++ radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
++ if (!radio->buffer) {
++ ret = -EIO;
++ goto errrel;
++ }
++
++ /* rds buffer configuration */
++ radio->wr_index = 0;
++ radio->rd_index = 0;
++ init_waitqueue_head(&radio->read_queue);
++
++ ret = request_irq(client->irq, si4705_i2c_interrupt,
++ IRQF_TRIGGER_FALLING, DRIVER_NAME, radio);
++ if (ret) {
++ dev_err(&client->dev, "Failed to register interrupt\n");
++ goto err_rds;
++ }
++
++ ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
++ if (ret < 0) {
++ dev_warn(&client->dev, "Could not register video device!");
++ goto err_all;
++ }
++
++ i2c_set_clientdata(client, radio);
++
++ return 0;
++err_all:
++ free_irq(client->irq, radio);
++err_rds:
++ kfree(radio->buffer);
++errrel:
++ video_device_release(radio->videodev);
++err_radio:
++ kfree(radio);
++err_initial:
++ return ret;
++}
++
++static int __devexit si4705_i2c_remove(struct i2c_client *client)
++{
++ struct si4705_device *radio = i2c_get_clientdata(client);
++
++ free_irq(client->irq, radio);
++ cancel_work_sync(&radio->radio_work);
++#ifdef USE_LEGACY_ONOFF
++ si4705_power_down(radio);
++#endif
++ kfree(radio->buffer);
++ video_unregister_device(radio->videodev);
++ kfree(radio);
++
++ return 0;
++}
++
++/* I2C subsystem interface */
++static const struct i2c_device_id si4705_i2c_id[] = {
++ /* Generic Entry */
++ { "radio-si4705", 0 },
++ /* Terminating entry */
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, si4705_i2c_id);
++
++#ifdef CONFIG_PM
++/*
++ * si470x_i2c_suspend - suspend the device
++ */
++static int si4705_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
++{
++ struct si4705_device *radio = i2c_get_clientdata(client);
++
++ if (si4705_power_down(radio))
++ return -EIO;
++
++ return 0;
++}
++
++
++/*
++ * si470x_i2c_resume - resume the device
++ */
++static int si4705_i2c_resume(struct i2c_client *client)
++{
++ struct si4705_device *radio = i2c_get_clientdata(client);
++
++ if (si4705_power_up(radio))
++ return -EIO;
++
++ return 0;
++}
++#else
++#define si4705_i2c_suspend NULL
++#define si4705_i2c_resume NULL
++#endif
++
++static struct i2c_driver si4705_i2c_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = si4705_i2c_probe,
++ .remove = __devexit_p(si4705_i2c_remove),
++ .suspend = si4705_i2c_suspend,
++ .resume = si4705_i2c_resume,
++ .id_table = si4705_i2c_id,
++};
++
++/* init the driver */
++static int __init si4705_init(void)
++{
++ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ": "
++ DRIVER_DESC "\n");
++ return i2c_add_driver(&si4705_i2c_driver);
++}
++
++/* cleanup the driver */
++static void __exit si4705_exit(void)
++{
++ i2c_del_driver(&si4705_i2c_driver);
++}
++
++module_init(si4705_init);
++module_exit(si4705_exit);
++
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_VERSION(DRIVER_VERSION);
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/drivers/media/radio/radio-si4705.h linux.35.new/drivers/media/radio/radio-si4705.h
+--- linux.35.old/drivers/media/radio/radio-si4705.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/media/radio/radio-si4705.h 2010-12-03 09:51:55.436349742 +0100
+@@ -0,0 +1,217 @@
++/*
++ * drivers/media/radio/radio-si4705.h
++ *
++ * Property and commands definitions for Si4705 radio receiver chip.
++ *
++ * Copyright (c) 2010 Voipac
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ */
++
++#ifndef RADIO_SI4705_H
++#define RADIO_SI4705_H
++
++#include <linux/types.h>
++
++
++/* driver definitions */
++#define DRIVER_NAME "radio-si4705"
++
++#define DRIVER_VERSION "v0.01"
++#define RADIO_VERSION KERNEL_VERSION(0, 0, 1)
++
++#define DRIVER_AUTHOR "Voipac <support@voipac.com>"
++#define DRIVER_DESC "A driver for the SI4705 radio chip."
++
++/* Tunner will remain active until the driver is uloaded */
++#define USE_LEGACY_ONOFF
++#define DISSABLE_RDS
++
++/* Tunner will remain active only when fd is open */
++//#undef USE_LEGACY_ONOFF
++
++/* Frequency limits in MHz -- these are European values. For Japanese
++devices, that would be 76000 and 91000. */
++#define FREQ_MIN 87500
++#define FREQ_MAX 108000
++#define FREQ_MUL 16
++
++/* Firmware Versions */
++#define RADIO_FW_VERSION 20
++
++
++/* Status response mask */
++#define SI4705_STS_CTS 0x80
++#define SI4705_STS_ERR 0x40
++
++/* Power Up mask */
++#define SI4705_PU_INT_ENABLE 0xC0
++#define SI4705_PU_MODE_AN 0x05
++#define SI4705_PU_MODE_DI 0xB0
++#define SI4705_PU_MODE_ANDI (SI4705_PU_MODE_AN | SI4705_PU_MODE_DI)
++
++/* Get int status mask */
++#define SI4705_GIS_RDSINT 0x04
++
++/* Fm rds starus mask */
++#define SI4705_FRS_MTFIFO 0x02
++#define SI4705_FRS_INTACK 0x01
++
++struct si4705_reg {
++ u8 part_number; // hex - last two digits
++ u8 fw_major; // ASCII
++ u8 fw_minor; // ASCII
++ u8 revision; // ASCII
++ u16 tunned_freq; // hex 101.20MHz ~ 0x2788
++} __attribute__ ((packed));
++
++typedef struct {
++ u8 POWER_UP;
++ u8 GET_REV;
++ u8 POWER_DOWN;
++ u8 SET_PROPERTY;
++ u8 GET_PROPERTY;
++ u8 GET_INT_STATUS;
++ u8 PATCH_ARGS;
++ u8 PATCH_DATA;
++ u8 FM_TUNE_FREQ;
++ u8 FM_SEEK_START;
++ u8 FM_TUNE_STATUS;
++ u8 FM_RSQ_STATUS;
++ u8 FM_RDS_STATUS;
++ u8 FM_AGC_STATUS;
++ u8 FM_AGC_OVERRIDE;
++ u8 GPIO_CTL;
++ u8 GPIO_SET;
++} SI4705_CMD;
++
++SI4705_CMD si4705_cmd = {
++ .POWER_UP = 0x01,
++ .GET_REV = 0x10,
++ .POWER_DOWN = 0x11,
++ .SET_PROPERTY = 0x12,
++ .GET_PROPERTY = 0x13,
++ .GET_INT_STATUS = 0x14,
++ .PATCH_ARGS = 0x15,
++ .PATCH_DATA = 0x16,
++ .FM_TUNE_FREQ = 0x20,
++ .FM_SEEK_START = 0x21,
++ .FM_TUNE_STATUS = 0x22,
++ .FM_RSQ_STATUS = 0x23,
++ .FM_RDS_STATUS = 0x24,
++ .FM_AGC_STATUS = 0x27,
++ .FM_AGC_OVERRIDE = 0x28,
++ .GPIO_CTL = 0x80,
++ .GPIO_SET = 0x81
++};
++
++/* gpo_ien */
++#define SI4705_GI_RDSREP 0x0400
++#define SI4705_GI_RDSIEN 0x0004
++
++/* rx_hard_mute */
++#define SI4705_RHM_MUTE_R 0x0001
++#define SI4705_RHM_MUTE_L 0x0002
++#define SI4705_RHM_MUTE_ALL (SI4705_RHM_MUTE_R | SI4705_RHM_MUTE_L)
++#define SI4705_RHM_MUTE_NONE 0x0000
++
++struct si4705_property {
++ u16 gpo_ien; /* Enables interrupt sources */
++ u16 digital_output_format; /* Configure digital audio outputs */
++ u16 digital_output_sample_rate;
++ u16 refclk_freq;
++ u16 refclk_prescale;
++ u16 fm_deemphasis;
++ u16 fm_blend_stereo_threshold;
++ u16 fm_blend_mono_threshold;
++ u16 fm_antena_input;
++ u16 fm_max_tune_error;
++ u16 fm_rsq_int_source;
++ u16 fm_rsq_snr_hi_threshold;
++ u16 fm_rsq_snr_lo_threshold;
++ u16 fm_rsq_rssi_hi_threshold;
++ u16 fm_rsq_rssi_lo_threshold;
++ u16 fm_rsq_blend_threshold;
++ u16 fm_soft_mute_rate;
++ u16 fm_soft_mute_max_attenuation;
++ u16 fm_soft_mute_snr_threshold;
++ u16 fm_seek_band_bottom;
++ u16 fm_seek_band_top;
++ u16 fm_seek_freq_spacing;
++ u16 fm_seek_tune_snr_threshold;
++ u16 fm_seek_tune_rssi_threshold;
++ u16 rds_int_source;
++ u16 rds_int_fifo_count;
++ u16 rds_config;
++ u16 rx_volume;
++ u16 rx_hard_mute;
++} __attribute__ ((packed));
++
++typedef struct {
++ u16 GPO_IEN;
++ u16 DIGITAL_OUTPUT_FORMAT;
++ u16 DIGITAL_OUTPUT_SAMPLE_RATE;
++ u16 REFCLK_FREQ;
++ u16 REFCLK_PRESCALE;
++ u16 FM_DEEMPHASIS;
++ u16 FM_BLEND_STEREO_THRESHOLD;
++ u16 FM_BLEND_MONO_THRESHOLD;
++ u16 FM_ANTENNA_INPUT;
++ u16 FM_MAX_TUNE_ERROR;
++ u16 FM_RSQ_INT_SOURCE;
++ u16 FM_RSQ_SNR_HI_THRESHOLD;
++ u16 FM_RSQ_SNR_LO_THRESHOLD;
++ u16 FM_RSQ_RSSI_HI_THRESHOLD;
++ u16 FM_RSQ_RSSI_LO_THRESHOLD;
++ u16 FM_RQS_BLEND_THRESHOLD;
++ u16 FM_SOFT_MUTE_RATE;
++ u16 FM_SOFT_MUTE_MAX_ATTENUATION;
++ u16 FM_SOFT_MUTE_SNR_THRESHOLD;
++ u16 FM_SEEK_BAND_BOTTOM;
++ u16 FM_SEEK_BAND_TOP;
++ u16 FM_SEEK_FREQ_SPACING;
++ u16 FM_SEEK_TUNE_SNR_THRESHOLD;
++ u16 FM_SEEK_TUNE_RSSI_TRESHOLD;
++ u16 RDS_INT_SOURCE;
++ u16 RDS_INT_FIFO_COUNT;
++ u16 RDS_CONFIG;
++ u16 RX_VOLUME;
++ u16 RX_HARD_MUTE;
++} SI4705_PROP_CMD;
++
++SI4705_PROP_CMD si4705_prop_cmd = {
++ .GPO_IEN = 0x0001,
++ .DIGITAL_OUTPUT_FORMAT = 0x0102,
++ .DIGITAL_OUTPUT_SAMPLE_RATE = 0x0104,
++ .REFCLK_FREQ = 0x0201,
++ .REFCLK_PRESCALE = 0x0202,
++ .FM_DEEMPHASIS = 0x1100,
++ .FM_BLEND_STEREO_THRESHOLD = 0x1105,
++ .FM_BLEND_MONO_THRESHOLD = 0x1106,
++ .FM_ANTENNA_INPUT = 0x1107,
++ .FM_MAX_TUNE_ERROR = 0x1108,
++ .FM_RSQ_INT_SOURCE = 0x1200,
++ .FM_RSQ_SNR_HI_THRESHOLD = 0x1201,
++ .FM_RSQ_SNR_LO_THRESHOLD = 0x1202,
++ .FM_RSQ_RSSI_HI_THRESHOLD = 0x1203,
++ .FM_RSQ_RSSI_LO_THRESHOLD = 0x1204,
++ .FM_RQS_BLEND_THRESHOLD = 0x1207,
++ .FM_SOFT_MUTE_RATE = 0x1300,
++ .FM_SOFT_MUTE_MAX_ATTENUATION = 0x1302,
++ .FM_SOFT_MUTE_SNR_THRESHOLD = 0x1303,
++ .FM_SEEK_BAND_BOTTOM = 0x1400,
++ .FM_SEEK_BAND_TOP = 0x1401,
++ .FM_SEEK_FREQ_SPACING = 0x1402,
++ .FM_SEEK_TUNE_SNR_THRESHOLD = 0x1403,
++ .FM_SEEK_TUNE_RSSI_TRESHOLD = 0x1404,
++ .RDS_INT_SOURCE = 0x1500,
++ .RDS_INT_FIFO_COUNT = 0x1501,
++ .RDS_CONFIG = 0x1502,
++ .RX_VOLUME = 0x4000,
++ .RX_HARD_MUTE = 0x4001
++};
++
++#endif /* ifndef RADIO_SI4705_H */
+diff -urN linux.35.old/drivers/mmc/host/Kconfig linux.35.new/drivers/mmc/host/Kconfig
+--- linux.35.old/drivers/mmc/host/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/mmc/host/Kconfig 2010-12-03 09:51:55.436349742 +0100
+@@ -313,6 +313,34 @@
+
+ If unsure, or if your system has no SPI master driver, say N.
+
++config MMC_SDHCI_MXC
++ tristate "Freescale i.MX Secure Digital Host Controller Interface support"
++ depends on ARCH_MXC && MMC
++ help
++ This selects the Secure Digital Host Controller Interface (SDHCI)
++ on Freescale i.MX platforms.
++ If you have an i.MX platform with a Multimedia Card slot,
++ say Y or M here.
++
++ If unsure, say N.
++
++config MMC_SDHCI_MXC_SELECT2
++ bool "Enable second ESDHCI port"
++ depends on MMC_SDHCI_MXC && ARCH_MX25
++ help
++ Enable the second ESDHC port
++
++config MMC_SDHCI_MXC_PIO_MODE
++ bool "Freescale i.MX Secure Digital Host Controller Interface PIO mode"
++ depends on MMC_SDHCI_MXC
++ help
++ This set the Freescale i.MX Multimedia card Interface to PIO mode.
++ If you have a i.MX platform with a Multimedia Card slot,
++ and want test it with PIO mode.
++ say Y here.
++
++ If unsure, say N.
++
+ config MMC_S3C
+ tristate "Samsung S3C SD/MMC Card Interface support"
+ depends on ARCH_S3C2410
+diff -urN linux.35.old/drivers/mmc/host/Makefile linux.35.new/drivers/mmc/host/Makefile
+--- linux.35.old/drivers/mmc/host/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/mmc/host/Makefile 2010-12-03 09:51:55.436349742 +0100
+@@ -14,6 +14,7 @@
+ obj-$(CONFIG_MMC_SDHCI_PCI) += sdhci-pci.o
+ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
+ obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
++obj-$(CONFIG_MMC_SDHCI_MXC) += sdhci-mxc.o
+ obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
+ obj-$(CONFIG_MMC_WBSD) += wbsd.o
+ obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
+diff -urN linux.35.old/drivers/mmc/host/sdhci-mxc.c linux.35.new/drivers/mmc/host/sdhci-mxc.c
+--- linux.35.old/drivers/mmc/host/sdhci-mxc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mmc/host/sdhci-mxc.c 2010-12-28 11:05:01.467488497 +0100
+@@ -0,0 +1,2183 @@
++/*
++ * Copyright (C) 2009 Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * based on: mx_sdhci.c Copyright 2008-2009 Freescale Semiconductor, 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
++ * version 2 as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ *
++ * Driver for the Freescale Semiconductor MXC eSDHC controller
++ *
++ * This driver code is based on sdhci.c, by Pierre Ossman <drzeus@drzeus.cx>");
++ * This driver supports Enhanced Secure Digital Host Controller
++ * modules eSDHC of MXC. eSDHC is also referred as enhanced MMC/SD
++ * controller.
++ *
++ */
++
++#include <linux/delay.h>
++#include <linux/highmem.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++#include <linux/scatterlist.h>
++#include <linux/io.h>
++#include <linux/leds.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/card.h>
++#include <linux/clk.h>
++#include <linux/irq.h>
++#include <linux/slab.h>
++
++#include <mach/dma.h>
++#include <mach/hardware.h>
++#include <mach/sdhci.h>
++
++#include "sdhci-mxc.h"
++
++#ifdef DEBUG
++static int debug = 1;
++#define dbg_lvl(n) ((n) < debug)
++#define DBG(lvl, fmt...) do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++module_param(debug, int, S_IWUSR | S_IRUGO);
++#else
++static int debug;
++#define dbg_lvl(n) 0
++#define DBG(lvl, fmt...) do { } while (0)
++module_param(debug, int, 0);
++#endif
++
++#define DRIVER_NAME "sdhci"
++
++
++static unsigned int debug_quirks;
++module_param(debug_quirks, uint, S_IRUGO);
++MODULE_PARM_DESC(debug_quirks, "Force certain quirks");
++
++/*
++ * Different quirks to handle when the hardware deviates from a strict
++ * interpretation of the SDHCI specification.
++ */
++
++/* Controller doesn't honor resets unless we touch the clock register */
++#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1 << 0)
++/* Controller has bad caps bits, but really supports DMA */
++#define SDHCI_QUIRK_FORCE_DMA (1 << 1)
++/* Controller doesn't like to be reset when there is no card inserted. */
++#define SDHCI_QUIRK_NO_CARD_NO_RESET (1 << 2)
++/* Controller doesn't like clearing the power reg before a change */
++#define SDHCI_QUIRK_SINGLE_POWER_WRITE (1 << 3)
++/* Controller has flaky internal state so reset it on each ios change */
++#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1 << 4)
++/* Controller has an unusable DMA engine */
++#define SDHCI_QUIRK_BROKEN_DMA (1 << 5)
++/* Controller can only DMA from 32-bit aligned addresses */
++#define SDHCI_QUIRK_32BIT_DMA_ADDR (1 << 6)
++/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
++#define SDHCI_QUIRK_32BIT_DMA_SIZE (1 << 7)
++/* Controller needs to be reset after each request to stay stable */
++#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1 << 8)
++/* Controller needs voltage and power writes to happen separately */
++#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER (1 << 9)
++/* Controller has an off-by-one issue with timeout value */
++#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL (1 << 10)
++/* Controller only support the PIO */
++#define SDHCI_QUIRK_ONLY_PIO (1 << 16)
++/* Controller support the External DMA */
++#define SDHCI_QUIRK_EXTERNAL_DMA_MODE (1 << 17)
++/* Controller support the Internal Simple DMA */
++#define SDHCI_QUIRK_INTERNAL_SIMPLE_DMA (1 << 18)
++/* Controller support the Internal Advanced DMA */
++#define SDHCI_QUIRK_INTERNAL_ADVANCED_DMA (1 << 19)
++
++#define SDHCI_QUIRK_RESET_AFTER_READ (1 << 20)
++
++/*
++ * defines the mxc flags refer to the special hw pre-conditons and behavior
++ */
++#ifdef CONFIG_MMC_SDHCI_MXC_PIO_MODE
++static unsigned int debug_quirks = SDHCI_QUIRK_ONLY_PIO;
++#endif
++static unsigned int mxc_wml_value = 512;
++
++#ifndef MXC_SDHCI_NUM
++#define MXC_SDHCI_NUM 4
++#endif
++
++static struct sdhci_chip *mxc_fix_chips[MXC_SDHCI_NUM];
++
++static void sdhci_prepare_data(struct sdhci_host *, struct mmc_data *);
++static void sdhci_finish_data(struct sdhci_host *);
++
++static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
++static void sdhci_finish_command(struct sdhci_host *);
++static void sdhci_dma_irq(void *devid, int error, unsigned int cnt);
++
++#define platform_func(f, args...) ((f) ? (f)(args) : 0)
++
++void mxc_mmc_force_detect(int id)
++{
++ struct sdhci_host *host;
++
++ if ((id < 0) || (id >= MXC_SDHCI_NUM))
++ return;
++ if (!mxc_fix_chips[id])
++ return;
++ host = mxc_fix_chips[id]->hosts[0];
++ if (host->detect_irq >= 0)
++ return;
++
++ schedule_work(&host->cd_wq);
++ return;
++}
++EXPORT_SYMBOL(mxc_mmc_force_detect);
++
++#ifdef DEBUG
++#undef readl
++#undef writel
++#define readl(a) __readl(a, __FUNCTION__, __LINE__)
++#define writel(v,a) __writel(v, a, __FUNCTION__, __LINE__)
++
++static u32 __readl(void __iomem *addr,
++ const char *fn, unsigned int ln)
++{
++ u32 val;
++
++ DBG(2, "%s@%d: Reading reg %p\n", fn, ln, addr);
++ BUG_ON(addr < (void __iomem *)4096);
++ val = __raw_readl(addr);
++ DBG(2, "%s@%d: read %08x from reg %p\n", fn, ln, val, addr);
++ return val;
++}
++
++static void __writel(u32 val, void __iomem *addr,
++ const char *fn, unsigned int ln)
++{
++ DBG(2, "%s@%d: writing %08x to reg %p\n", fn, ln, val, addr);
++ BUG_ON(addr < (void __iomem *)4096);
++ __raw_writel(val, addr);
++}
++#endif
++
++static inline void sdhci_clk_enable(struct sdhci_host *host)
++{
++ if (host->clk_enable++) {
++ BUG_ON(host->clk_enable < 0);
++ return;
++ }
++ clk_enable(host->clk);
++}
++
++static inline void sdhci_clk_disable(struct sdhci_host *host)
++{
++ if (--host->clk_enable) {
++ BUG_ON(host->clk_enable < 0);
++ return;
++ }
++ clk_disable(host->clk);
++}
++
++static void sdhci_dumpregs(struct sdhci_host *host)
++{
++ sdhci_clk_enable(host);
++ DBG(1, "============== REGISTER DUMP ==============\n");
++
++ DBG(1, "Sys addr: 0x%08x | Version: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_DMA_ADDRESS),
++ readl(host->ioaddr + SDHCI_HOST_VERSION));
++ DBG(1, "Blk size: 0x%08x | Blk cnt: 0x%08x\n",
++ (readl(host->ioaddr + SDHCI_BLOCK_SIZE) & 0xFFFF),
++ (readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16));
++ DBG(1, "Argument: 0x%08x | Trn mode: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_ARGUMENT),
++ readl(host->ioaddr + SDHCI_TRANSFER_MODE));
++ DBG(1, "Present: 0x%08x | Host ctl: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_PRESENT_STATE),
++ readl(host->ioaddr + SDHCI_HOST_CONTROL));
++ DBG(1, "Clock: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_CLOCK_CONTROL));
++ DBG(1, "Int stat: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_INT_STATUS));
++ DBG(1, "Int enab: 0x%08x | Sig enab: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_INT_ENABLE),
++ readl(host->ioaddr + SDHCI_SIGNAL_ENABLE));
++ DBG(1, "Caps: 0x%08x\n",
++ readl(host->ioaddr + SDHCI_CAPABILITIES));
++
++ DBG(1, "===========================================\n");
++ sdhci_clk_disable(host);
++}
++
++/*****************************************************************************\
++ * *
++ * Low level functions *
++ * *
++\*****************************************************************************/
++
++static void sdhci_reset(struct sdhci_host *host, u8 mask)
++{
++ unsigned long tmp;
++ unsigned long mask_u32;
++ unsigned long reg_save = 0;
++
++ if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
++ if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
++ SDHCI_CARD_PRESENT))
++ return;
++ }
++
++ if (mask & SDHCI_RESET_ALL)
++ host->clock = 0;
++ else if (host->flags & SDHCI_CD_PRESENT)
++ reg_save = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++
++ tmp = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) | (mask << 24);
++ mask_u32 = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ writel(tmp, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ /* Wait max 100 ms */
++ tmp = 5000;
++
++ /* hw clears the bit when it's done */
++ while ((readl(host->ioaddr + SDHCI_CLOCK_CONTROL) >> 24) & mask) {
++ if (tmp == 0) {
++ printk(KERN_ERR "%s: Reset 0x%02x never completed\n",
++ mmc_hostname(host->mmc), mask);
++ sdhci_dumpregs(host);
++ return;
++ }
++ tmp--;
++ udelay(20);
++ }
++ /*
++ * The INT_EN SIG_EN regs have been modified after reset.
++ * re-configure them ag.
++ */
++ if (!(mask & SDHCI_RESET_ALL) && (host->flags & SDHCI_CD_PRESENT))
++ writel(reg_save, host->ioaddr + SDHCI_HOST_CONTROL);
++ if (host->flags & SDHCI_USE_DMA)
++ mask_u32 &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL);
++ if (mxc_wml_value == 512)
++ writel(SDHCI_WML_128_WORDS, host->ioaddr + SDHCI_WML);
++ else
++ writel(SDHCI_WML_16_WORDS, host->ioaddr + SDHCI_WML);
++ writel(mask_u32 | SDHCI_INT_CARD_INT, host->ioaddr + SDHCI_INT_ENABLE);
++ writel(mask_u32, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ host->last_op_dir = 0;
++}
++
++static void sdhci_init(struct sdhci_host *host)
++{
++ u32 intmask;
++
++ sdhci_reset(host, SDHCI_RESET_ALL);
++
++ intmask = SDHCI_INT_ADMA_ERROR |
++ SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC |
++ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
++ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
++ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
++ SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
++
++ if (host->flags & SDHCI_USE_DMA)
++ intmask &= ~(SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL);
++ /* Configure the WML reg */
++ if (mxc_wml_value == 512)
++ writel(SDHCI_WML_128_WORDS, host->ioaddr + SDHCI_WML);
++ else
++ writel(SDHCI_WML_16_WORDS, host->ioaddr + SDHCI_WML);
++ writel(intmask | SDHCI_INT_CARD_INT, host->ioaddr + SDHCI_INT_ENABLE);
++ writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++}
++
++static void sdhci_activate_led(struct sdhci_host *host)
++{
++ u32 ctrl;
++
++ ctrl = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++ ctrl |= SDHCI_CTRL_LED;
++ writel(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
++}
++
++static void sdhci_deactivate_led(struct sdhci_host *host)
++{
++ u32 ctrl;
++
++ ctrl = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++ ctrl &= ~SDHCI_CTRL_LED;
++ writel(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
++}
++
++/*****************************************************************************\
++ * *
++ * Core functions *
++ * *
++\*****************************************************************************/
++
++static inline char *sdhci_sg_to_buffer(struct sdhci_host *host)
++{
++ return sg_virt(host->cur_sg);
++}
++
++static inline int sdhci_next_sg(struct sdhci_host *host)
++{
++ /*
++ * Skip to next SG entry.
++ */
++ host->cur_sg++;
++ host->num_sg--;
++
++ /*
++ * Any entries left?
++ */
++ if (host->num_sg > 0) {
++ host->offset = 0;
++ host->remain = host->cur_sg->length;
++ }
++
++ return host->num_sg;
++}
++
++static void sdhci_read_block_pio(struct sdhci_host *host)
++{
++ int blksize, chunk_remain;
++ u32 data;
++ char *buffer;
++ int size;
++
++ DBG(3, "PIO reading\n");
++
++ blksize = host->data->blksz;
++ chunk_remain = 0;
++ data = 0;
++
++ buffer = sdhci_sg_to_buffer(host) + host->offset;
++
++ while (blksize) {
++ if (chunk_remain == 0) {
++ data = readl(host->ioaddr + SDHCI_BUFFER);
++ chunk_remain = min(blksize, 4);
++ }
++
++ size = min(host->remain, chunk_remain);
++
++ chunk_remain -= size;
++ blksize -= size;
++ host->offset += size;
++ host->remain -= size;
++
++ while (size) {
++ *buffer = data & 0xFF;
++ buffer++;
++ data >>= 8;
++ size--;
++ }
++
++ if (host->remain == 0) {
++ if (sdhci_next_sg(host) == 0) {
++ BUG_ON(blksize != 0);
++ return;
++ }
++ buffer = sdhci_sg_to_buffer(host);
++ }
++ }
++}
++
++static void sdhci_write_block_pio(struct sdhci_host *host)
++{
++ int blksize, chunk_remain;
++ u32 data;
++ char *buffer;
++ int bytes, size;
++
++ DBG(3, "PIO writing\n");
++
++ blksize = host->data->blksz;
++ chunk_remain = 4;
++ data = 0;
++
++ bytes = 0;
++ buffer = sdhci_sg_to_buffer(host) + host->offset;
++
++ while (blksize) {
++ size = min(host->remain, chunk_remain);
++
++ chunk_remain -= size;
++ blksize -= size;
++ host->offset += size;
++ host->remain -= size;
++
++ while (size) {
++ data >>= 8;
++ data |= (u32) *buffer << 24;
++ buffer++;
++ size--;
++ }
++
++ if (chunk_remain == 0) {
++ writel(data, host->ioaddr + SDHCI_BUFFER);
++ chunk_remain = min(blksize, 4);
++ }
++
++ if (host->remain == 0) {
++ if (sdhci_next_sg(host) == 0) {
++ BUG_ON(blksize != 0);
++ return;
++ }
++ buffer = sdhci_sg_to_buffer(host);
++ }
++ }
++}
++
++static void sdhci_transfer_pio(struct sdhci_host *host)
++{
++ u32 mask;
++
++ BUG_ON(!host->data);
++
++ if (host->num_sg == 0)
++ return;
++
++ if (host->data->flags & MMC_DATA_READ)
++ mask = SDHCI_DATA_AVAILABLE;
++ else
++ mask = SDHCI_SPACE_AVAILABLE;
++
++ while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
++ if (host->data->flags & MMC_DATA_READ)
++ sdhci_read_block_pio(host);
++ else
++ sdhci_write_block_pio(host);
++
++ if (host->num_sg == 0)
++ break;
++ }
++
++ DBG(3, "PIO transfer complete\n");
++}
++
++static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
++{
++ u32 count;
++ unsigned target_timeout;//, current_timeout;
++
++ WARN_ON(host->data);
++
++ if (data == NULL)
++ return;
++
++ /* Sanity checks */
++ BUG_ON(data->blksz * data->blocks > 524288);
++ BUG_ON(data->blksz > host->mmc->max_blk_size);
++ BUG_ON(data->blocks > 65535);
++
++ host->data = data;
++ host->data_early = 0;
++ if (host->data->flags & MMC_DATA_READ)
++ writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL) |
++ SDHCI_CLOCK_HLK_EN, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ /* timeout in us */
++ target_timeout = data->timeout_ns / 1000 +
++ data->timeout_clks / host->clock;
++#if 0
++ /*
++ * Figure out needed cycles.
++ * We do this in steps in order to fit inside a 32 bit int.
++ * The first step is the minimum timeout, which will have a
++ * minimum resolution of 6 bits:
++ * (1) 2^13*1000 > 2^22,
++ * (2) host->timeout_clk < 2^16
++ * =>
++ * (1) / (2) > 2^6
++ */
++ count = 0;
++ current_timeout = (1 << 13) * 1000 / host->timeout_clk;
++ while (current_timeout < target_timeout) {
++ count++;
++ current_timeout <<= 1;
++ if (count >= 0xF)
++ break;
++ }
++
++ /*
++ * Compensate for an off-by-one error in the CaFe hardware; otherwise,
++ * a too-small count gives us interrupt timeouts.
++ */
++ if ((host->chip->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
++ count++;
++
++ if (count >= 0xF) {
++ DBG(0, KERN_WARNING "%s: Too large timeout requested!\n",
++ mmc_hostname(host->mmc));
++ count = 0xE;
++ }
++#else
++ /* Set the max time-out value to level up the compatibility */
++ count = 0xE;
++#endif
++ count = (count << 16) | (readl(host->ioaddr + SDHCI_CLOCK_CONTROL) &
++ 0xFFF0FFFF);
++ writel(count, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ if (unlikely((host->flags & SDHCI_USE_DMA) &&
++ (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
++ ((data->blksz * data->blocks) & 0x3))) {
++ DBG(0, "Reverting to PIO because of transfer size (%d)\n",
++ data->blksz * data->blocks);
++ host->flags &= ~SDHCI_REQ_USE_DMA;
++ } else if (host->flags & SDHCI_USE_DMA) {
++ host->flags |= SDHCI_REQ_USE_DMA;
++ }
++
++ /*
++ * The assumption here being that alignment is the same after
++ * translation to device address space.
++ */
++ if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
++ (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
++ (data->sg->offset & 0x3))) {
++ DBG(0, "Reverting to PIO because of bad alignment\n");
++ host->flags &= ~SDHCI_REQ_USE_DMA;
++ }
++
++ if (host->flags & SDHCI_REQ_USE_DMA) {
++ int i;
++ struct scatterlist *tsg;
++
++ host->dma_size = data->blocks * data->blksz;
++ count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
++ (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE :
++ DMA_TO_DEVICE);
++ BUG_ON(count != data->sg_len);
++ DBG(2, "Configure the sg DMA, %s, len is 0x%08x, count is %d\n",
++ (data->flags & MMC_DATA_READ) ?
++ "DMA_FROM_DEVICE" : "DMA_TO_DEVICE", host->dma_size,
++ count);
++
++ /* Make sure the ADMA mode is selected. */
++ if (host->caps & (SDHCI_CAN_DO_ADMA1 | SDHCI_CAN_DO_ADMA2)) {
++ DBG(2, "%s: Enabling ADMA\n", __FUNCTION__);
++ i = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++ i |= SDHCI_CTRL_ADMA;
++ writel(i, host->ioaddr + SDHCI_HOST_CONTROL);
++ } else
++ goto single_dma;
++
++ tsg = data->sg;
++ /* ADMA mode is used, create the descriptor table */
++ for (i = 0; i < count; i++, tsg++) {
++ struct adma_desc *adma_desc = &host->adma_des_table[i];
++
++ if (tsg->dma_address & 0xFFF) {
++ printk(KERN_WARNING "ADMA addr isn't 4K aligned: 0x%08x\n",
++ tsg->dma_address);
++ printk(KERN_WARNING "Changed to Single DMA mode\n");
++ goto single_dma;
++ }
++ adma_desc->length = tsg->length;
++ adma_desc->attr = FSL_ADMA_DES_ATTR_SET |
++ FSL_ADMA_DES_ATTR_VALID;
++ adma_desc->dma_addr = tsg->dma_address |
++ FSL_ADMA_DES_ATTR_TRAN |
++ FSL_ADMA_DES_ATTR_VALID |
++ ((count == (i + 1)) ? FSL_ADMA_DES_ATTR_END : 0);
++ }
++
++ /* Write the physical address to ADMA address reg */
++ writel(virt_to_phys(host->adma_des_table),
++ host->ioaddr + SDHCI_ADMA_ADDRESS);
++ DBG(-1, "%s: ADMA addr: %08x(%08x)\n", __FUNCTION__,
++ readl(host->ioaddr + SDHCI_DMA_ADDRESS),
++ sg_dma_address(data->sg));
++ goto skip;
++ single_dma:
++ /* Rollback to the Single DMA mode */
++ i = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++ i &= ~SDHCI_CTRL_ADMA;
++ writel(i, host->ioaddr + SDHCI_HOST_CONTROL);
++ /* Single DMA mode is used */
++ skip:
++ writel(sg_dma_address(data->sg),
++ host->ioaddr + SDHCI_DMA_ADDRESS);
++ DBG(0, "%s: DMA addr: %08x(%08x)\n", __FUNCTION__,
++ readl(host->ioaddr + SDHCI_DMA_ADDRESS),
++ sg_dma_address(data->sg));
++ } else if ((host->flags & SDHCI_USE_EXTERNAL_DMA) &&
++ (data->blocks * data->blksz >= mxc_wml_value)) {
++ host->dma_size = data->blocks * data->blksz;
++ DBG(2, "Configure the External DMA, %s, len is 0x%08x\n",
++ (data->flags & MMC_DATA_READ) ?
++ "DMA_FROM_DEVICE" : "DMA_TO_DEVICE", host->dma_size);
++
++ if (data->blksz & 0x3) {
++ dev_err(mmc_dev(host->mmc),
++ "block size not multiple of 4 bytes\n");
++ }
++
++ 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);
++
++ if (data->flags & MMC_DATA_READ) {
++ mxc_dma_sg_config(host->dma, data->sg, data->sg_len,
++ host->dma_size, MXC_DMA_MODE_READ);
++ } else {
++ mxc_dma_sg_config(host->dma, data->sg, data->sg_len,
++ host->dma_size, MXC_DMA_MODE_WRITE);
++ }
++ } else {
++ host->cur_sg = data->sg;
++ host->num_sg = data->sg_len;
++
++ host->offset = 0;
++ host->remain = host->cur_sg->length;
++ }
++
++ /* We do not handle DMA boundaries, so set it to max (512 KiB) */
++ writel((data->blocks << 16) | SDHCI_MAKE_BLKSZ(7, data->blksz),
++ host->ioaddr + SDHCI_BLOCK_SIZE);
++}
++
++static void sdhci_finish_data(struct sdhci_host *host)
++{
++ struct mmc_data *data;
++ u16 blocks;
++
++ BUG_ON(!host->data);
++
++ data = host->data;
++ host->data = NULL;
++
++ if (host->flags & SDHCI_REQ_USE_DMA) {
++ dma_unmap_sg(&(host->chip->pdev)->dev, data->sg, data->sg_len,
++ (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE :
++ DMA_TO_DEVICE);
++ }
++ if ((host->flags & SDHCI_USE_EXTERNAL_DMA) &&
++ (host->dma_size >= mxc_wml_value) && (data != NULL)) {
++ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
++ host->dma_len, host->dma_dir);
++ host->dma_size = 0;
++ }
++
++ /*
++ * Controller doesn't count down when in single block mode.
++ */
++ if (data->blocks == 1)
++ blocks = (data->error == 0) ? 0 : 1;
++ else
++ blocks = readl(host->ioaddr + SDHCI_BLOCK_COUNT) >> 16;
++ data->bytes_xfered = data->blksz * data->blocks;
++
++ if (data->stop) {
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (data->error) {
++ sdhci_reset(host, SDHCI_RESET_CMD);
++ sdhci_reset(host, SDHCI_RESET_DATA);
++ }
++
++ sdhci_send_command(host, data->stop);
++ } else
++ tasklet_schedule(&host->finish_tasklet);
++}
++
++static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
++{
++ int flags;
++ u32 mask;
++ u32 mode = 0;
++ unsigned long timeout;
++
++ DBG(2, "sdhci_send_command 0x%08x is starting...\n", cmd->opcode);
++ WARN_ON(host->cmd);
++
++ /* Wait max 10 ms */
++ timeout = 5000;
++
++ mask = SDHCI_CMD_INHIBIT;
++ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
++ mask |= SDHCI_DATA_INHIBIT;
++
++ /* We shouldn't wait for data inihibit for stop commands, even
++ though they might use busy signaling */
++ if (host->mrq->data && (cmd == host->mrq->data->stop))
++ mask &= ~SDHCI_DATA_INHIBIT;
++
++ while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
++ if (timeout == 0) {
++ printk(KERN_ERR "%s: Controller never released "
++ "inhibit bit(s)\n", mmc_hostname(host->mmc));
++ sdhci_dumpregs(host);
++ cmd->error = -EIO;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++ timeout--;
++ udelay(20);
++ }
++
++ mod_timer(&host->timer, jiffies + 1 * HZ);
++
++ host->cmd = cmd;
++
++ sdhci_prepare_data(host, cmd->data);
++
++ writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
++
++ /* Set up the transfer mode */
++ if (cmd->data != NULL) {
++ mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_DPSEL;
++ if (cmd->data->blocks > 1)
++ mode |= SDHCI_TRNS_MULTI;
++ if (cmd->data->flags & MMC_DATA_READ)
++ mode |= SDHCI_TRNS_READ;
++ else
++ mode &= ~SDHCI_TRNS_READ;
++ if (host->flags & SDHCI_USE_DMA)
++ mode |= SDHCI_TRNS_DMA;
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA)
++ DBG(2, "Prepare data complete in EXTERNAL DMA transfer mode\n");
++ }
++
++ if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
++ printk(KERN_ERR "%s: Unsupported response type!\n",
++ mmc_hostname(host->mmc));
++ cmd->error = -EINVAL;
++ tasklet_schedule(&host->finish_tasklet);
++ return;
++ }
++
++ if (!(cmd->flags & MMC_RSP_PRESENT))
++ flags = SDHCI_CMD_RESP_NONE;
++ else if (cmd->flags & MMC_RSP_136)
++ flags = SDHCI_CMD_RESP_LONG;
++ else if (cmd->flags & MMC_RSP_BUSY)
++ flags = SDHCI_CMD_RESP_SHORT_BUSY;
++ else
++ flags = SDHCI_CMD_RESP_SHORT;
++
++ if (cmd->flags & MMC_RSP_CRC)
++ flags |= SDHCI_CMD_CRC;
++ if (cmd->flags & MMC_RSP_OPCODE)
++ flags |= SDHCI_CMD_INDEX;
++ if (cmd->data)
++ flags |= SDHCI_CMD_DATA;
++
++ mode |= SDHCI_MAKE_CMD(cmd->opcode, flags);
++ DBG(2, "Complete sending cmd, transfer mode 0x%08x\n", mode);
++ writel(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
++}
++
++static void sdhci_finish_command(struct sdhci_host *host)
++{
++ int i;
++
++ BUG_ON(host->cmd == NULL);
++
++ if (host->cmd->flags & MMC_RSP_PRESENT) {
++ if (host->cmd->flags & MMC_RSP_136) {
++ /* CRC is stripped so we need to do some shifting. */
++ for (i = 0; i < 4; i++) {
++ host->cmd->resp[i] = readl(host->ioaddr +
++ SDHCI_RESPONSE + (3 -
++ i)
++ * 4) << 8;
++ if (i != 3)
++ host->cmd->resp[i] |=
++ readb(host->ioaddr +
++ SDHCI_RESPONSE + (3 - i) * 4 -
++ 1);
++ }
++ } else {
++ host->cmd->resp[0] =
++ readl(host->ioaddr + SDHCI_RESPONSE);
++ }
++ }
++
++ host->cmd->error = 0;
++
++ if (host->data && host->data_early)
++ sdhci_finish_data(host);
++
++ if (!host->cmd->data)
++ tasklet_schedule(&host->finish_tasklet);
++
++ host->cmd = NULL;
++}
++
++static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
++{
++ /*This variable holds the value of clock divider, prescaler */
++ int div = 0, prescaler = 0;
++ int clk_rate;
++ u32 clk;
++
++ if (clock == 0) {
++ goto out;
++ } else {
++ sdhci_clk_enable(host);
++ }
++ if (clock == host->clock)
++ return;
++
++ clk_rate = clk_get_rate(host->clk);
++ clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK;
++ writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ if (clock == host->min_clk)
++ prescaler = 16;
++ else
++ prescaler = 0;
++ while (prescaler <= 0x80) {
++ for (div = 0; div <= 0xF; div++) {
++ int x;
++ if (prescaler != 0)
++ x = (clk_rate / (div + 1)) / (prescaler * 2);
++ else
++ x = clk_rate / (div + 1);
++
++ DBG(2, "x=%d, clock=%d %d\n", x, clock, div);
++ if (x <= clock)
++ break;
++ }
++ if (div < 0x10)
++ break;
++ if (prescaler == 0)
++ prescaler = 1;
++ else
++ prescaler <<= 1;
++ }
++ DBG(0, "prescaler = 0x%08x, divider = 0x%08x\n", prescaler, div);
++ clk |= (prescaler << 8) | (div << 4);
++
++ /* Configure the clock control register */
++ clk |= (readl(host->ioaddr + SDHCI_CLOCK_CONTROL) & ~SDHCI_CLOCK_MASK);
++ if (host->vendor_ver < ESDHC_VENDOR_V22)
++ writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
++ else
++ writel(clk | SDHCI_CLOCK_SD_EN,
++ host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ /* Wait max 10 ms */
++#if 1
++ msleep(10);
++#else
++ {
++ unsigned long timeout;
++ timeout = 5000;
++ while (timeout > 0) {
++ timeout--;
++ udelay(20);
++ }
++ }
++#endif
++out:
++ host->clock = clock;
++}
++
++static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
++{
++ /* There is no PWR CTL REG */
++ if (host->power == power)
++ return;
++ if (platform_func(host->plat_data->setpower, host->mmc->parent, power) == 0)
++ host->power = power;
++}
++
++/*****************************************************************************\
++ * *
++ * MMC callbacks *
++ * *
++\*****************************************************************************/
++
++static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct sdhci_host *host;
++ unsigned long flags;
++
++ host = mmc_priv(mmc);
++
++ /* Enable the clock */
++ sdhci_clk_enable(host);
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ WARN_ON(host->mrq != NULL);
++
++ sdhci_activate_led(host);
++
++ if (host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_READ) {
++ if (mrq->cmd && mrq->data) {
++ if (mrq->data->flags & MMC_DATA_READ)
++ host->last_op_dir = 1;
++ else {
++ if (host->last_op_dir) {
++ DBG(0, "%s: Resetting SDHCI controller\n",
++ __FUNCTION__);
++ sdhci_reset(host,
++ SDHCI_RESET_CMD |
++ SDHCI_RESET_DATA);
++ }
++ }
++ }
++ }
++
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA)
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ host->mrq = mrq;
++ if (!(host->flags & SDHCI_CD_PRESENT)) {
++ host->mrq->cmd->error = -ENOMEDIUM;
++ tasklet_schedule(&host->finish_tasklet);
++ } else
++ sdhci_send_command(host, mrq->cmd);
++
++ if (!(host->flags & SDHCI_USE_EXTERNAL_DMA))
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ mmiowb();
++}
++
++static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ struct sdhci_host *host;
++ unsigned long flags;
++ u32 tmp;
++ mxc_dma_device_t dev_id = 0;
++
++ DBG(0, "%s: clock %u, bus %lu, power %u, vdd %u\n", __FUNCTION__,
++ ios->clock, 1UL << ios->bus_width, ios->power_mode, ios->vdd);
++
++ host = mmc_priv(mmc);
++
++ /* Configure the External DMA mode */
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA) {
++ host->dma_dir = DMA_NONE;
++ if (mmc->ios.bus_width != host->mode) {
++ mxc_dma_free(host->dma);
++ if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
++ if (host->id == 0)
++ dev_id = MXC_DMA_MMC1_WIDTH_4;
++ else
++ dev_id = MXC_DMA_MMC2_WIDTH_4;
++ } else {
++ if (host->id == 0)
++ dev_id = MXC_DMA_MMC1_WIDTH_1;
++ else
++ dev_id = MXC_DMA_MMC2_WIDTH_1;
++ }
++ host->dma = mxc_dma_request(dev_id, "MXC MMC");
++ if (host->dma < 0) {
++ printk(KERN_ERR "Cannot allocate MMC DMA channel\n");
++ return;
++ }
++ mxc_dma_callback_set(host->dma, sdhci_dma_irq,
++ host);
++ /* Configure the WML rege */
++ if (mxc_wml_value == 512)
++ writel(SDHCI_WML_128_WORDS,
++ host->ioaddr + SDHCI_WML);
++ else
++ writel(SDHCI_WML_16_WORDS,
++ host->ioaddr + SDHCI_WML);
++ }
++ }
++
++ host->mode = mmc->ios.bus_width;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ /*
++ * Reset the chip on each power off.
++ * Should clear out any weird states.
++ */
++ if (ios->power_mode == MMC_POWER_OFF) {
++ writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ sdhci_init(host);
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++ sdhci_set_clock(host, ios->clock);
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (ios->power_mode == MMC_POWER_OFF)
++ sdhci_set_power(host, -1);
++ else {
++ sdhci_set_power(host, ios->vdd);
++ if (!readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)) {
++ tmp = readl(host->ioaddr + SDHCI_INT_ENABLE);
++ if (host->sdio_enable)
++ writel(tmp, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ else
++ writel(tmp & ~SDHCI_INT_CARD_INT,
++ host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ }
++ }
++
++ tmp = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++
++ if (ios->bus_width == MMC_BUS_WIDTH_4) {
++ tmp &= ~SDHCI_CTRL_8BITBUS;
++ tmp |= SDHCI_CTRL_4BITBUS;
++ } else if (ios->bus_width == MMC_BUS_WIDTH_8) {
++ tmp &= ~SDHCI_CTRL_4BITBUS;
++ tmp |= SDHCI_CTRL_8BITBUS;
++ } else if (ios->bus_width == MMC_BUS_WIDTH_1) {
++ tmp &= ~SDHCI_CTRL_4BITBUS;
++ tmp &= ~SDHCI_CTRL_8BITBUS;
++ }
++
++ if (host->flags & SDHCI_USE_DMA)
++ tmp |= SDHCI_CTRL_ADMA;
++
++ writel(tmp, host->ioaddr + SDHCI_HOST_CONTROL);
++
++ /*
++ * Some (ENE) controllers go apeshit on some ios operation,
++ * signalling timeout and CRC errors even on CMD0. Resetting
++ * it on each ios seems to solve the problem.
++ */
++ if (host->chip->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
++ sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static int sdhci_get_ro(struct mmc_host *mmc)
++{
++ struct sdhci_host *host = mmc_priv(mmc);
++ return platform_func(host->plat_data->get_ro, mmc->parent);
++}
++
++static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ struct sdhci_host *host = mmc_priv(mmc);
++ unsigned long flags;
++ u32 ier, prot, clk, present;
++
++ if (enable) {
++ if (host->sdio_enable++)
++ return;
++ } else {
++ if (--(host->sdio_enable))
++ return;
++ }
++ /* Enable the clock */
++ sdhci_clk_enable(host);
++ spin_lock_irqsave(&host->lock, flags);
++
++ ier = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ prot = readl(host->ioaddr + SDHCI_HOST_CONTROL);
++ clk = readl(host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ if (enable) {
++ ier |= SDHCI_INT_CARD_INT;
++ prot |= SDHCI_CTRL_D3CD;
++ clk |= SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN;
++ present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
++ if ((present & SDHCI_CARD_INT_MASK) != SDHCI_CARD_INT_ID)
++ writel(SDHCI_INT_CARD_INT,
++ host->ioaddr + SDHCI_INT_STATUS);
++ } else {
++ ier &= ~SDHCI_INT_CARD_INT;
++ prot &= ~SDHCI_CTRL_D3CD;
++ clk &= ~(SDHCI_CLOCK_PER_EN | SDHCI_CLOCK_IPG_EN);
++ }
++
++ writel(prot, host->ioaddr + SDHCI_HOST_CONTROL);
++ writel(ier, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ writel(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
++
++ mmiowb();
++
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static const struct mmc_host_ops sdhci_ops = {
++ .request = sdhci_request,
++ .set_ios = sdhci_set_ios,
++ .get_ro = sdhci_get_ro,
++ .enable_sdio_irq = sdhci_enable_sdio_irq,
++};
++
++/*****************************************************************************\
++ * *
++ * Tasklets *
++ * *
++\*****************************************************************************/
++
++static void sdhci_tasklet_card(unsigned long param)
++{
++ struct sdhci_host *host = (struct sdhci_host *)param;
++ unsigned long flags;
++
++ if (host->flags & SDHCI_CD_PRESENT)
++ host->flags &= ~SDHCI_CD_PRESENT;
++ else
++ host->flags |= SDHCI_CD_PRESENT;
++ /* Detect there is a card in slot or not */
++ DBG(0, "cd_status=%s\n", (host->flags & SDHCI_CD_PRESENT) ? "inserted" : "removed");
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (!(host->flags & SDHCI_CD_PRESENT)) {
++ if (host->mrq) {
++ printk(KERN_ERR "%s: Card removed during transfer!\n",
++ mmc_hostname(host->mmc));
++ printk(KERN_ERR "%s: Resetting controller\n",
++ mmc_hostname(host->mmc));
++
++ sdhci_reset(host, SDHCI_RESET_CMD);
++ sdhci_reset(host, SDHCI_RESET_DATA);
++
++ host->mrq->cmd->error = -ENOMEDIUM;
++ tasklet_schedule(&host->finish_tasklet);
++ }
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ mmc_detect_change(host->mmc,
++ msecs_to_jiffies(host->plat_data->detect_delay));
++}
++
++static void sdhci_tasklet_finish(unsigned long param)
++{
++ struct sdhci_host *host = (struct sdhci_host *)param;
++ unsigned long flags;
++ struct mmc_request *mrq;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ del_timer(&host->timer);
++
++ mrq = host->mrq;
++
++ /*
++ * The controller needs a reset of internal state machines
++ * upon error conditions.
++ */
++ if (mrq->cmd->error ||
++ (mrq->data && (mrq->data->error ||
++ (mrq->data->stop && mrq->data->stop->error))) ||
++ (host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
++ /* Some controllers need this kick or reset won't work here */
++ if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
++ unsigned int clock;
++
++ /* This is to force an update */
++ clock = host->clock;
++ host->clock = 0;
++ spin_unlock_irqrestore(&host->lock, flags);
++ sdhci_set_clock(host, clock);
++ spin_lock_irqsave(&host->lock, flags);
++ }
++
++ /* Spec says we should do both at the same time, but Ricoh
++ controllers do not like that. */
++ sdhci_reset(host, SDHCI_RESET_CMD);
++ sdhci_reset(host, SDHCI_RESET_DATA);
++ }
++
++ host->mrq = NULL;
++ host->cmd = NULL;
++ host->data = NULL;
++
++ sdhci_deactivate_led(host);
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ /* Stop the clock when the req is done */
++ flags = SDHCI_DATA_ACTIVE | SDHCI_DOING_WRITE | SDHCI_DOING_READ;
++ if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & flags)) {
++ sdhci_clk_disable(host);
++ }
++
++ mmc_request_done(host->mmc, mrq);
++}
++
++static void sdhci_timeout_timer(unsigned long data)
++{
++ struct sdhci_host *host = (struct sdhci_host *)data;
++ unsigned long tmp, flags;
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (host->mrq) {
++ printk(KERN_ERR "%s: Timeout waiting for hardware interrupt\n",
++ mmc_hostname(host->mmc));
++ sdhci_dumpregs(host);
++
++ if (host->data) {
++ host->data->error = -ETIMEDOUT;
++ sdhci_finish_data(host);
++ } else {
++ if (host->cmd)
++ host->cmd->error = -ETIMEDOUT;
++ else
++ host->mrq->cmd->error = -ETIMEDOUT;
++
++ tasklet_schedule(&host->finish_tasklet);
++ }
++
++ if (!readl(host->ioaddr + SDHCI_SIGNAL_ENABLE)) {
++ printk(KERN_ERR "%s, ERROR SIG_INT is 0\n", __func__);
++ tmp = readl(host->ioaddr + SDHCI_INT_ENABLE);
++ if (host->sdio_enable)
++ writel(tmp, host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ else
++ writel(tmp & ~SDHCI_INT_CARD_INT,
++ host->ioaddr + SDHCI_SIGNAL_ENABLE);
++ if (!host->plat_data->status(host->mmc->parent))
++ schedule_work(&host->cd_wq);
++ }
++ }
++
++ mmiowb();
++ spin_unlock_irqrestore(&host->lock, flags);
++}
++
++static void sdhci_cd_timer(unsigned long data)
++{
++ struct sdhci_host *host = (struct sdhci_host *)data;
++ schedule_work(&host->cd_wq);
++}
++
++/*****************************************************************************\
++ * *
++ * Interrupt handling *
++ * *
++\*****************************************************************************/
++
++static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
++{
++ BUG_ON(intmask == 0);
++
++ if (!host->cmd) {
++ printk(KERN_ERR "%s: Got command interrupt 0x%08x even though no command operation was in progress\n",
++ mmc_hostname(host->mmc), intmask);
++ sdhci_dumpregs(host);
++ return;
++ }
++
++ if (intmask & SDHCI_INT_TIMEOUT)
++ host->cmd->error = -ETIMEDOUT;
++ else if (intmask & (SDHCI_INT_CRC | SDHCI_INT_END_BIT |
++ SDHCI_INT_INDEX))
++ host->cmd->error = -EILSEQ;
++
++ if (host->cmd->error)
++ tasklet_schedule(&host->finish_tasklet);
++ else if (intmask & SDHCI_INT_RESPONSE)
++ sdhci_finish_command(host);
++}
++
++static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
++{
++ u32 intsave = 0;
++
++ BUG_ON(intmask == 0);
++
++ if (!host->data) {
++ /*
++ * A data end interrupt is sent together with the response
++ * for the stop command.
++ */
++ if (intmask & SDHCI_INT_DATA_END)
++ return;
++
++ printk(KERN_ERR "%s: Got data interrupt 0x%08x even "
++ "though no data operation was in progress\n",
++ mmc_hostname(host->mmc), (unsigned)intmask);
++ sdhci_dumpregs(host);
++ sdhci_reset(host, SDHCI_RESET_CMD);
++ sdhci_reset(host, SDHCI_RESET_DATA);
++ return;
++ }
++
++ /* Mask the INT */
++ intsave = readl(host->ioaddr + SDHCI_INT_ENABLE);
++ writel(intsave & (~(intmask & SDHCI_INT_DATA_RE_MASK)),
++ host->ioaddr + SDHCI_INT_ENABLE);
++
++ if (intmask & SDHCI_INT_DATA_TIMEOUT)
++ host->data->error = -ETIMEDOUT;
++ else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
++ host->data->error = -EILSEQ;
++
++ if (host->data->error)
++ sdhci_finish_data(host);
++ else {
++ if ((host->flags & SDHCI_USE_EXTERNAL_DMA) &&
++ (host->dma_size >= mxc_wml_value)) {
++ /* Use DMA if transfer size is greater than fifo size */
++ if (intmask & (SDHCI_INT_DATA_AVAIL |
++ SDHCI_INT_SPACE_AVAIL)) {
++ intsave &= ~SDHCI_INT_DATA_RE_MASK;
++ if (mxc_dma_enable(host->dma) < 0) {
++ printk(KERN_ERR "ENABLE SDMA ERR\n");
++ intsave |= SDHCI_INT_DATA_RE_MASK;
++ }
++ }
++ } else {
++ if (intmask & (SDHCI_INT_DATA_AVAIL |
++ SDHCI_INT_SPACE_AVAIL))
++ sdhci_transfer_pio(host);
++ }
++
++ /*
++ * We currently don't do anything fancy with DMA
++ * boundaries, but as we can't disable the feature
++ * we need to at least restart the transfer.
++ */
++ if ((intmask & SDHCI_INT_DMA_END) &&
++ (!(intmask & SDHCI_INT_DATA_END)))
++ writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
++ host->ioaddr + SDHCI_DMA_ADDRESS);
++
++ if (intmask & SDHCI_INT_DATA_END) {
++ if (host->data->flags & MMC_DATA_READ)
++ writel(readl(host->ioaddr + SDHCI_CLOCK_CONTROL)
++ & ~SDHCI_CLOCK_HLK_EN,
++ host->ioaddr + SDHCI_CLOCK_CONTROL);
++ if (host->cmd) {
++ /*
++ * Data managed to finish before the
++ * command completed. Make sure we do
++ * things in the proper order.
++ */
++ host->data_early = 1;
++ } else {
++
++ if (host->vendor_ver < ESDHC_VENDOR_V22) {
++ /*
++ * There are the DATA END INT when
++ * writing is not complete. Double
++ * check on it. TO2 has been fixed it.
++ */
++ intmask = readl(host->ioaddr +
++ SDHCI_PRESENT_STATE);
++ if (intmask & SDHCI_DATA_ACTIVE)
++ goto data_irq_out;
++ }
++ sdhci_finish_data(host);
++ }
++ }
++ }
++ data_irq_out:
++ /* Enable the INT */
++ writel(intsave, host->ioaddr + SDHCI_INT_ENABLE);
++}
++
++/*!
++* This function is called by DMA Interrupt Service Routine to indicate
++* requested DMA transfer is completed.
++*
++* @param devid pointer to device specific structure
++* @param error any DMA error
++* @param cnt amount of data that was transferred
++*/
++static void sdhci_dma_irq(void *devid, int error, unsigned int cnt)
++{
++ u32 intsave = 0;
++ int ret;
++ struct sdhci_host *host = devid;
++
++ DBG(0, "%s: error: %d Transferred bytes: %d\n", __FUNCTION__, error, cnt);
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA) {
++ /*
++ * Stop the DMA transfer here, the data_irq will be called
++ * to process the others
++ */
++ ret = mxc_dma_disable(host->dma);
++ if (ret < 0)
++ printk(KERN_ERR "Disable dma channel err %d\n", ret);
++
++ if (error) {
++ DBG(0, "Error in DMA transfer\n");
++ return;
++ }
++ intsave = readl(host->ioaddr + SDHCI_INT_ENABLE);
++ intsave |= SDHCI_INT_DATA_RE_MASK;
++ writel(intsave, host->ioaddr + SDHCI_INT_ENABLE);
++ }
++}
++
++static void esdhc_cd_callback(struct work_struct *work)
++{
++ struct sdhci_host *host = container_of(work, struct sdhci_host, cd_wq);
++ unsigned long flags;
++ unsigned int cd_status = 0;
++
++ if(host->plat_data->force_sd_detect == 0) { // bypass hw cd
++ cd_status = host->plat_data->status(host->mmc->parent);
++ if (cd_status)
++ host->flags &= ~SDHCI_CD_PRESENT;
++ else
++ host->flags |= SDHCI_CD_PRESENT;
++ } else {
++ host->flags |= SDHCI_CD_PRESENT;
++ }
++
++ /* Detect, if there is a card in slot or not */
++ DBG(0, "cd_status=%d %s\n", cd_status,
++ (host->flags & SDHCI_CD_PRESENT) ? "inserted" : "removed");
++
++ spin_lock_irqsave(&host->lock, flags);
++
++ if (!(host->flags & SDHCI_CD_PRESENT)) {
++ dev_info(mmc_dev(host->mmc),
++ "Card removed and resetting controller\n");
++ if (host->mrq) {
++ struct mmc_data *data;
++ data = host->data;
++ host->data = NULL;
++
++ dev_err(mmc_dev(host->mmc),
++ "Card removed during transfer!\n");
++
++ if ((host->flags & SDHCI_USE_EXTERNAL_DMA) &&
++ (data != NULL)) {
++ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
++ host->dma_len, host->dma_dir);
++ host->dma_size = 0;
++ }
++ sdhci_reset(host, SDHCI_RESET_CMD);
++ sdhci_reset(host, SDHCI_RESET_DATA);
++
++ host->mrq->cmd->error = -ENOMEDIUM;
++ tasklet_schedule(&host->finish_tasklet);
++ }
++
++ if (host->init_flag > 0)
++ /* The initialization of sdhc controller has been
++ * done in the resume func */
++ host->init_flag--;
++ else
++ sdhci_init(host);
++ }
++
++ spin_unlock_irqrestore(&host->lock, flags);
++
++ if (host->flags & SDHCI_CD_PRESENT) {
++ del_timer(&host->cd_timer);
++ mmc_detect_change(host->mmc,
++ msecs_to_jiffies(host->plat_data->detect_delay));
++ } else
++ mmc_detect_change(host->mmc, 0);
++}
++
++/*!
++* Card detection interrupt service routine registered to handle
++* the SDHC interrupts. This interrupt routine handles card
++* insertion and card removal interrupts.
++*
++* @param irq the interrupt number
++* @param devid driver private data
++*
++* @return The function returns \b IRQ_RETVAL(1)
++*/
++static irqreturn_t sdhci_cd_irq(int irq, void *dev_id)
++{
++ struct mmc_host *mmc = dev_id;
++ struct sdhci_host *host = mmc_priv(mmc);
++
++ dev_dbg(mmc_dev(mmc), "%s\n", __func__);
++
++ schedule_work(&host->cd_wq);
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t sdhci_irq(int irq, void *dev_id)
++{
++ irqreturn_t result;
++ struct sdhci_host *host = dev_id;
++ u32 intmask;
++ int cardint = 0;
++
++ BUG_ON(!host);
++ BUG_ON(!host->ioaddr);
++ spin_lock(&host->lock);
++
++ intmask = readl(host->ioaddr + SDHCI_INT_STATUS);
++
++ if (!intmask || intmask == 0xffffffff) {
++ result = IRQ_NONE;
++ goto out;
++ }
++
++ DBG(3, "*** %s got interrupt: 0x%08x\n",
++ mmc_hostname(host->mmc), intmask);
++
++ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
++ writel(intmask &
++ (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
++ host->ioaddr + SDHCI_INT_STATUS);
++ tasklet_schedule(&host->card_tasklet);
++ }
++
++ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
++
++ if (intmask & SDHCI_INT_CMD_MASK) {
++ writel(intmask & SDHCI_INT_CMD_MASK,
++ host->ioaddr + SDHCI_INT_STATUS);
++ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
++ }
++
++ if (intmask & SDHCI_INT_DATA_MASK) {
++ writel(intmask & SDHCI_INT_DATA_MASK,
++ host->ioaddr + SDHCI_INT_STATUS);
++#ifdef CONFIG_ARCH_MX35
++ if (mx35_revision() < MX35_CHIP_REV_2_0) {
++ if (!(readl(host->ioaddr + SDHCI_TRANSFER_MODE) &
++ SDHCI_TRNS_READ))
++ intmask &= ~SDHCI_INT_DATA_END_BIT;
++ }
++#endif
++ if (intmask & SDHCI_INT_DATA_MASK)
++ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
++ }
++
++ intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
++ intmask &= ~SDHCI_INT_ERROR;
++
++ if (intmask & SDHCI_INT_BUS_POWER) {
++ printk(KERN_ERR "%s: Card is consuming too much power!\n",
++ mmc_hostname(host->mmc));
++ writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
++ }
++
++ intmask &= ~SDHCI_INT_BUS_POWER;
++
++ if (intmask & SDHCI_INT_CARD_INT)
++ cardint = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE) &
++ SDHCI_INT_CARD_INT;
++
++ intmask &= ~SDHCI_INT_CARD_INT;
++
++ if (intmask) {
++ printk(KERN_ERR "%s: Unexpected interrupt 0x%08x\n",
++ mmc_hostname(host->mmc), intmask);
++ sdhci_dumpregs(host);
++
++ writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
++ }
++
++ result = IRQ_HANDLED;
++
++ mmiowb();
++out:
++ spin_unlock(&host->lock);
++
++ /*
++ * We have to delay this as it calls back into the driver.
++ */
++ if (cardint)
++ mmc_signal_sdio_irq(host->mmc);
++
++ return result;
++}
++
++/*****************************************************************************\
++ * *
++ * Suspend/resume *
++ * *
++\*****************************************************************************/
++
++#ifdef CONFIG_PM
++static int sdhci_suspend(struct device *dev)
++{
++ struct sdhci_chip *chip;
++ int i, ret;
++
++ chip = dev_get_drvdata(dev);
++ if (!chip)
++ return 0;
++
++ DBG(0, "Suspending...\n");
++
++ for (i = 0; i < chip->num_slots; i++) {
++ if (!chip->hosts[i])
++ continue;
++ ret = mmc_suspend_host(chip->hosts[i]->mmc);
++ if (ret) {
++ for (i--; i >= 0; i--)
++ mmc_resume_host(chip->hosts[i]->mmc);
++ return ret;
++ }
++ }
++
++ for (i = 0; i < chip->num_slots; i++) {
++ struct sdhci_host *host = chip->hosts[i];
++
++ if (host == NULL)
++ continue;
++ free_irq(host->irq, host);
++ ret = platform_func(host->plat_data->suspend, dev);
++ }
++
++ return ret;
++}
++
++static int sdhci_resume(struct device *dev)
++{
++ struct sdhci_chip *chip;
++ int i, ret;
++
++ chip = dev_get_drvdata(dev);
++ if (!chip)
++ return 0;
++
++ DBG(0, "Resuming...\n");
++
++ for (i = 0; i < chip->num_slots; i++) {
++ struct sdhci_host *host = chip->hosts[i];
++
++ if (host == NULL)
++ continue;
++
++ ret = platform_func(host->plat_data->resume, dev);
++ if (ret) {
++ return ret;
++ }
++ ret = request_irq(host->irq, sdhci_irq, 0,
++ mmc_hostname(host->mmc),
++ host);
++ if (ret)
++ return ret;
++ sdhci_init(host);
++ host->init_flag = 2;
++ mmiowb();
++ ret = mmc_resume_host(host->mmc);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++#else /* CONFIG_PM */
++#define sdhci_suspend NULL
++#define sdhci_resume NULL
++#endif /* CONFIG_PM */
++
++static ssize_t
++mmc_mxc_show_force_cd(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
++ struct sdhci_host *host = mmc_priv(mmc);
++ struct mxc_sdhci_platform_data *pdata = host->plat_data;
++
++ return sprintf(buf, "%d\n", pdata->force_sd_detect);
++}
++
++static ssize_t
++mmc_mxc_store_force_cd(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
++ struct sdhci_host *host = mmc_priv(mmc);
++ struct mxc_sdhci_platform_data *pdata = host->plat_data;
++
++ if(count != 2) return count;
++
++ switch(buf[0]) {
++ default :
++ case '0': pdata->force_sd_detect = 0;
++ break;
++ case '1': pdata->force_sd_detect = 1;
++ break;
++ };
++
++ schedule_work(&host->cd_wq);
++ return count;
++}
++
++static DEVICE_ATTR(force_cd, S_IRUGO | S_IWUGO, mmc_mxc_show_force_cd, mmc_mxc_store_force_cd);
++
++
++/*****************************************************************************\
++ * *
++ * Device probing/removal *
++ * *
++\*****************************************************************************/
++
++static int __devinit sdhci_probe_slot(struct platform_device *pdev,
++ struct sdhci_chip *chip, int slot)
++{
++ struct mxc_sdhci_platform_data *mmc_plat = pdev->dev.platform_data;
++ int ret = 0;
++ unsigned int version;
++ struct mmc_host *mmc;
++ struct sdhci_host *host;
++ mxc_dma_device_t dev_id = 0;
++
++ dev_dbg(&pdev->dev, "%s: Init slot %d on chip %p\n",
++ __FUNCTION__, slot, chip);
++ if (!mmc_plat)
++ return -ENODEV;
++
++ mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
++ if (!mmc)
++ return -ENOMEM;
++
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ host->id = pdev->id;
++ host->dma = -1;
++ host->plat_data = mmc_plat;
++
++ host->chip = chip;
++ chip->hosts[slot] = host;
++
++ /* Active the eSDHC bus */
++ ret = platform_func(mmc_plat->init, &pdev->dev, sdhci_cd_irq,
++ host->mmc);
++ if (ret) {
++ DBG(0, "%s: Platform init failed: %d\n", __FUNCTION__, ret);
++ goto out1;
++ }
++
++ /* Get the SDHC clock from clock system APIs */
++ host->clk = clk_get(&pdev->dev, "esdhc_clk");
++ if (IS_ERR(host->clk)) {
++ dev_err(&pdev->dev, "failed to get clock esdhc_clk\n");
++ ret = PTR_ERR(host->clk);
++ goto out1a;
++ }
++ DBG(0, "SDHC: %d clock: %lu\n", pdev->id, clk_get_rate(host->clk));
++
++ host->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!host->res) {
++ ret = -ENODEV;
++ goto out2;
++ }
++
++ host->irq = platform_get_irq(pdev, 0);
++ if (host->irq < 0) {
++ ret = -ENODEV;
++ goto out2;
++ }
++
++ host->detect_irq = platform_get_irq(pdev, 1);
++ if (host->detect_irq < 0) {
++ host->flags &= ~SDHCI_CD_PRESENT;
++ if ((pdev->id >= 0) && (pdev->id < MXC_SDHCI_NUM))
++ mxc_fix_chips[pdev->id] = chip;
++ goto no_detect_irq;
++ }
++// MASU FIXME THIS
++ if(mmc_plat->force_sd_detect == 0) { // bypass hw cd
++ ret = mmc_plat->status(host->mmc->parent);
++ if (ret)
++ host->flags &= ~SDHCI_CD_PRESENT;
++ else
++ host->flags |= SDHCI_CD_PRESENT;
++ } else {
++ host->flags |= SDHCI_CD_PRESENT;
++ }
++// MASU END FIXING
++
++no_detect_irq:
++ DBG(0, "slot %d at 0x%08x, irq %d\n", slot, host->res->start, host->irq);
++ if (!request_mem_region(host->res->start, resource_size(host->res),
++ pdev->name)) {
++ printk(KERN_ERR "request_mem_region failed\n");
++ ret = -EBUSY;
++ goto out2;
++ }
++ host->ioaddr = ioremap(host->res->start, resource_size(host->res));
++ if (!host->ioaddr) {
++ ret = -ENOMEM;
++ goto out3;
++ }
++
++ DBG(1, "%s: Resetting SDHCI controller\n", __FUNCTION__);
++ sdhci_reset(host, SDHCI_RESET_ALL);
++
++ version = readl(host->ioaddr + SDHCI_HOST_VERSION);
++ host->vendor_ver = (version & SDHCI_VENDOR_VER_MASK) >>
++ SDHCI_VENDOR_VER_SHIFT;
++ version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
++ dev_dbg(&pdev->dev, "SDHCI controller version: %d vendor version %d.%d\n",
++ version, (host->vendor_ver >> 4) + 1, host->vendor_ver & 0xf);
++ if (version != 1) {
++ printk(KERN_ERR "%s: Unknown controller version (%d). You may experience problems\n",
++ mmc_hostname(mmc), version);
++ }
++
++ host->caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
++ if (!(chip->quirks & SDHCI_QUIRK_INTERNAL_ADVANCED_DMA)) {
++ host->caps &= ~(SDHCI_CAN_DO_ADMA1 | SDHCI_CAN_DO_ADMA2);
++ }
++ if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
++ host->flags |= SDHCI_USE_DMA;
++ else if (!(host->caps & SDHCI_CAN_DO_DMA))
++ DBG(0, "Controller doesn't have DMA capability\n");
++ else if (chip->quirks & (SDHCI_QUIRK_INTERNAL_ADVANCED_DMA |
++ SDHCI_QUIRK_INTERNAL_SIMPLE_DMA))
++ host->flags |= SDHCI_USE_DMA;
++ else if (chip->quirks & (SDHCI_QUIRK_EXTERNAL_DMA_MODE))
++ host->flags |= SDHCI_USE_EXTERNAL_DMA;
++ else
++ host->flags &= ~SDHCI_USE_DMA;
++
++ /*
++ * These definitions of eSDHC are not compatible with the SD Host
++ * Controller Spec v2.0
++ */
++ host->min_clk = mmc_plat->min_clk;
++ host->max_clk = mmc_plat->max_clk;
++ host->timeout_clk = 1024 * 1000; /* Just set the value temporarily. */
++
++ /*
++ * Set host parameters.
++ */
++ mmc->ops = &sdhci_ops;
++ mmc->f_min = host->min_clk;
++ mmc->f_max = host->max_clk;
++ mmc->caps = MMC_CAP_SDIO_IRQ;
++ mmc->caps |= mmc_plat->caps;
++
++ if (host->caps & SDHCI_CAN_DO_HISPD)
++ mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
++
++ mmc->ocr_avail = mmc_plat->ocr_avail;
++ if (host->caps & SDHCI_CAN_VDD_330)
++ mmc->ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
++ if (host->caps & SDHCI_CAN_VDD_300)
++ mmc->ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
++ if (host->caps & SDHCI_CAN_VDD_180)
++ mmc->ocr_avail |= MMC_VDD_165_195;
++
++ if (mmc->ocr_avail == 0) {
++ printk(KERN_ERR "%s: Hardware doesn't report any supported voltages\n",
++ mmc_hostname(mmc));
++ ret = -ENODEV;
++ goto out3;
++ }
++
++ spin_lock_init(&host->lock);
++
++ /*
++ * Maximum number of segments. Hardware cannot do scatter lists.
++ */
++ if (host->flags & SDHCI_USE_DMA)
++ mmc->max_hw_segs = 1;
++ else
++ mmc->max_hw_segs = 16;
++ mmc->max_phys_segs = 16;
++
++ /*
++ * Maximum number of sectors in one transfer. Limited by DMA boundary
++ * size (512KiB).
++ */
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA)
++ mmc->max_req_size = SZ_32M;
++ else
++ mmc->max_req_size = SZ_512K;
++
++ /*
++ * Maximum segment size. Could be one segment with the maximum number
++ * of bytes.
++ */
++ mmc->max_seg_size = mmc->max_req_size;
++
++ /*
++ * Maximum block size. This varies from controller to controller and
++ * is specified in the capabilities register.
++ */
++ mmc->max_blk_size = (host->caps & SDHCI_MAX_BLOCK_MASK) >>
++ SDHCI_MAX_BLOCK_SHIFT;
++ if (mmc->max_blk_size > 3) {
++ printk(KERN_WARNING "%s: Invalid maximum block size, "
++ "assuming 512 bytes\n", mmc_hostname(mmc));
++ mmc->max_blk_size = 512;
++ } else
++ mmc->max_blk_size = 512 << mmc->max_blk_size;
++
++ /*
++ * Maximum block count.
++ */
++ mmc->max_blk_count = 65535;
++
++ /*
++ * Allocate contiguous physical memory used for storing the ADMA
++ * descriptor table.
++ */
++ if (host->flags & SDHCI_USE_DMA) {
++ host->dma_desc_size = (2 * (mmc->max_phys_segs) + 1) *
++ sizeof(unsigned int);
++ host->adma_des_table = dma_alloc_coherent(&pdev->dev,
++ host->dma_desc_size,
++ &host->dma_desc,
++ GFP_DMA);
++ if (host->adma_des_table == NULL) {
++ printk(KERN_ERR "Cannot allocate ADMA memory\n");
++ ret = -ENOMEM;
++ goto out3;
++ }
++ }
++
++ /*
++ * Init tasklets.
++ */
++ tasklet_init(&host->card_tasklet,
++ sdhci_tasklet_card, (unsigned long)host);
++ tasklet_init(&host->finish_tasklet,
++ sdhci_tasklet_finish, (unsigned long)host);
++
++ /* initialize the work queue */
++ INIT_WORK(&host->cd_wq, esdhc_cd_callback);
++
++ setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
++ setup_timer(&host->cd_timer, sdhci_cd_timer, (unsigned long)host);
++
++ ret = request_irq(host->irq, sdhci_irq, 0, pdev->name, host);
++ if (ret)
++ goto out5;
++
++ sdhci_init(host);
++
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA) {
++ /* Apply the 1-bit SDMA channel. */
++ if (host->id == 0)
++ dev_id = MXC_DMA_MMC1_WIDTH_1;
++ else
++ dev_id = MXC_DMA_MMC2_WIDTH_1;
++ host->dma = mxc_dma_request(dev_id, "MXC MMC");
++ if (host->dma < 0) {
++ DBG(0, "Cannot allocate MMC DMA channel\n");
++ ret = host->dma;
++ goto out6;
++ }
++ mxc_dma_callback_set(host->dma, sdhci_dma_irq, host);
++ }
++#ifdef CONFIG_MMC_DEBUG
++ sdhci_dumpregs(host);
++#endif
++ mmiowb();
++
++ ret = mmc_add_host(mmc);
++ if (ret)
++ goto out6;
++
++// MASU FIXME
++ ret = device_create_file(&mmc->class_dev,
++ &dev_attr_force_cd);
++ if (ret < 0)
++ goto out6;
++// MASU FIXME END
++
++ if (host->flags & SDHCI_USE_EXTERNAL_DMA)
++ dev_info(mmc_dev(mmc), "SDHCI detect irq %d irq %d %s\n",
++ host->detect_irq, host->irq, "EXTERNAL DMA");
++ else
++ dev_info(mmc_dev(mmc), "SDHCI detect irq %d irq %d %s\n",
++ host->detect_irq, host->irq,
++ (host->flags & SDHCI_USE_DMA) ? "INTERNAL DMA" : "PIO");
++
++ return 0;
++
++out6:
++ free_irq(host->irq, host);
++out5:
++ if (host->detect_irq >= 0) {
++ if ((pdev->id >= 0) && (pdev->id < MXC_SDHCI_NUM))
++ mxc_fix_chips[pdev->id] = NULL;
++ }
++ del_timer_sync(&host->timer);
++ del_timer_sync(&host->cd_timer);
++
++ tasklet_kill(&host->card_tasklet);
++ tasklet_kill(&host->finish_tasklet);
++
++ if (host->flags & SDHCI_USE_DMA)
++ dma_free_coherent(&pdev->dev, host->dma_desc_size,
++ host->adma_des_table, host->dma_desc);
++out3:
++ release_mem_region(host->res->start, resource_size(host->res));
++out2:
++ clk_disable(host->clk);
++ clk_put(host->clk);
++out1a:
++ platform_func(mmc_plat->exit, &pdev->dev, mmc);
++out1:
++ mmc_free_host(mmc);
++ DBG(0, "%s: Failed to init SDHCI driver: %d\n", __FUNCTION__, ret);
++ return ret;
++}
++
++static void sdhci_remove_slot(struct platform_device *pdev, int slot)
++{
++ struct sdhci_chip *chip;
++ struct mmc_host *mmc;
++ struct sdhci_host *host;
++
++ DBG(0, "%s: Removing slot %d\n", __FUNCTION__, slot);
++
++ chip = dev_get_drvdata(&pdev->dev);
++ host = chip->hosts[slot];
++ mmc = host->mmc;
++
++ chip->hosts[slot] = NULL;
++// MASU FIXME START
++ device_remove_file(&mmc->class_dev, &dev_attr_force_cd);
++//MASU END
++ mmc_remove_host(mmc);
++
++ sdhci_reset(host, SDHCI_RESET_ALL);
++
++ if (host->detect_irq >= 0) {
++ if ((pdev->id >= 0) && (pdev->id < MXC_SDHCI_NUM))
++ mxc_fix_chips[pdev->id] = NULL;
++ }
++ free_irq(host->irq, host);
++ if (chip->quirks & SDHCI_QUIRK_EXTERNAL_DMA_MODE) {
++ host->flags &= ~SDHCI_USE_EXTERNAL_DMA;
++ mxc_dma_free(host->dma);
++ }
++
++ del_timer_sync(&host->timer);
++
++ tasklet_kill(&host->card_tasklet);
++ tasklet_kill(&host->finish_tasklet);
++
++ if (host->flags & SDHCI_USE_DMA)
++ dma_free_coherent(&pdev->dev, host->dma_desc_size,
++ host->adma_des_table, host->dma_desc);
++
++ release_mem_region(host->res->start, resource_size(host->res));
++ clk_disable(host->clk);
++ clk_put(host->clk);
++ platform_func(host->plat_data->exit, &pdev->dev, mmc);
++ mmc_free_host(mmc);
++}
++
++static void sdhci_enable_quirks(struct sdhci_chip *chip)
++{
++ if (cpu_is_mx25()) {
++ //chip->quirks |= SDHCI_QUIRK_INTERNAL_ADVANCED_DMA;
++ chip->quirks |= SDHCI_QUIRK_INTERNAL_SIMPLE_DMA;
++ //chip->quirks |= SDHCI_QUIRK_RESET_AFTER_READ;
++ }
++#ifdef CONFIG_ARCH_MX35
++ if (mx35_revision() < MX35_CHIP_REV_2_0) {
++ chip->quirks |= SDHCI_QUIRK_RESET_AFTER_READ;
++ }
++#endif
++}
++
++static int __devinit sdhci_probe(struct platform_device *pdev)
++{
++ int ret = 0, i;
++ u8 slots = 1;
++ struct sdhci_chip *chip;
++
++ printk(KERN_INFO "MXC SDHCI Controller Driver\n");
++
++ chip = kzalloc(sizeof(struct sdhci_chip) +
++ sizeof(struct sdhci_host *) * slots, GFP_KERNEL);
++ if (!chip) {
++ ret = -ENOMEM;
++ goto err;
++ }
++ chip->pdev = pdev;
++
++ sdhci_enable_quirks(chip);
++ if (debug_quirks)
++ chip->quirks = debug_quirks;
++
++ chip->num_slots = slots;
++
++ for (i = 0; i < slots; i++) {
++ ret = sdhci_probe_slot(pdev, chip, i);
++ if (ret) {
++ for (i--; i >= 0; i--)
++ sdhci_remove_slot(pdev, i);
++ goto free;
++ }
++ }
++ dev_set_drvdata(&pdev->dev, chip);
++ return 0;
++
++free:
++ kfree(chip);
++err:
++ return ret;
++}
++
++static int __devexit sdhci_remove(struct platform_device *pdev)
++{
++ int i;
++ struct sdhci_chip *chip;
++
++ chip = dev_get_drvdata(&pdev->dev);
++
++ if (chip) {
++ for (i = 0; i < chip->num_slots; i++)
++ sdhci_remove_slot(pdev, i);
++
++ dev_set_drvdata(&pdev->dev, NULL);
++ kfree(chip);
++ }
++
++ return 0;
++}
++
++static struct dev_pm_ops sdhci_pm_ops = {
++ .suspend = sdhci_suspend,
++ .resume = sdhci_resume,
++};
++
++static struct platform_driver sdhci_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .pm = &sdhci_pm_ops,
++ },
++ .probe = sdhci_probe,
++ .remove = __devexit_p(sdhci_remove),
++};
++
++/*****************************************************************************\
++ * *
++ * Driver init/exit *
++ * *
++\*****************************************************************************/
++
++static int __init sdhci_drv_init(void)
++{
++ return platform_driver_register(&sdhci_driver);
++}
++module_init(sdhci_drv_init);
++
++static void __exit sdhci_drv_exit(void)
++{
++ platform_driver_unregister(&sdhci_driver);
++}
++module_exit(sdhci_drv_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC Secure Digital Host Controller Interface driver");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:sdhci");
+diff -urN linux.35.old/drivers/mmc/host/sdhci-mxc.h linux.35.new/drivers/mmc/host/sdhci-mxc.h
+--- linux.35.old/drivers/mmc/host/sdhci-mxc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mmc/host/sdhci-mxc.h 2010-12-20 14:51:10.320319327 +0100
+@@ -0,0 +1,290 @@
++/*
++ * linux/drivers/mmc/host/sdhci-mxc.h - Secure Digital Host
++ * Controller Interface driver
++ *
++ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
++ * Copyright 2008-2009 Freescale Semiconductor, 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.
++ */
++
++/*
++ * Controller registers
++ */
++
++#define SDHCI_DMA_ADDRESS 0x00
++
++#define SDHCI_BLOCK_SIZE 0x04
++#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 13) | (blksz & 0x1FFF))
++
++#define SDHCI_BLOCK_COUNT 0x04
++
++#define SDHCI_ARGUMENT 0x08
++
++#define SDHCI_TRANSFER_MODE 0x0C
++#define SDHCI_TRNS_DMA 0x00000001
++#define SDHCI_TRNS_BLK_CNT_EN 0x00000002
++#define SDHCI_TRNS_ACMD12 0x00000004
++#define SDHCI_TRNS_READ 0x00000010
++#define SDHCI_TRNS_MULTI 0x00000020
++#define SDHCI_TRNS_DPSEL 0x00200000
++#define SDHCI_TRNS_MASK 0xFFFF0000
++
++#define SDHCI_COMMAND 0x0E
++#define SDHCI_CMD_RESP_MASK 0x03
++#define SDHCI_CMD_CRC 0x08
++#define SDHCI_CMD_INDEX 0x10
++#define SDHCI_CMD_DATA 0x20
++
++#define SDHCI_CMD_RESP_NONE 0x00
++#define SDHCI_CMD_RESP_LONG 0x01
++#define SDHCI_CMD_RESP_SHORT 0x02
++#define SDHCI_CMD_RESP_SHORT_BUSY 0x03
++
++#define SDHCI_MAKE_CMD(c, f) ((((c & 0xff) << 8) | (f & 0xff)) << 16)
++
++#define SDHCI_RESPONSE 0x10
++
++#define SDHCI_BUFFER 0x20
++
++#define SDHCI_PRESENT_STATE 0x24
++#define SDHCI_CMD_INHIBIT 0x00000001
++#define SDHCI_DATA_INHIBIT 0x00000002
++#define SDHCI_DATA_ACTIVE 0x00000004
++#define SDHCI_DOING_WRITE 0x00000100
++#define SDHCI_DOING_READ 0x00000200
++#define SDHCI_SPACE_AVAILABLE 0x00000400
++#define SDHCI_DATA_AVAILABLE 0x00000800
++#define SDHCI_CARD_PRESENT 0x00010000
++#define SDHCI_WRITE_PROTECT 0x00080000
++#define SDHCI_DAT0_IDLE 0x01000000
++#define SDHCI_CARD_INT_MASK 0x0E000000
++#define SDHCI_CARD_INT_ID 0x0C000000
++
++#define SDHCI_HOST_CONTROL 0x28
++#define SDHCI_CTRL_LED 0x00000001
++#define SDHCI_CTRL_4BITBUS 0x00000002
++#define SDHCI_CTRL_8BITBUS 0x00000004
++#define SDHCI_CTRL_HISPD 0x00000004
++#define SDHCI_CTRL_DMA_MASK 0x18
++#define SDHCI_CTRL_SDMA 0x00
++#define SDHCI_CTRL_ADMA1 0x08
++#define SDHCI_CTRL_ADMA32 0x10
++#define SDHCI_CTRL_ADMA64 0x18
++#define SDHCI_CTRL_D3CD 0x00000008
++#define SDHCI_CTRL_ADMA 0x00000100
++/* wake up control */
++#define SDHCI_CTRL_WECINS 0x04000000
++
++#define SDHCI_POWER_CONTROL 0x29
++#define SDHCI_POWER_ON 0x01
++#define SDHCI_POWER_180 0x0A
++#define SDHCI_POWER_300 0x0C
++#define SDHCI_POWER_330 0x0E
++
++#define SDHCI_BLOCK_GAP_CONTROL 0x2A
++
++#define SDHCI_WAKE_UP_CONTROL 0x2B
++
++#define SDHCI_CLOCK_CONTROL 0x2C
++#define SDHCI_DIVIDER_SHIFT 8
++#define SDHCI_CLOCK_SD_EN 0x00000008
++#define SDHCI_CLOCK_PER_EN 0x00000004
++#define SDHCI_CLOCK_HLK_EN 0x00000002
++#define SDHCI_CLOCK_IPG_EN 0x00000001
++#define SDHCI_CLOCK_MASK 0x0000FFFF
++
++#define SDHCI_TIMEOUT_CONTROL 0x2E
++
++#define SDHCI_SOFTWARE_RESET 0x2F
++#define SDHCI_RESET_ALL 0x01
++#define SDHCI_RESET_CMD 0x02
++#define SDHCI_RESET_DATA 0x04
++
++#define SDHCI_INT_STATUS 0x30
++#define SDHCI_INT_ENABLE 0x34
++#define SDHCI_SIGNAL_ENABLE 0x38
++#define SDHCI_INT_RESPONSE 0x00000001
++#define SDHCI_INT_DATA_END 0x00000002
++#define SDHCI_INT_DMA_END 0x00000008
++#define SDHCI_INT_SPACE_AVAIL 0x00000010
++#define SDHCI_INT_DATA_AVAIL 0x00000020
++#define SDHCI_INT_CARD_INSERT 0x00000040
++#define SDHCI_INT_CARD_REMOVE 0x00000080
++#define SDHCI_INT_CARD_INT 0x00000100
++#define SDHCI_INT_ERROR 0x00008000
++#define SDHCI_INT_TIMEOUT 0x00010000
++#define SDHCI_INT_CRC 0x00020000
++#define SDHCI_INT_END_BIT 0x00040000
++#define SDHCI_INT_INDEX 0x00080000
++#define SDHCI_INT_DATA_TIMEOUT 0x00100000
++#define SDHCI_INT_DATA_CRC 0x00200000
++#define SDHCI_INT_DATA_END_BIT 0x00400000
++#define SDHCI_INT_BUS_POWER 0x00800000
++#define SDHCI_INT_ACMD12ERR 0x01000000
++#define SDHCI_INT_ADMA_ERROR 0x10000000
++
++#define SDHCI_INT_NORMAL_MASK 0x00007FFF
++#define SDHCI_INT_ERROR_MASK 0xFFFF8000
++
++#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
++ SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
++#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
++ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
++ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
++ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR)
++#define SDHCI_INT_DATA_RE_MASK (SDHCI_INT_DMA_END | \
++ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)
++
++#define SDHCI_ACMD12_ERR 0x3C
++
++/* 3E-3F reserved */
++
++#define SDHCI_CAPABILITIES 0x40
++#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
++#define SDHCI_TIMEOUT_CLK_SHIFT 0
++#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
++#define SDHCI_CLOCK_BASE_MASK 0x00003F00
++#define SDHCI_CLOCK_BASE_SHIFT 8
++#define SDHCI_MAX_BLOCK_MASK 0x00030000
++#define SDHCI_MAX_BLOCK_SHIFT 16
++#define SDHCI_CAN_DO_ADMA2 0x00080000
++#define SDHCI_CAN_DO_ADMA1 0x00100000
++#define SDHCI_CAN_DO_HISPD 0x00200000
++#define SDHCI_CAN_DO_DMA 0x00400000
++#define SDHCI_CAN_VDD_330 0x01000000
++#define SDHCI_CAN_VDD_300 0x02000000
++#define SDHCI_CAN_VDD_180 0x04000000
++#define SDHCI_CAN_64BIT 0x10000000
++
++/* 44-47 reserved for more caps */
++#define SDHCI_WML 0x44
++#define SDHCI_WML_4_WORDS 0x00040004
++#define SDHCI_WML_16_WORDS 0x00100010
++#define SDHCI_WML_64_WORDS 0x00400040
++#define SDHCI_WML_128_WORDS 0x00800080
++
++#define SDHCI_MAX_CURRENT 0x48
++
++/* 4C-4F reserved for more max current */
++
++#define SDHCI_SET_ACMD12_ERROR 0x50
++#define SDHCI_SET_INT_ERROR 0x52
++
++#define SDHCI_ADMA_ERROR 0x54
++
++/* 55-57 reserved */
++
++#define SDHCI_ADMA_ADDRESS 0x58
++
++/* 60-FB reserved */
++
++/* ADMA Addr Descriptor Attribute Field */
++enum {
++ FSL_ADMA_DES_ATTR_VALID = 0x01,
++ FSL_ADMA_DES_ATTR_END = 0x02,
++ FSL_ADMA_DES_ATTR_INT = 0x04,
++ FSL_ADMA_DES_ATTR_SET = 0x10,
++ FSL_ADMA_DES_ATTR_TRAN = 0x20,
++ FSL_ADMA_DES_ATTR_LINK = 0x30,
++};
++
++#define SDHCI_HOST_VERSION 0xFC
++#define SDHCI_VENDOR_VER_MASK 0xFF00
++#define SDHCI_VENDOR_VER_SHIFT 8
++#define SDHCI_SPEC_VER_MASK 0x00FF
++#define SDHCI_SPEC_VER_SHIFT 0
++#define SDHCI_SPEC_100 0
++#define SDHCI_SPEC_200 1
++#define ESDHC_VENDOR_V22 0x12
++
++struct sdhci_chip;
++
++struct adma_desc {
++ unsigned long attr:12,
++ length:20;
++ unsigned long dma_addr;
++};
++
++struct sdhci_host {
++ unsigned int vendor_ver;
++ unsigned int caps;
++ struct sdhci_chip *chip;
++ struct mmc_host *mmc; /* MMC structure */
++
++#ifdef CONFIG_LEDS_CLASS
++ struct led_classdev led; /* LED control */
++#endif
++ spinlock_t lock;
++
++ int init_flag; /* Host has been initialized */
++ int flags; /* Host attributes */
++#define SDHCI_USE_DMA (1 << 0) /* Host is DMA capable */
++#define SDHCI_REQ_USE_DMA (1 << 1) /* Use DMA for this req. */
++#define SDHCI_USE_EXTERNAL_DMA (1 << 2) /* Use the External DMA */
++#define SDHCI_CD_PRESENT (1 << 8) /* CD present */
++#define SDHCI_WP_ENABLED (1 << 9) /* Write protect */
++
++ unsigned int max_clk; /* Max possible freq (MHz) */
++ unsigned int min_clk; /* Min possible freq (MHz) */
++ unsigned int timeout_clk; /* Timeout freq (KHz) */
++
++ unsigned int clock; /* Current clock (MHz) */
++ unsigned short power; /* Current voltage */
++ struct regulator *regulator_mmc; /*! Regulator */
++
++ struct mmc_request *mrq; /* Current request */
++ struct mmc_command *cmd; /* Current command */
++ struct mmc_data *data; /* Current data request */
++ unsigned int data_early:1, /* Data finished before cmd */
++ last_op_dir:1; /* last CMD was read (for MX35 quirk) */
++
++ unsigned int id; /* Id for SD/MMC block */
++ int mode; /* SD/MMC mode */
++ int dma; /* DMA channel number. */
++ unsigned int dma_size; /* Number of Bytes in DMA */
++ unsigned int dma_len; /* Length of the s-g list */
++ unsigned int dma_dir; /* DMA transfer direction */
++#if 1
++ struct adma_desc *adma_des_table; /* ADMA descriptor table */
++ dma_addr_t dma_desc; /* physical address of ADMA descriptor table */
++ size_t dma_desc_size; /* size of ADMA descriptor table */
++#else
++ unsigned int *adma_des_table; /* ADMA descriptor table */
++#endif
++ struct scatterlist *cur_sg; /* We're working on this */
++ int num_sg; /* Entries left */
++ int offset; /* Offset into current sg */
++ int remain; /* Bytes left in current */
++
++ struct resource *res; /* IO map memory */
++ int irq; /* Device IRQ */
++ int detect_irq; /* Card Detect IRQ number. */
++ int sdio_enable; /* sdio interrupt enable number. */
++ struct clk *clk; /* Clock id */
++ int clk_enable; /* clk enable/disable count */
++ int bar; /* PCI BAR index */
++ unsigned long addr; /* Bus address */
++ void __iomem *ioaddr; /* Mapped address */
++
++ struct tasklet_struct card_tasklet; /* Tasklet structures */
++ struct tasklet_struct finish_tasklet;
++ struct work_struct cd_wq; /* card detection work queue */
++ /* Platform specific data */
++ struct mxc_sdhci_platform_data *plat_data;
++
++ struct timer_list timer; /* Timer for timeouts */
++ struct timer_list cd_timer; /* Timer for cd */
++};
++
++struct sdhci_chip {
++ struct platform_device *pdev;
++
++ unsigned long quirks;
++
++ int num_slots; /* Slots on controller */
++ struct sdhci_host *hosts[0]; /* Pointers to hosts */
++};
+diff -urN linux.35.old/drivers/mtd/nand/mxc_nand.c linux.35.new/drivers/mtd/nand/mxc_nand.c
+--- linux.35.old/drivers/mtd/nand/mxc_nand.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/mtd/nand/mxc_nand.c 2010-12-03 09:51:55.444346316 +0100
+@@ -853,6 +853,8 @@
+ parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
+ if (nr_parts > 0)
+ add_mtd_partitions(mtd, host->parts, nr_parts);
++ else if (pdata->parts)
++ add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
+ else
+ #endif
+ {
+diff -urN linux.35.old/drivers/mxc/adc/imx_adc.c linux.35.new/drivers/mxc/adc/imx_adc.c
+--- linux.35.old/drivers/mxc/adc/imx_adc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/adc/imx_adc.c 2010-12-03 09:51:55.448348573 +0100
+@@ -0,0 +1,1134 @@
++/*
++ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file adc/imx_adc.c
++ * @brief This is the main file of i.MX ADC driver.
++ *
++ * @ingroup IMX_ADC
++ */
++
++/*
++ * Includes
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/time.h>
++#include <linux/wait.h>
++#include <linux/slab.h>
++#include <linux/imx_adc.h>
++#include "imx_adc_reg.h"
++
++static int imx_adc_major;
++
++/*!
++ * Number of users waiting in suspendq
++ */
++static int swait;
++
++/*!
++ * To indicate whether any of the adc devices are suspending
++ */
++static int suspend_flag;
++
++/*!
++ * The suspendq is used by blocking application calls
++ */
++static wait_queue_head_t suspendq;
++static wait_queue_head_t tsq;
++
++static bool imx_adc_ready;
++static bool ts_data_ready;
++static int tsi_data = TSI_DATA;
++static unsigned short ts_data_buf[16];
++
++static struct class *imx_adc_class;
++static struct imx_adc_data *adc_data;
++
++static DECLARE_MUTEX(general_convert_mutex);
++static DECLARE_MUTEX(ts_convert_mutex);
++
++unsigned long tsc_base;
++
++int is_imx_adc_ready(void)
++{
++ return imx_adc_ready;
++}
++EXPORT_SYMBOL(is_imx_adc_ready);
++
++void tsc_clk_enable(void)
++{
++ unsigned long reg;
++
++ clk_enable(adc_data->adc_clk);
++
++ reg = __raw_readl(tsc_base + TGCR);
++ reg |= TGCR_IPG_CLK_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++}
++
++void tsc_clk_disable(void)
++{
++ unsigned long reg;
++
++ clk_disable(adc_data->adc_clk);
++
++ reg = __raw_readl(tsc_base + TGCR);
++ reg &= ~TGCR_IPG_CLK_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++}
++
++void tsc_self_reset(void)
++{
++ unsigned long reg;
++
++ reg = __raw_readl(tsc_base + TGCR);
++ reg |= TGCR_TSC_RST;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ while (__raw_readl(tsc_base + TGCR) & TGCR_TSC_RST)
++ continue;
++}
++
++/* Internal reference */
++void tsc_intref_enable(void)
++{
++ unsigned long reg;
++
++ reg = __raw_readl(tsc_base + TGCR);
++ reg |= TGCR_INTREFEN;
++ __raw_writel(reg, tsc_base + TGCR);
++}
++
++/* initialize touchscreen */
++void imx_tsc_init(void)
++{
++ unsigned long reg;
++ int lastitemid;
++
++ /* Level sense */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_PD_CFG; /* edge sensitive */
++ reg |= (0xf << CQCR_FIFOWATERMARK_SHIFT); /* watermark */
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ /* Configure 4-wire */
++ reg = TSC_4WIRE_PRECHARGE;
++ reg |= CC_IGS;
++ __raw_writel(reg, tsc_base + TCC0);
++
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ reg |= 3 << CC_NOS_SHIFT; /* 4 samples */
++ reg |= 32 << CC_SETTLING_TIME_SHIFT; /* it's important! */
++ __raw_writel(reg, tsc_base + TCC1);
++
++ reg = TSC_4WIRE_X_MEASUMENT;
++ reg |= 3 << CC_NOS_SHIFT; /* 4 samples */
++ reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */
++ __raw_writel(reg, tsc_base + TCC2);
++
++ reg = TSC_4WIRE_Y_MEASUMENT;
++ reg |= 3 << CC_NOS_SHIFT; /* 4 samples */
++ reg |= 16 << CC_SETTLING_TIME_SHIFT; /* settling time */
++ __raw_writel(reg, tsc_base + TCC3);
++
++ reg = (TCQ_ITEM_TCC0 << TCQ_ITEM7_SHIFT) |
++ (TCQ_ITEM_TCC0 << TCQ_ITEM6_SHIFT) |
++ (TCQ_ITEM_TCC1 << TCQ_ITEM5_SHIFT) |
++ (TCQ_ITEM_TCC0 << TCQ_ITEM4_SHIFT) |
++ (TCQ_ITEM_TCC3 << TCQ_ITEM3_SHIFT) |
++ (TCQ_ITEM_TCC2 << TCQ_ITEM2_SHIFT) |
++ (TCQ_ITEM_TCC1 << TCQ_ITEM1_SHIFT) |
++ (TCQ_ITEM_TCC0 << TCQ_ITEM0_SHIFT);
++ __raw_writel(reg, tsc_base + TCQ_ITEM_7_0);
++
++ lastitemid = 5;
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg = (reg & ~CQCR_LAST_ITEM_ID_MASK) |
++ (lastitemid << CQCR_LAST_ITEM_ID_SHIFT);
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ /* Config idle for 4-wire */
++ reg = TSC_4WIRE_PRECHARGE;
++ __raw_writel(reg, tsc_base + TICR);
++
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ __raw_writel(reg, tsc_base + TICR);
++
++ /* pen down mask */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_PD_MSK;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg &= ~TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++
++ /* Debounce time = dbtime*8 adc clock cycles */
++ reg = __raw_readl(tsc_base + TGCR);
++ reg &= ~TGCR_PDBTIME_MASK;
++ reg |= TGCR_PDBTIME128 | TGCR_HSYNC_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ /* pen down enable */
++ reg = __raw_readl(tsc_base + TGCR);
++ reg |= TGCR_PDB_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++ reg |= TGCR_PD_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++}
++
++static irqreturn_t imx_adc_interrupt(int irq, void *dev_id)
++{
++ unsigned long reg;
++
++ if (__raw_readl(tsc_base + TGSR) & 0x4) {
++ /* deep sleep wakeup interrupt */
++ /* clear tgsr */
++ __raw_writel(0, tsc_base + TGSR);
++ /* clear deep sleep wakeup irq */
++ reg = __raw_readl(tsc_base + TGCR);
++ reg &= ~TGCR_SLPC;
++ __raw_writel(reg, tsc_base + TGCR);
++ /* un-mask pen down and pen down irq */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_PD_MSK;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg &= ~TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++ } else if ((__raw_readl(tsc_base + TGSR) & 0x1) &&
++ (__raw_readl(tsc_base + TCQSR) & 0x1)) {
++
++ /* mask pen down detect irq */
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg |= TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++
++ ts_data_ready = 1;
++ wake_up_interruptible(&tsq);
++ }
++ return IRQ_HANDLED;
++}
++
++enum IMX_ADC_STATUS imx_adc_read_general(unsigned short *result)
++{
++ unsigned long reg;
++ unsigned int data_num = 0;
++
++ reg = __raw_readl(tsc_base + GCQCR);
++ reg |= CQCR_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++
++ while (!(__raw_readl(tsc_base + GCQSR) & CQSR_EOQ))
++ continue;
++ reg = __raw_readl(tsc_base + GCQCR);
++ reg &= ~CQCR_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++ reg = __raw_readl(tsc_base + GCQSR);
++ reg |= CQSR_EOQ;
++ __raw_writel(reg, tsc_base + GCQSR);
++
++ while (!(__raw_readl(tsc_base + GCQSR) & CQSR_EMPT)) {
++ result[data_num] = __raw_readl(tsc_base + GCQFIFO) >>
++ GCQFIFO_ADCOUT_SHIFT;
++ data_num++;
++ }
++ return IMX_ADC_SUCCESS;
++}
++
++/*!
++ * This function will get raw (X,Y) value by converting the voltage
++ * @param touch_sample Pointer to touch sample
++ *
++ * return This funciton returns 0 if successful.
++ *
++ *
++ */
++enum IMX_ADC_STATUS imx_adc_read_ts(struct t_touch_screen *touch_sample,
++ int wait_tsi)
++{
++ unsigned long reg;
++ int data_num = 0;
++ int detect_sample1, detect_sample2;
++
++ memset(ts_data_buf, 0, sizeof ts_data_buf);
++ touch_sample->valid_flag = 1;
++
++ if (wait_tsi) {
++ /* Config idle for 4-wire */
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ __raw_writel(reg, tsc_base + TICR);
++
++ /* Pen interrupt starts new conversion queue */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_PEN;
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ /* unmask pen down detect irq */
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg &= ~TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++
++ wait_event_interruptible(tsq, ts_data_ready);
++ while (!(__raw_readl(tsc_base + TCQSR) & CQSR_EOQ))
++ continue;
++
++ /* stop the conversion */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = CQSR_PD | CQSR_EOQ;
++ __raw_writel(reg, tsc_base + TCQSR);
++
++ /* change configuration for FQS mode */
++ tsi_data = TSI_DATA;
++ reg = (0x1 << CC_YPLLSW_SHIFT) | (0x1 << CC_XNURSW_SHIFT) |
++ CC_XPULSW;
++ __raw_writel(reg, tsc_base + TICR);
++ } else {
++ /* FQS semaphore */
++ down(&ts_convert_mutex);
++
++ reg = (0x1 << CC_YPLLSW_SHIFT) | (0x1 << CC_XNURSW_SHIFT) |
++ CC_XPULSW;
++ __raw_writel(reg, tsc_base + TICR);
++
++ /* FQS */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_FQS;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg |= CQCR_FQS;
++ __raw_writel(reg, tsc_base + TCQCR);
++ while (!(__raw_readl(tsc_base + TCQSR) & CQSR_EOQ))
++ continue;
++
++ /* stop FQS */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_FQS;
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ /* clear status bit */
++ reg = __raw_readl(tsc_base + TCQSR);
++ reg |= CQSR_EOQ;
++ __raw_writel(reg, tsc_base + TCQSR);
++ tsi_data = FQS_DATA;
++
++ /* Config idle for 4-wire */
++ reg = TSC_4WIRE_PRECHARGE;
++ __raw_writel(reg, tsc_base + TICR);
++
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ __raw_writel(reg, tsc_base + TICR);
++
++ }
++
++ while (!(__raw_readl(tsc_base + TCQSR) & CQSR_EMPT)) {
++ reg = __raw_readl(tsc_base + TCQFIFO);
++ ts_data_buf[data_num] = reg;
++ data_num++;
++ }
++
++ touch_sample->x_position1 = ts_data_buf[4] >> 4;
++ touch_sample->x_position2 = ts_data_buf[5] >> 4;
++ touch_sample->x_position3 = ts_data_buf[6] >> 4;
++ touch_sample->y_position1 = ts_data_buf[9] >> 4;
++ touch_sample->y_position2 = ts_data_buf[10] >> 4;
++ touch_sample->y_position3 = ts_data_buf[11] >> 4;
++
++ detect_sample1 = ts_data_buf[0];
++ detect_sample2 = ts_data_buf[12];
++
++ if ((detect_sample1 > 0x6000) || (detect_sample2 > 0x6000))
++ touch_sample->valid_flag = 0;
++
++ ts_data_ready = 0;
++
++ if (!(touch_sample->x_position1 ||
++ touch_sample->x_position2 || touch_sample->x_position3))
++ touch_sample->contact_resistance = 0;
++ else
++ touch_sample->contact_resistance = 1;
++
++ if (tsi_data == FQS_DATA)
++ up(&ts_convert_mutex);
++ return IMX_ADC_SUCCESS;
++}
++
++/*!
++ * This function performs filtering and rejection of excessive noise prone
++ * sampl.
++ *
++ * @param ts_curr Touch screen value
++ *
++ * @return This function returns 0 on success, -1 otherwise.
++ */
++static int imx_adc_filter(struct t_touch_screen *ts_curr)
++{
++
++ unsigned int ydiff1, ydiff2, ydiff3, xdiff1, xdiff2, xdiff3;
++ unsigned int sample_sumx, sample_sumy;
++ static unsigned int prev_x[FILTLEN], prev_y[FILTLEN];
++ int index = 0;
++ unsigned int y_curr, x_curr;
++ static int filt_count;
++ /* Added a variable filt_type to decide filtering at run-time */
++ unsigned int filt_type = 0;
++
++ /* ignore the data converted when pen down and up */
++ if ((ts_curr->contact_resistance == 0) || tsi_data == TSI_DATA) {
++ ts_curr->x_position = 0;
++ ts_curr->y_position = 0;
++ filt_count = 0;
++ return 0;
++ }
++ /* ignore the data valid */
++ if (ts_curr->valid_flag == 0)
++ return -1;
++
++ ydiff1 = abs(ts_curr->y_position1 - ts_curr->y_position2);
++ ydiff2 = abs(ts_curr->y_position2 - ts_curr->y_position3);
++ ydiff3 = abs(ts_curr->y_position1 - ts_curr->y_position3);
++ if ((ydiff1 > DELTA_Y_MAX) ||
++ (ydiff2 > DELTA_Y_MAX) || (ydiff3 > DELTA_Y_MAX)) {
++ pr_debug("imx_adc_filter: Ret pos 1\n");
++ return -1;
++ }
++
++ xdiff1 = abs(ts_curr->x_position1 - ts_curr->x_position2);
++ xdiff2 = abs(ts_curr->x_position2 - ts_curr->x_position3);
++ xdiff3 = abs(ts_curr->x_position1 - ts_curr->x_position3);
++
++ if ((xdiff1 > DELTA_X_MAX) ||
++ (xdiff2 > DELTA_X_MAX) || (xdiff3 > DELTA_X_MAX)) {
++ pr_debug("imx_adc_filter: Ret pos 2\n");
++ return -1;
++ }
++ /* Compute two closer values among the three available Y readouts */
++
++ if (ydiff1 < ydiff2) {
++ if (ydiff1 < ydiff3) {
++ /* Sample 0 & 1 closest together */
++ sample_sumy = ts_curr->y_position1 +
++ ts_curr->y_position2;
++ } else {
++ /* Sample 0 & 2 closest together */
++ sample_sumy = ts_curr->y_position1 +
++ ts_curr->y_position3;
++ }
++ } else {
++ if (ydiff2 < ydiff3) {
++ /* Sample 1 & 2 closest together */
++ sample_sumy = ts_curr->y_position2 +
++ ts_curr->y_position3;
++ } else {
++ /* Sample 0 & 2 closest together */
++ sample_sumy = ts_curr->y_position1 +
++ ts_curr->y_position3;
++ }
++ }
++
++ /*
++ * Compute two closer values among the three available X
++ * readouts
++ */
++ if (xdiff1 < xdiff2) {
++ if (xdiff1 < xdiff3) {
++ /* Sample 0 & 1 closest together */
++ sample_sumx = ts_curr->x_position1 +
++ ts_curr->x_position2;
++ } else {
++ /* Sample 0 & 2 closest together */
++ sample_sumx = ts_curr->x_position1 +
++ ts_curr->x_position3;
++ }
++ } else {
++ if (xdiff2 < xdiff3) {
++ /* Sample 1 & 2 closest together */
++ sample_sumx = ts_curr->x_position2 +
++ ts_curr->x_position3;
++ } else {
++ /* Sample 0 & 2 closest together */
++ sample_sumx = ts_curr->x_position1 +
++ ts_curr->x_position3;
++ }
++ }
++
++ /*
++ * Wait FILTER_MIN_DELAY number of samples to restart
++ * filtering
++ */
++ if (filt_count < FILTER_MIN_DELAY) {
++ /*
++ * Current output is the average of the two closer
++ * values and no filtering is used
++ */
++ y_curr = (sample_sumy / 2);
++ x_curr = (sample_sumx / 2);
++ ts_curr->y_position = y_curr;
++ ts_curr->x_position = x_curr;
++ filt_count++;
++
++ } else {
++ if (abs(sample_sumx - (prev_x[0] + prev_x[1])) >
++ (DELTA_X_MAX * 16)) {
++ pr_debug("imx_adc_filter: : Ret pos 3\n");
++ return -1;
++ }
++ if (abs(sample_sumy - (prev_y[0] + prev_y[1])) >
++ (DELTA_Y_MAX * 16)) {
++ pr_debug("imx_adc_filter: : Ret pos 4\n");
++ return -1;
++ }
++ sample_sumy /= 2;
++ sample_sumx /= 2;
++ /* Use hard filtering if the sample difference < 10 */
++ if ((abs(sample_sumy - prev_y[0]) > 10) ||
++ (abs(sample_sumx - prev_x[0]) > 10))
++ filt_type = 1;
++
++ /*
++ * Current outputs are the average of three previous
++ * values and the present readout
++ */
++ y_curr = sample_sumy;
++ for (index = 0; index < FILTLEN; index++) {
++ if (filt_type == 0)
++ y_curr = y_curr + (prev_y[index]);
++ else
++ y_curr = y_curr + (prev_y[index] / 3);
++ }
++ if (filt_type == 0)
++ y_curr = y_curr >> 2;
++ else
++ y_curr = y_curr >> 1;
++ ts_curr->y_position = y_curr;
++
++ x_curr = sample_sumx;
++ for (index = 0; index < FILTLEN; index++) {
++ if (filt_type == 0)
++ x_curr = x_curr + (prev_x[index]);
++ else
++ x_curr = x_curr + (prev_x[index] / 3);
++ }
++ if (filt_type == 0)
++ x_curr = x_curr >> 2;
++ else
++ x_curr = x_curr >> 1;
++ ts_curr->x_position = x_curr;
++
++ }
++
++ /* Update previous X and Y values */
++ for (index = (FILTLEN - 1); index > 0; index--) {
++ prev_x[index] = prev_x[index - 1];
++ prev_y[index] = prev_y[index - 1];
++ }
++
++ /*
++ * Current output will be the most recent past for the
++ * next sample
++ */
++ prev_y[0] = y_curr;
++ prev_x[0] = x_curr;
++
++ return 0;
++
++}
++
++/*!
++ * This function retrieves the current touch screen (X,Y) coordinates.
++ *
++ * @param touch_sample Pointer to touch sample.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_get_touch_sample(struct t_touch_screen
++ *touch_sample, int wait_tsi)
++{
++ if (imx_adc_read_ts(touch_sample, wait_tsi))
++ return IMX_ADC_ERROR;
++ if (!imx_adc_filter(touch_sample))
++ return IMX_ADC_SUCCESS;
++ else
++ return IMX_ADC_ERROR;
++}
++EXPORT_SYMBOL(imx_adc_get_touch_sample);
++
++void imx_adc_set_hsync(int on)
++{
++ unsigned long reg;
++ if (imx_adc_ready) {
++ reg = __raw_readl(tsc_base + TGCR);
++ if (on)
++ reg |= TGCR_HSYNC_EN;
++ else
++ reg &= ~TGCR_HSYNC_EN;
++ __raw_writel(reg, tsc_base + TGCR);
++ }
++}
++EXPORT_SYMBOL(imx_adc_set_hsync);
++
++/*!
++ * This is the suspend of power management for the i.MX ADC API.
++ * It supports SAVE and POWER_DOWN state.
++ *
++ * @param pdev the device
++ * @param state the state
++ *
++ * @return This function returns 0 if successful.
++ */
++static int imx_adc_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ unsigned long reg;
++
++ /* Config idle for 4-wire */
++ reg = TSC_4WIRE_PRECHARGE;
++ __raw_writel(reg, tsc_base + TICR);
++
++ reg = TSC_4WIRE_TOUCH_DETECT;
++ __raw_writel(reg, tsc_base + TICR);
++
++ /* enable deep sleep wake up */
++ reg = __raw_readl(tsc_base + TGCR);
++ reg |= TGCR_SLPC;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ /* mask pen down and pen down irq */
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg |= CQCR_PD_MSK;
++ __raw_writel(reg, tsc_base + TCQCR);
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg |= TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++
++ /* Set power mode to off */
++ reg = __raw_readl(tsc_base + TGCR) & ~TGCR_POWER_MASK;
++ reg |= TGCR_POWER_OFF;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ if (device_may_wakeup(&pdev->dev)) {
++ enable_irq_wake(adc_data->irq);
++ } else {
++ suspend_flag = 1;
++ tsc_clk_disable();
++ }
++ return 0;
++};
++
++/*!
++ * This is the resume of power management for the i.MX adc API.
++ * It supports RESTORE state.
++ *
++ * @param pdev the device
++ *
++ * @return This function returns 0 if successful.
++ */
++static int imx_adc_resume(struct platform_device *pdev)
++{
++ unsigned long reg;
++
++ if (device_may_wakeup(&pdev->dev)) {
++ disable_irq_wake(adc_data->irq);
++ } else {
++ suspend_flag = 0;
++ tsc_clk_enable();
++ while (swait > 0) {
++ swait--;
++ wake_up_interruptible(&suspendq);
++ }
++ }
++
++ /* recover power mode */
++ reg = __raw_readl(tsc_base + TGCR) & ~TGCR_POWER_MASK;
++ reg |= TGCR_POWER_SAVE;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ return 0;
++}
++
++/*!
++ * This function implements the open method on an i.MX ADC device.
++ *
++ * @param inode pointer on the node
++ * @param file pointer on the file
++ * @return This function returns 0.
++ */
++static int imx_adc_open(struct inode *inode, struct file *file)
++{
++ while (suspend_flag) {
++ swait++;
++ /* Block if the device is suspended */
++ if (wait_event_interruptible(suspendq, !suspend_flag))
++ return -ERESTARTSYS;
++ }
++ pr_debug("imx_adc : imx_adc_open()\n");
++ return 0;
++}
++
++/*!
++ * This function implements the release method on an i.MX ADC device.
++ *
++ * @param inode pointer on the node
++ * @param file pointer on the file
++ * @return This function returns 0.
++ */
++static int imx_adc_free(struct inode *inode, struct file *file)
++{
++ pr_debug("imx_adc : imx_adc_free()\n");
++ return 0;
++}
++
++/*!
++ * This function initializes all ADC registers with default values. This
++ * function also registers the interrupt events.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++int imx_adc_init(void)
++{
++ unsigned long reg;
++
++ pr_debug("imx_adc_init()\n");
++
++ if (suspend_flag)
++ return -EBUSY;
++
++ tsc_clk_enable();
++
++ /* Reset */
++ tsc_self_reset();
++
++ /* Internal reference */
++ tsc_intref_enable();
++
++ /* Set power mode */
++ reg = __raw_readl(tsc_base + TGCR) & ~TGCR_POWER_MASK;
++ reg |= TGCR_POWER_SAVE;
++ __raw_writel(reg, tsc_base + TGCR);
++
++ imx_tsc_init();
++
++ return IMX_ADC_SUCCESS;
++}
++EXPORT_SYMBOL(imx_adc_init);
++
++/*!
++ * This function disables the ADC, de-registers the interrupt events.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_deinit(void)
++{
++ pr_debug("imx_adc_deinit()\n");
++
++ return IMX_ADC_SUCCESS;
++}
++EXPORT_SYMBOL(imx_adc_deinit);
++
++/*!
++ * This function triggers a conversion and returns one sampling result of one
++ * channel.
++ *
++ * @param channel The channel to be sampled
++ * @param result The pointer to the conversion result. The memory
++ * should be allocated by the caller of this function.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_convert(enum t_channel channel,
++ unsigned short *result)
++{
++ unsigned long reg;
++ int lastitemid;
++ struct t_touch_screen touch_sample;
++
++ switch (channel) {
++
++ case TS_X_POS:
++ imx_adc_get_touch_sample(&touch_sample, 0);
++ result[0] = touch_sample.x_position;
++
++ /* if no pen down ,recover the register configuration */
++ if (touch_sample.contact_resistance == 0) {
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_PEN;
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg &= ~TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++ }
++ break;
++
++ case TS_Y_POS:
++ imx_adc_get_touch_sample(&touch_sample, 0);
++ result[1] = touch_sample.y_position;
++
++ /* if no pen down ,recover the register configuration */
++ if (touch_sample.contact_resistance == 0) {
++ reg = __raw_readl(tsc_base + TCQCR);
++ reg &= ~CQCR_QSM_MASK;
++ reg |= CQCR_QSM_PEN;
++ __raw_writel(reg, tsc_base + TCQCR);
++
++ reg = __raw_readl(tsc_base + TCQMR);
++ reg &= ~TCQMR_PD_IRQ_MSK;
++ __raw_writel(reg, tsc_base + TCQMR);
++ }
++ break;
++
++ case GER_PURPOSE_ADC0:
++ down(&general_convert_mutex);
++
++ lastitemid = 0;
++ reg = (0xf << CQCR_FIFOWATERMARK_SHIFT) |
++ (lastitemid << CQCR_LAST_ITEM_ID_SHIFT) | CQCR_QSM_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++
++ reg = TSC_GENERAL_ADC_GCC0;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC0);
++
++ imx_adc_read_general(result);
++ up(&general_convert_mutex);
++ break;
++
++ case GER_PURPOSE_ADC1:
++ down(&general_convert_mutex);
++
++ lastitemid = 0;
++ reg = (0xf << CQCR_FIFOWATERMARK_SHIFT) |
++ (lastitemid << CQCR_LAST_ITEM_ID_SHIFT) | CQCR_QSM_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++
++ reg = TSC_GENERAL_ADC_GCC1;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC0);
++
++ imx_adc_read_general(result);
++ up(&general_convert_mutex);
++ break;
++
++ case GER_PURPOSE_ADC2:
++ down(&general_convert_mutex);
++
++ lastitemid = 0;
++ reg = (0xf << CQCR_FIFOWATERMARK_SHIFT) |
++ (lastitemid << CQCR_LAST_ITEM_ID_SHIFT) | CQCR_QSM_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++
++ reg = TSC_GENERAL_ADC_GCC2;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC0);
++
++ imx_adc_read_general(result);
++ up(&general_convert_mutex);
++ break;
++
++ case GER_PURPOSE_MULTICHNNEL:
++ down(&general_convert_mutex);
++
++ reg = TSC_GENERAL_ADC_GCC0;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC0);
++
++ reg = TSC_GENERAL_ADC_GCC1;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC1);
++
++ reg = TSC_GENERAL_ADC_GCC2;
++ reg |= (3 << CC_NOS_SHIFT) | (16 << CC_SETTLING_TIME_SHIFT);
++ __raw_writel(reg, tsc_base + GCC2);
++
++ reg = (GCQ_ITEM_GCC2 << GCQ_ITEM2_SHIFT) |
++ (GCQ_ITEM_GCC1 << GCQ_ITEM1_SHIFT) |
++ (GCQ_ITEM_GCC0 << GCQ_ITEM0_SHIFT);
++ __raw_writel(reg, tsc_base + GCQ_ITEM_7_0);
++
++ lastitemid = 2;
++ reg = (0xf << CQCR_FIFOWATERMARK_SHIFT) |
++ (lastitemid << CQCR_LAST_ITEM_ID_SHIFT) | CQCR_QSM_FQS;
++ __raw_writel(reg, tsc_base + GCQCR);
++
++ imx_adc_read_general(result);
++ up(&general_convert_mutex);
++ break;
++ default:
++ pr_debug("%s: bad channel number\n", __func__);
++ return IMX_ADC_ERROR;
++ }
++
++ return IMX_ADC_SUCCESS;
++}
++EXPORT_SYMBOL(imx_adc_convert);
++
++/*!
++ * This function triggers a conversion and returns sampling results of each
++ * specified channel.
++ *
++ * @param channels This input parameter is bitmap to specify channels
++ * to be sampled.
++ * @param result The pointer to array to store sampling results.
++ * The memory should be allocated by the caller of this
++ * function.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_convert_multichnnel(enum t_channel channels,
++ unsigned short *result)
++{
++ imx_adc_convert(GER_PURPOSE_MULTICHNNEL, result);
++ return IMX_ADC_SUCCESS;
++}
++EXPORT_SYMBOL(imx_adc_convert_multichnnel);
++
++/*!
++ * This function implements IOCTL controls on an i.MX ADC device.
++ *
++ * @param inode pointer on the node
++ * @param file pointer on the file
++ * @param cmd the command
++ * @param arg the parameter
++ * @return This function returns 0 if successful.
++ */
++static int imx_adc_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct t_adc_convert_param *convert_param;
++
++ if ((_IOC_TYPE(cmd) != 'p') && (_IOC_TYPE(cmd) != 'D'))
++ return -ENOTTY;
++
++ while (suspend_flag) {
++ swait++;
++ /* Block if the device is suspended */
++ if (wait_event_interruptible(suspendq, !suspend_flag))
++ return -ERESTARTSYS;
++ }
++
++ switch (cmd) {
++ case IMX_ADC_INIT:
++ pr_debug("init adc\n");
++ CHECK_ERROR(imx_adc_init());
++ break;
++
++ case IMX_ADC_DEINIT:
++ pr_debug("deinit adc\n");
++ CHECK_ERROR(imx_adc_deinit());
++ break;
++
++ case IMX_ADC_CONVERT:
++ convert_param = kmalloc(sizeof(*convert_param), GFP_KERNEL);
++ if (convert_param == NULL)
++ return -ENOMEM;
++ if (copy_from_user(convert_param,
++ (struct t_adc_convert_param *)arg,
++ sizeof(*convert_param))) {
++ kfree(convert_param);
++ return -EFAULT;
++ }
++ CHECK_ERROR_KFREE(imx_adc_convert(convert_param->channel,
++ convert_param->result),
++ (kfree(convert_param)));
++
++ if (copy_to_user((struct t_adc_convert_param *)arg,
++ convert_param, sizeof(*convert_param))) {
++ kfree(convert_param);
++ return -EFAULT;
++ }
++ kfree(convert_param);
++ break;
++
++ case IMX_ADC_CONVERT_MULTICHANNEL:
++ convert_param = kmalloc(sizeof(*convert_param), GFP_KERNEL);
++ if (convert_param == NULL)
++ return -ENOMEM;
++ if (copy_from_user(convert_param,
++ (struct t_adc_convert_param *)arg,
++ sizeof(*convert_param))) {
++ kfree(convert_param);
++ return -EFAULT;
++ }
++ CHECK_ERROR_KFREE(imx_adc_convert_multichnnel
++ (convert_param->channel,
++ convert_param->result),
++ (kfree(convert_param)));
++
++ if (copy_to_user((struct t_adc_convert_param *)arg,
++ convert_param, sizeof(*convert_param))) {
++ kfree(convert_param);
++ return -EFAULT;
++ }
++ kfree(convert_param);
++ break;
++
++ default:
++ pr_debug("imx_adc_ioctl: unsupported ioctl command 0x%x\n",
++ cmd);
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static struct file_operations imx_adc_fops = {
++ .owner = THIS_MODULE,
++ .ioctl = imx_adc_ioctl,
++ .open = imx_adc_open,
++ .release = imx_adc_free,
++};
++
++static int imx_adc_module_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++ int retval;
++ struct device *temp_class;
++ struct resource *res;
++ void __iomem *base;
++
++ /* ioremap the base address */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ dev_err(&pdev->dev, "No TSC base address provided\n");
++ goto err_out0;
++ }
++ base = ioremap(res->start, res->end - res->start);
++ if (base == NULL) {
++ dev_err(&pdev->dev, "failed to rebase TSC base address\n");
++ goto err_out0;
++ }
++ tsc_base = (unsigned long)base;
++
++ /* create the chrdev */
++ imx_adc_major = register_chrdev(0, "imx_adc", &imx_adc_fops);
++
++ if (imx_adc_major < 0) {
++ dev_err(&pdev->dev, "Unable to get a major for imx_adc\n");
++ return imx_adc_major;
++ }
++ init_waitqueue_head(&suspendq);
++ init_waitqueue_head(&tsq);
++
++ imx_adc_class = class_create(THIS_MODULE, "imx_adc");
++ if (IS_ERR(imx_adc_class)) {
++ dev_err(&pdev->dev, "Error creating imx_adc class.\n");
++ ret = PTR_ERR(imx_adc_class);
++ goto err_out1;
++ }
++
++ temp_class = device_create(imx_adc_class, NULL,
++ MKDEV(imx_adc_major, 0), NULL, "imx_adc");
++ if (IS_ERR(temp_class)) {
++ dev_err(&pdev->dev, "Error creating imx_adc class device.\n");
++ ret = PTR_ERR(temp_class);
++ goto err_out2;
++ }
++
++ adc_data = kmalloc(sizeof(struct imx_adc_data), GFP_KERNEL);
++ if (adc_data == NULL)
++ return -ENOMEM;
++ adc_data->irq = platform_get_irq(pdev, 0);
++ retval = request_irq(adc_data->irq, imx_adc_interrupt,
++ 0, MOD_NAME, MOD_NAME);
++ if (retval) {
++ return retval;
++ }
++ adc_data->adc_clk = clk_get(&pdev->dev, "tsc_clk");
++
++ ret = imx_adc_init();
++
++ if (ret != IMX_ADC_SUCCESS) {
++ dev_err(&pdev->dev, "Error in imx_adc_init.\n");
++ goto err_out4;
++ }
++ imx_adc_ready = 1;
++
++ /* By default, devices should wakeup if they can */
++ /* So TouchScreen is set as "should wakeup" as it can */
++ device_init_wakeup(&pdev->dev, 1);
++
++ pr_info("i.MX ADC at 0x%x irq %d\n", (unsigned int)res->start,
++ adc_data->irq);
++ return ret;
++
++err_out4:
++ device_destroy(imx_adc_class, MKDEV(imx_adc_major, 0));
++err_out2:
++ class_destroy(imx_adc_class);
++err_out1:
++ unregister_chrdev(imx_adc_major, "imx_adc");
++err_out0:
++ return ret;
++}
++
++static int imx_adc_module_remove(struct platform_device *pdev)
++{
++ imx_adc_ready = 0;
++ imx_adc_deinit();
++ device_destroy(imx_adc_class, MKDEV(imx_adc_major, 0));
++ class_destroy(imx_adc_class);
++ unregister_chrdev(imx_adc_major, "imx_adc");
++ free_irq(adc_data->irq, MOD_NAME);
++ kfree(adc_data);
++ pr_debug("i.MX ADC successfully removed\n");
++ return 0;
++}
++
++static struct platform_driver imx_adc_driver = {
++ .driver = {
++ .name = "imx_adc",
++ },
++ .suspend = imx_adc_suspend,
++ .resume = imx_adc_resume,
++ .probe = imx_adc_module_probe,
++ .remove = imx_adc_module_remove,
++};
++
++/*
++ * Initialization and Exit
++ */
++static int __init imx_adc_module_init(void)
++{
++ printk(KERN_INFO "i.MX ADC driver loading...\n");
++ return platform_driver_register(&imx_adc_driver);
++}
++
++static void __exit imx_adc_module_exit(void)
++{
++ platform_driver_unregister(&imx_adc_driver);
++ printk(KERN_INFO "i.MX ADC driver successfully unloaded\n");
++}
++
++/*
++ * Module entry points
++ */
++
++module_init(imx_adc_module_init);
++module_exit(imx_adc_module_exit);
++
++MODULE_DESCRIPTION("i.MX ADC device driver");
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/drivers/mxc/adc/imx_adc_reg.h linux.35.new/drivers/mxc/adc/imx_adc_reg.h
+--- linux.35.old/drivers/mxc/adc/imx_adc_reg.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/adc/imx_adc_reg.h 2010-12-03 09:51:55.452350145 +0100
+@@ -0,0 +1,242 @@
++/*
++ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU Lesser General
++ * Public License. You may obtain a copy of the GNU Lesser General
++ * Public License Version 2.1 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/lgpl-license.html
++ * http://www.gnu.org/copyleft/lgpl.html
++ */
++
++#ifndef __IMX_ADC_H__
++#define __IMX_ADC_H__
++
++/* TSC General Config Register */
++#define TGCR 0x000
++#define TGCR_IPG_CLK_EN (1 << 0)
++#define TGCR_TSC_RST (1 << 1)
++#define TGCR_FUNC_RST (1 << 2)
++#define TGCR_SLPC (1 << 4)
++#define TGCR_STLC (1 << 5)
++#define TGCR_HSYNC_EN (1 << 6)
++#define TGCR_HSYNC_POL (1 << 7)
++#define TGCR_POWERMODE_SHIFT 8
++#define TGCR_POWER_OFF (0x0 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_SAVE (0x1 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_ON (0x3 << TGCR_POWERMODE_SHIFT)
++#define TGCR_POWER_MASK (0x3 << TGCR_POWERMODE_SHIFT)
++#define TGCR_INTREFEN (1 << 10)
++#define TGCR_ADCCLKCFG_SHIFT 16
++#define TGCR_PD_EN (1 << 23)
++#define TGCR_PDB_EN (1 << 24)
++#define TGCR_PDBTIME_SHIFT 25
++#define TGCR_PDBTIME128 (0x3f << TGCR_PDBTIME_SHIFT)
++#define TGCR_PDBTIME_MASK (0x7f << TGCR_PDBTIME_SHIFT)
++
++/* TSC General Status Register */
++#define TGSR 0x004
++#define TCQ_INT (1 << 0)
++#define GCQ_INT (1 << 1)
++#define SLP_INT (1 << 2)
++#define TCQ_DMA (1 << 16)
++#define GCQ_DMA (1 << 17)
++
++/* TSC IDLE Config Register */
++#define TICR 0x008
++
++/* TouchScreen Convert Queue FIFO Register */
++#define TCQFIFO 0x400
++/* TouchScreen Convert Queue Control Register */
++#define TCQCR 0x404
++#define CQCR_QSM_SHIFT 0
++#define CQCR_QSM_STOP (0x0 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_PEN (0x1 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_FQS (0x2 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_FQS_PEN (0x3 << CQCR_QSM_SHIFT)
++#define CQCR_QSM_MASK (0x3 << CQCR_QSM_SHIFT)
++#define CQCR_FQS (1 << 2)
++#define CQCR_RPT (1 << 3)
++#define CQCR_LAST_ITEM_ID_SHIFT 4
++#define CQCR_LAST_ITEM_ID_MASK (0xf << CQCR_LAST_ITEM_ID_SHIFT)
++#define CQCR_FIFOWATERMARK_SHIFT 8
++#define CQCR_FIFOWATERMARK_MASK (0xf << CQCR_FIFOWATERMARK_SHIFT)
++#define CQCR_REPEATWAIT_SHIFT 12
++#define CQCR_REPEATWAIT_MASK (0xf << CQCR_REPEATWAIT_SHIFT)
++#define CQCR_QRST (1 << 16)
++#define CQCR_FRST (1 << 17)
++#define CQCR_PD_MSK (1 << 18)
++#define CQCR_PD_CFG (1 << 19)
++
++/* TouchScreen Convert Queue Status Register */
++#define TCQSR 0x408
++#define CQSR_PD (1 << 0)
++#define CQSR_EOQ (1 << 1)
++#define CQSR_FOR (1 << 4)
++#define CQSR_FUR (1 << 5)
++#define CQSR_FER (1 << 6)
++#define CQSR_EMPT (1 << 13)
++#define CQSR_FULL (1 << 14)
++#define CQSR_FDRY (1 << 15)
++
++/* TouchScreen Convert Queue Mask Register */
++#define TCQMR 0x40c
++#define TCQMR_PD_IRQ_MSK (1 << 0)
++#define TCQMR_EOQ_IRQ_MSK (1 << 1)
++#define TCQMR_FOR_IRQ_MSK (1 << 4)
++#define TCQMR_FUR_IRQ_MSK (1 << 5)
++#define TCQMR_FER_IRQ_MSK (1 << 6)
++#define TCQMR_PD_DMA_MSK (1 << 16)
++#define TCQMR_EOQ_DMA_MSK (1 << 17)
++#define TCQMR_FOR_DMA_MSK (1 << 20)
++#define TCQMR_FUR_DMA_MSK (1 << 21)
++#define TCQMR_FER_DMA_MSK (1 << 22)
++#define TCQMR_FDRY_DMA_MSK (1 << 31)
++
++/* TouchScreen Convert Queue ITEM 7~0 */
++#define TCQ_ITEM_7_0 0x420
++
++/* TouchScreen Convert Queue ITEM 15~8 */
++#define TCQ_ITEM_15_8 0x424
++
++#define TCQ_ITEM7_SHIFT 28
++#define TCQ_ITEM6_SHIFT 24
++#define TCQ_ITEM5_SHIFT 20
++#define TCQ_ITEM4_SHIFT 16
++#define TCQ_ITEM3_SHIFT 12
++#define TCQ_ITEM2_SHIFT 8
++#define TCQ_ITEM1_SHIFT 4
++#define TCQ_ITEM0_SHIFT 0
++
++#define TCQ_ITEM_TCC0 0x0
++#define TCQ_ITEM_TCC1 0x1
++#define TCQ_ITEM_TCC2 0x2
++#define TCQ_ITEM_TCC3 0x3
++#define TCQ_ITEM_TCC4 0x4
++#define TCQ_ITEM_TCC5 0x5
++#define TCQ_ITEM_TCC6 0x6
++#define TCQ_ITEM_TCC7 0x7
++#define TCQ_ITEM_GCC7 0x8
++#define TCQ_ITEM_GCC6 0x9
++#define TCQ_ITEM_GCC5 0xa
++#define TCQ_ITEM_GCC4 0xb
++#define TCQ_ITEM_GCC3 0xc
++#define TCQ_ITEM_GCC2 0xd
++#define TCQ_ITEM_GCC1 0xe
++#define TCQ_ITEM_GCC0 0xf
++
++/* TouchScreen Convert Config 0-7 */
++#define TCC0 0x440
++#define TCC1 0x444
++#define TCC2 0x448
++#define TCC3 0x44c
++#define TCC4 0x450
++#define TCC5 0x454
++#define TCC6 0x458
++#define TCC7 0x45c
++#define CC_PEN_IACK (1 << 1)
++#define CC_SEL_REFN_SHIFT 2
++#define CC_SEL_REFN_YNLR (0x1 << CC_SEL_REFN_SHIFT)
++#define CC_SEL_REFN_AGND (0x2 << CC_SEL_REFN_SHIFT)
++#define CC_SEL_REFN_MASK (0x3 << CC_SEL_REFN_SHIFT)
++#define CC_SELIN_SHIFT 4
++#define CC_SELIN_XPUL (0x0 << CC_SELIN_SHIFT)
++#define CC_SELIN_YPLL (0x1 << CC_SELIN_SHIFT)
++#define CC_SELIN_XNUR (0x2 << CC_SELIN_SHIFT)
++#define CC_SELIN_YNLR (0x3 << CC_SELIN_SHIFT)
++#define CC_SELIN_WIPER (0x4 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX0 (0x5 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX1 (0x6 << CC_SELIN_SHIFT)
++#define CC_SELIN_INAUX2 (0x7 << CC_SELIN_SHIFT)
++#define CC_SELIN_MASK (0x7 << CC_SELIN_SHIFT)
++#define CC_SELREFP_SHIFT 7
++#define CC_SELREFP_YPLL (0x0 << CC_SELREFP_SHIFT)
++#define CC_SELREFP_XPUL (0x1 << CC_SELREFP_SHIFT)
++#define CC_SELREFP_EXT (0x2 << CC_SELREFP_SHIFT)
++#define CC_SELREFP_INT (0x3 << CC_SELREFP_SHIFT)
++#define CC_SELREFP_MASK (0x3 << CC_SELREFP_SHIFT)
++#define CC_XPULSW (1 << 9)
++#define CC_XNURSW_SHIFT 10
++#define CC_XNURSW_HIGH (0x0 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_OFF (0x1 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_LOW (0x3 << CC_XNURSW_SHIFT)
++#define CC_XNURSW_MASK (0x3 << CC_XNURSW_SHIFT)
++#define CC_YPLLSW_SHIFT 12
++#define CC_YPLLSW_MASK (0x3 << CC_YPLLSW_SHIFT)
++#define CC_YNLRSW (1 << 14)
++#define CC_WIPERSW (1 << 15)
++#define CC_NOS_SHIFT 16
++#define CC_YPLLSW_HIGH (0x0 << CC_NOS_SHIFT)
++#define CC_YPLLSW_OFF (0x1 << CC_NOS_SHIFT)
++#define CC_YPLLSW_LOW (0x3 << CC_NOS_SHIFT
++#define CC_NOS_MASK (0xf << CC_NOS_SHIFT)
++#define CC_IGS (1 << 20)
++#define CC_SETTLING_TIME_SHIFT 24
++#define CC_SETTLING_TIME_MASK (0xff << CC_SETTLING_TIME_SHIFT)
++
++#define TSC_4WIRE_PRECHARGE 0x158c
++#define TSC_4WIRE_TOUCH_DETECT 0x578e
++
++#define TSC_4WIRE_X_MEASUMENT 0x1c90
++#define TSC_4WIRE_Y_MEASUMENT 0x4604
++
++#define TSC_GENERAL_ADC_GCC0 0x17dc
++#define TSC_GENERAL_ADC_GCC1 0x17ec
++#define TSC_GENERAL_ADC_GCC2 0x17fc
++
++/* GeneralADC Convert Queue FIFO Register */
++#define GCQFIFO 0x800
++#define GCQFIFO_ADCOUT_SHIFT 4
++#define GCQFIFO_ADCOUT_MASK (0xfff << GCQFIFO_ADCOUT_SHIFT)
++/* GeneralADC Convert Queue Control Register */
++#define GCQCR 0x804
++/* GeneralADC Convert Queue Status Register */
++#define GCQSR 0x808
++/* GeneralADC Convert Queue Mask Register */
++#define GCQMR 0x80c
++
++/* GeneralADC Convert Queue ITEM 7~0 */
++#define GCQ_ITEM_7_0 0x820
++/* GeneralADC Convert Queue ITEM 15~8 */
++#define GCQ_ITEM_15_8 0x824
++
++#define GCQ_ITEM7_SHIFT 28
++#define GCQ_ITEM6_SHIFT 24
++#define GCQ_ITEM5_SHIFT 20
++#define GCQ_ITEM4_SHIFT 16
++#define GCQ_ITEM3_SHIFT 12
++#define GCQ_ITEM2_SHIFT 8
++#define GCQ_ITEM1_SHIFT 4
++#define GCQ_ITEM0_SHIFT 0
++
++#define GCQ_ITEM_GCC0 0x0
++#define GCQ_ITEM_GCC1 0x1
++#define GCQ_ITEM_GCC2 0x2
++#define GCQ_ITEM_GCC3 0x3
++
++/* GeneralADC Convert Config 0-7 */
++#define GCC0 0x840
++#define GCC1 0x844
++#define GCC2 0x848
++#define GCC3 0x84c
++#define GCC4 0x850
++#define GCC5 0x854
++#define GCC6 0x858
++#define GCC7 0x85c
++
++/* TSC Test Register R/W */
++#define TTR 0xc00
++/* TSC Monitor Register 1, 2 */
++#define MNT1 0xc04
++#define MNT2 0xc04
++
++#define DETECT_ITEM_ID_1 1
++#define DETECT_ITEM_ID_2 5
++#define TS_X_ITEM_ID 2
++#define TS_Y_ITEM_ID 3
++#define TSI_DATA 1
++#define FQS_DATA 0
++
++#endif /* __IMX_ADC_H__ */
+diff -urN linux.35.old/drivers/mxc/adc/Kconfig linux.35.new/drivers/mxc/adc/Kconfig
+--- linux.35.old/drivers/mxc/adc/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/adc/Kconfig 2010-12-03 09:51:55.452350145 +0100
+@@ -0,0 +1,14 @@
++#
++# i.MX ADC devices
++#
++
++menu "i.MX ADC support"
++
++config IMX_ADC
++ tristate "i.MX ADC"
++ depends on ARCH_MXC
++ default n
++ help
++ This selects the Freescale i.MX on-chip ADC driver.
++
++endmenu
+diff -urN linux.35.old/drivers/mxc/adc/Makefile linux.35.new/drivers/mxc/adc/Makefile
+--- linux.35.old/drivers/mxc/adc/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/adc/Makefile 2010-12-03 09:51:55.452350145 +0100
+@@ -0,0 +1,4 @@
++#
++# Makefile for i.MX adc devices.
++#
++obj-$(CONFIG_IMX_ADC) += imx_adc.o
+diff -urN linux.35.old/drivers/mxc/Kconfig linux.35.new/drivers/mxc/Kconfig
+--- linux.35.old/drivers/mxc/Kconfig 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/Kconfig 2010-12-03 09:51:55.452350145 +0100
+@@ -0,0 +1,11 @@
++# drivers/video/mxc/Kconfig
++
++if ARCH_MXC
++
++menu "MXC support drivers"
++
++source "drivers/mxc/adc/Kconfig"
++
++endmenu
++
++endif
+diff -urN linux.35.old/drivers/mxc/Makefile linux.35.new/drivers/mxc/Makefile
+--- linux.35.old/drivers/mxc/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/mxc/Makefile 2010-12-03 09:51:55.452350145 +0100
+@@ -0,0 +1 @@
++obj-y += adc/
+diff -urN linux.35.old/drivers/net/can/flexcan.c linux.35.new/drivers/net/can/flexcan.c
+--- linux.35.old/drivers/net/can/flexcan.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/net/can/flexcan.c 2010-12-03 09:51:55.456347637 +0100
+@@ -0,0 +1,1030 @@
++/*
++ * flexcan.c - FLEXCAN CAN controller driver
++ *
++ * Copyright (c) 2005-2006 Varma Electronics Oy
++ * Copyright (c) 2009 Sascha Hauer, Pengutronix
++ * Copyright (c) 2010 Marc Kleine-Budde, Pengutronix
++ *
++ * Based on code originally by Andrey Volkov <avolkov@varma-el.com>
++ *
++ * LICENCE:
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * 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.
++ *
++ */
++
++#include <linux/netdevice.h>
++#include <linux/can.h>
++#include <linux/can/dev.h>
++#include <linux/can/error.h>
++#include <linux/can/platform/flexcan.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/if_arp.h>
++#include <linux/if_ether.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include <mach/clock.h>
++
++#define DRV_NAME "flexcan"
++
++/* 8 for RX fifo and 2 error handling */
++#define FLEXCAN_NAPI_WEIGHT (8 + 2)
++
++/* FLEXCAN module configuration register (CANMCR) bits */
++#define FLEXCAN_MCR_MDIS BIT(31)
++#define FLEXCAN_MCR_FRZ BIT(30)
++#define FLEXCAN_MCR_FEN BIT(29)
++#define FLEXCAN_MCR_HALT BIT(28)
++#define FLEXCAN_MCR_NOT_RDY BIT(27)
++#define FLEXCAN_MCR_WAK_MSK BIT(26)
++#define FLEXCAN_MCR_SOFTRST BIT(25)
++#define FLEXCAN_MCR_FRZ_ACK BIT(24)
++#define FLEXCAN_MCR_SUPV BIT(23)
++#define FLEXCAN_MCR_SLF_WAK BIT(22)
++#define FLEXCAN_MCR_WRN_EN BIT(21)
++#define FLEXCAN_MCR_LPM_ACK BIT(20)
++#define FLEXCAN_MCR_WAK_SRC BIT(19)
++#define FLEXCAN_MCR_DOZE BIT(18)
++#define FLEXCAN_MCR_SRX_DIS BIT(17)
++#define FLEXCAN_MCR_BCC BIT(16)
++#define FLEXCAN_MCR_LPRIO_EN BIT(13)
++#define FLEXCAN_MCR_AEN BIT(12)
++#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf)
++#define FLEXCAN_MCR_IDAM_A (0 << 8)
++#define FLEXCAN_MCR_IDAM_B (1 << 8)
++#define FLEXCAN_MCR_IDAM_C (2 << 8)
++#define FLEXCAN_MCR_IDAM_D (3 << 8)
++
++/* FLEXCAN control register (CANCTRL) bits */
++#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24)
++#define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22)
++#define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19)
++#define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16)
++#define FLEXCAN_CTRL_BOFF_MSK BIT(15)
++#define FLEXCAN_CTRL_ERR_MSK BIT(14)
++#define FLEXCAN_CTRL_CLK_SRC BIT(13)
++#define FLEXCAN_CTRL_LPB BIT(12)
++#define FLEXCAN_CTRL_TWRN_MSK BIT(11)
++#define FLEXCAN_CTRL_RWRN_MSK BIT(10)
++#define FLEXCAN_CTRL_SMP BIT(7)
++#define FLEXCAN_CTRL_BOFF_REC BIT(6)
++#define FLEXCAN_CTRL_TSYN BIT(5)
++#define FLEXCAN_CTRL_LBUF BIT(4)
++#define FLEXCAN_CTRL_LOM BIT(3)
++#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07)
++#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK)
++#define FLEXCAN_CTRL_ERR_STATE \
++ (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \
++ FLEXCAN_CTRL_BOFF_MSK)
++#define FLEXCAN_CTRL_ERR_ALL \
++ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE)
++
++/* FLEXCAN error and status register (ESR) bits */
++#define FLEXCAN_ESR_TWRN_INT BIT(17)
++#define FLEXCAN_ESR_RWRN_INT BIT(16)
++#define FLEXCAN_ESR_BIT1_ERR BIT(15)
++#define FLEXCAN_ESR_BIT0_ERR BIT(14)
++#define FLEXCAN_ESR_ACK_ERR BIT(13)
++#define FLEXCAN_ESR_CRC_ERR BIT(12)
++#define FLEXCAN_ESR_FRM_ERR BIT(11)
++#define FLEXCAN_ESR_STF_ERR BIT(10)
++#define FLEXCAN_ESR_TX_WRN BIT(9)
++#define FLEXCAN_ESR_RX_WRN BIT(8)
++#define FLEXCAN_ESR_IDLE BIT(7)
++#define FLEXCAN_ESR_TXRX BIT(6)
++#define FLEXCAN_EST_FLT_CONF_SHIFT (4)
++#define FLEXCAN_ESR_FLT_CONF_MASK (0x3 << FLEXCAN_EST_FLT_CONF_SHIFT)
++#define FLEXCAN_ESR_FLT_CONF_ACTIVE (0x0 << FLEXCAN_EST_FLT_CONF_SHIFT)
++#define FLEXCAN_ESR_FLT_CONF_PASSIVE (0x1 << FLEXCAN_EST_FLT_CONF_SHIFT)
++#define FLEXCAN_ESR_BOFF_INT BIT(2)
++#define FLEXCAN_ESR_ERR_INT BIT(1)
++#define FLEXCAN_ESR_WAK_INT BIT(0)
++#define FLEXCAN_ESR_ERR_BUS \
++ (FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \
++ FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \
++ FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR)
++#define FLEXCAN_ESR_ERR_STATE \
++ (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT)
++#define FLEXCAN_ESR_ERR_ALL \
++ (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE)
++
++/* FLEXCAN interrupt flag register (IFLAG) bits */
++#define FLEXCAN_TX_BUF_ID 8
++#define FLEXCAN_IFLAG_BUF(x) BIT(x)
++#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7)
++#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6)
++#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5)
++#define FLEXCAN_IFLAG_DEFAULT \
++ (FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \
++ FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID))
++
++/* FLEXCAN message buffers */
++#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24)
++#define FLEXCAN_MB_CNT_SRR BIT(22)
++#define FLEXCAN_MB_CNT_IDE BIT(21)
++#define FLEXCAN_MB_CNT_RTR BIT(20)
++#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16)
++#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff)
++
++#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
++
++/* Structure of the message buffer */
++struct flexcan_mb {
++ u32 can_ctrl;
++ u32 can_id;
++ u32 data[2];
++};
++
++/* Structure of the hardware registers */
++struct flexcan_regs {
++ u32 mcr; /* 0x00 */
++ u32 ctrl; /* 0x04 */
++ u32 timer; /* 0x08 */
++ u32 _reserved1; /* 0x0c */
++ u32 rxgmask; /* 0x10 */
++ u32 rx14mask; /* 0x14 */
++ u32 rx15mask; /* 0x18 */
++ u32 ecr; /* 0x1c */
++ u32 esr; /* 0x20 */
++ u32 imask2; /* 0x24 */
++ u32 imask1; /* 0x28 */
++ u32 iflag2; /* 0x2c */
++ u32 iflag1; /* 0x30 */
++ u32 _reserved2[19];
++ struct flexcan_mb cantxfg[64];
++};
++
++struct flexcan_priv {
++ struct can_priv can;
++ struct net_device *dev;
++ struct napi_struct napi;
++
++ void __iomem *base;
++ u32 reg_esr;
++ u32 reg_ctrl_default;
++
++ struct clk *clk;
++ struct flexcan_platform_data *pdata;
++};
++
++static struct can_bittiming_const flexcan_bittiming_const = {
++ .name = DRV_NAME,
++ .tseg1_min = 4,
++ .tseg1_max = 16,
++ .tseg2_min = 2,
++ .tseg2_max = 8,
++ .sjw_max = 4,
++ .brp_min = 1,
++ .brp_max = 256,
++ .brp_inc = 1,
++};
++
++/*
++ * Swtich transceiver on or off
++ */
++static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on)
++{
++ if (priv->pdata && priv->pdata->transceiver_switch)
++ priv->pdata->transceiver_switch(on);
++}
++
++static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv,
++ u32 reg_esr)
++{
++ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) &&
++ (reg_esr & FLEXCAN_ESR_ERR_BUS);
++}
++
++static inline void flexcan_chip_enable(struct flexcan_priv *priv)
++{
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg;
++
++ reg = readl(®s->mcr);
++ reg &= ~FLEXCAN_MCR_MDIS;
++ writel(reg, ®s->mcr);
++
++ udelay(10);
++}
++
++static inline void flexcan_chip_disable(struct flexcan_priv *priv)
++{
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg;
++
++ reg = readl(®s->mcr);
++ reg |= FLEXCAN_MCR_MDIS;
++ writel(reg, ®s->mcr);
++}
++
++static int flexcan_get_berr_counter(const struct net_device *dev,
++ struct can_berr_counter *bec)
++{
++ const struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg = readl(®s->ecr);
++
++ bec->txerr = (reg >> 0) & 0xff;
++ bec->rxerr = (reg >> 8) & 0xff;
++
++ return 0;
++}
++
++static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++ const struct flexcan_priv *priv = netdev_priv(dev);
++ struct net_device_stats *stats = &dev->stats;
++ struct flexcan_regs __iomem *regs = priv->base;
++ struct can_frame *cf = (struct can_frame *)skb->data;
++ u32 can_id;
++ u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16);
++
++ if (can_dropped_invalid_skb(dev, skb))
++ return NETDEV_TX_OK;
++
++ netif_stop_queue(dev);
++
++ if (cf->can_id & CAN_EFF_FLAG) {
++ can_id = cf->can_id & CAN_EFF_MASK;
++ ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR;
++ } else {
++ can_id = (cf->can_id & CAN_SFF_MASK) << 18;
++ }
++
++ if (cf->can_id & CAN_RTR_FLAG)
++ ctrl |= FLEXCAN_MB_CNT_RTR;
++
++ if (cf->can_dlc > 0) {
++ u32 data = be32_to_cpup((__be32 *)&cf->data[0]);
++ writel(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
++ }
++ if (cf->can_dlc > 3) {
++ u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
++ writel(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
++ }
++
++ writel(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
++ writel(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl);
++
++ kfree_skb(skb);
++
++ /* tx_packets is incremented in flexcan_irq */
++ stats->tx_bytes += cf->can_dlc;
++
++ return NETDEV_TX_OK;
++}
++
++static void do_bus_err(struct net_device *dev,
++ struct can_frame *cf, u32 reg_esr)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ int rx_errors = 0, tx_errors = 0;
++
++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
++
++ if (reg_esr & FLEXCAN_ESR_BIT1_ERR) {
++ dev_dbg(dev->dev.parent, "BIT1_ERR irq\n");
++ cf->data[2] |= CAN_ERR_PROT_BIT1;
++ tx_errors = 1;
++ }
++ if (reg_esr & FLEXCAN_ESR_BIT0_ERR) {
++ dev_dbg(dev->dev.parent, "BIT0_ERR irq\n");
++ cf->data[2] |= CAN_ERR_PROT_BIT0;
++ tx_errors = 1;
++ }
++ if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
++ dev_dbg(dev->dev.parent, "ACK_ERR irq\n");
++ cf->can_id |= CAN_ERR_ACK;
++ cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
++ tx_errors = 1;
++ }
++ if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
++ dev_dbg(dev->dev.parent, "CRC_ERR irq\n");
++ cf->data[2] |= CAN_ERR_PROT_BIT;
++ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
++ rx_errors = 1;
++ }
++ if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
++ dev_dbg(dev->dev.parent, "FRM_ERR irq\n");
++ cf->data[2] |= CAN_ERR_PROT_FORM;
++ rx_errors = 1;
++ }
++ if (reg_esr & FLEXCAN_ESR_STF_ERR) {
++ dev_dbg(dev->dev.parent, "STF_ERR irq\n");
++ cf->data[2] |= CAN_ERR_PROT_STUFF;
++ rx_errors = 1;
++ }
++
++ priv->can.can_stats.bus_error++;
++ if (rx_errors)
++ dev->stats.rx_errors++;
++ if (tx_errors)
++ dev->stats.tx_errors++;
++}
++
++static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr)
++{
++ struct sk_buff *skb;
++ struct can_frame *cf;
++
++ skb = alloc_can_err_skb(dev, &cf);
++ if (unlikely(!skb))
++ return 0;
++
++ do_bus_err(dev, cf, reg_esr);
++ netif_receive_skb(skb);
++
++ dev->stats.rx_packets++;
++ dev->stats.rx_bytes += cf->can_dlc;
++
++ return 1;
++}
++
++static void do_state(struct net_device *dev,
++ struct can_frame *cf, enum can_state new_state)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct can_berr_counter bec;
++
++ flexcan_get_berr_counter(dev, &bec);
++
++ switch (priv->can.state) {
++ case CAN_STATE_ERROR_ACTIVE:
++ /*
++ * from: ERROR_ACTIVE
++ * to : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF
++ * => : there was a warning int
++ */
++ if (new_state >= CAN_STATE_ERROR_WARNING &&
++ new_state <= CAN_STATE_BUS_OFF) {
++ dev_dbg(dev->dev.parent, "Error Warning IRQ\n");
++ priv->can.can_stats.error_warning++;
++
++ cf->can_id |= CAN_ERR_CRTL;
++ cf->data[1] = (bec.txerr > bec.rxerr) ?
++ CAN_ERR_CRTL_TX_WARNING :
++ CAN_ERR_CRTL_RX_WARNING;
++ }
++ case CAN_STATE_ERROR_WARNING: /* fallthrough */
++ /*
++ * from: ERROR_ACTIVE, ERROR_WARNING
++ * to : ERROR_PASSIVE, BUS_OFF
++ * => : error passive int
++ */
++ if (new_state >= CAN_STATE_ERROR_PASSIVE &&
++ new_state <= CAN_STATE_BUS_OFF) {
++ dev_dbg(dev->dev.parent, "Error Passive IRQ\n");
++ priv->can.can_stats.error_passive++;
++
++ cf->can_id |= CAN_ERR_CRTL;
++ cf->data[1] = (bec.txerr > bec.rxerr) ?
++ CAN_ERR_CRTL_TX_PASSIVE :
++ CAN_ERR_CRTL_RX_PASSIVE;
++ }
++ break;
++ case CAN_STATE_BUS_OFF:
++ dev_err(dev->dev.parent,
++ "BUG! hardware recovered automatically from BUS_OFF\n");
++ break;
++ default:
++ break;
++ }
++
++ /* process state changes depending on the new state */
++ switch (new_state) {
++ case CAN_STATE_ERROR_ACTIVE:
++ dev_dbg(dev->dev.parent, "Error Active\n");
++ cf->can_id |= CAN_ERR_PROT;
++ cf->data[2] = CAN_ERR_PROT_ACTIVE;
++ break;
++ case CAN_STATE_BUS_OFF:
++ cf->can_id |= CAN_ERR_BUSOFF;
++ can_bus_off(dev);
++ break;
++ default:
++ break;
++ }
++}
++
++static int flexcan_poll_state(struct net_device *dev, u32 reg_esr)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct sk_buff *skb;
++ struct can_frame *cf;
++ enum can_state new_state;
++ int flt;
++
++ flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK;
++ if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) {
++ if (likely(!(reg_esr & (FLEXCAN_ESR_TX_WRN |
++ FLEXCAN_ESR_RX_WRN))))
++ new_state = CAN_STATE_ERROR_ACTIVE;
++ else
++ new_state = CAN_STATE_ERROR_WARNING;
++ } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE))
++ new_state = CAN_STATE_ERROR_PASSIVE;
++ else
++ new_state = CAN_STATE_BUS_OFF;
++
++ /* state hasn't changed */
++ if (likely(new_state == priv->can.state))
++ return 0;
++
++ skb = alloc_can_err_skb(dev, &cf);
++ if (unlikely(!skb))
++ return 0;
++
++ do_state(dev, cf, new_state);
++ priv->can.state = new_state;
++ netif_receive_skb(skb);
++
++ dev->stats.rx_packets++;
++ dev->stats.rx_bytes += cf->can_dlc;
++
++ return 1;
++}
++
++static void flexcan_read_fifo(const struct net_device *dev,
++ struct can_frame *cf)
++{
++ const struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ struct flexcan_mb __iomem *mb = ®s->cantxfg[0];
++ u32 reg_ctrl, reg_id;
++
++ reg_ctrl = readl(&mb->can_ctrl);
++ reg_id = readl(&mb->can_id);
++ if (reg_ctrl & FLEXCAN_MB_CNT_IDE)
++ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG;
++ else
++ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK;
++
++ if (reg_ctrl & FLEXCAN_MB_CNT_RTR)
++ cf->can_id |= CAN_RTR_FLAG;
++ cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
++
++ *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0]));
++ *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1]));
++
++ /* mark as read */
++ writel(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1);
++ readl(®s->timer);
++}
++
++static int flexcan_read_frame(struct net_device *dev)
++{
++ struct net_device_stats *stats = &dev->stats;
++ struct can_frame *cf;
++ struct sk_buff *skb;
++
++ skb = alloc_can_skb(dev, &cf);
++ if (unlikely(!skb)) {
++ stats->rx_dropped++;
++ return 0;
++ }
++
++ flexcan_read_fifo(dev, cf);
++ netif_receive_skb(skb);
++
++ stats->rx_packets++;
++ stats->rx_bytes += cf->can_dlc;
++
++ return 1;
++}
++
++static int flexcan_poll(struct napi_struct *napi, int quota)
++{
++ struct net_device *dev = napi->dev;
++ const struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg_iflag1, reg_esr;
++ int work_done = 0;
++
++ /*
++ * The error bits are cleared on read,
++ * use saved value from irq handler.
++ */
++ reg_esr = readl(®s->esr) | priv->reg_esr;
++
++ /* handle state changes */
++ work_done += flexcan_poll_state(dev, reg_esr);
++
++ /* handle RX-FIFO */
++ reg_iflag1 = readl(®s->iflag1);
++ while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
++ work_done < quota) {
++ work_done += flexcan_read_frame(dev);
++ reg_iflag1 = readl(®s->iflag1);
++ }
++
++ /* report bus errors */
++ if (flexcan_has_and_handle_berr(priv, reg_esr) && work_done < quota)
++ work_done += flexcan_poll_bus_err(dev, reg_esr);
++
++ if (work_done < quota) {
++ napi_complete(napi);
++ /* enable IRQs */
++ writel(FLEXCAN_IFLAG_DEFAULT, ®s->imask1);
++ writel(priv->reg_ctrl_default, ®s->ctrl);
++ }
++
++ return work_done;
++}
++
++static irqreturn_t flexcan_irq(int irq, void *dev_id)
++{
++ struct net_device *dev = dev_id;
++ struct net_device_stats *stats = &dev->stats;
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg_iflag1, reg_esr;
++
++ reg_iflag1 = readl(®s->iflag1);
++ reg_esr = readl(®s->esr);
++ writel(FLEXCAN_ESR_ERR_INT, ®s->esr); /* ACK err IRQ */
++
++ /*
++ * schedule NAPI in case of:
++ * - rx IRQ
++ * - state change IRQ
++ * - bus error IRQ and bus error reporting is activated
++ */
++ if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) ||
++ (reg_esr & FLEXCAN_ESR_ERR_STATE) ||
++ flexcan_has_and_handle_berr(priv, reg_esr)) {
++ /*
++ * The error bits are cleared on read,
++ * save them for later use.
++ */
++ priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS;
++ writel(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE,
++ ®s->imask1);
++ writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
++ ®s->ctrl);
++ napi_schedule(&priv->napi);
++ }
++
++ /* FIFO overflow */
++ if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
++ writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, ®s->iflag1);
++ dev->stats.rx_over_errors++;
++ dev->stats.rx_errors++;
++ }
++
++ /* transmission complete interrupt */
++ if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) {
++ /* tx_bytes is incremented in flexcan_start_xmit */
++ stats->tx_packets++;
++ writel((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1);
++ netif_wake_queue(dev);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void flexcan_set_bittiming(struct net_device *dev)
++{
++ const struct flexcan_priv *priv = netdev_priv(dev);
++ const struct can_bittiming *bt = &priv->can.bittiming;
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg;
++
++ reg = readl(®s->ctrl);
++ reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) |
++ FLEXCAN_CTRL_RJW(0x3) |
++ FLEXCAN_CTRL_PSEG1(0x7) |
++ FLEXCAN_CTRL_PSEG2(0x7) |
++ FLEXCAN_CTRL_PROPSEG(0x7) |
++ FLEXCAN_CTRL_LPB |
++ FLEXCAN_CTRL_SMP |
++ FLEXCAN_CTRL_LOM);
++
++ reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) |
++ FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) |
++ FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) |
++ FLEXCAN_CTRL_RJW(bt->sjw - 1) |
++ FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1);
++
++ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
++ reg |= FLEXCAN_CTRL_LPB;
++ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
++ reg |= FLEXCAN_CTRL_LOM;
++ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
++ reg |= FLEXCAN_CTRL_SMP;
++
++ dev_info(dev->dev.parent, "writing ctrl=0x%08x\n", reg);
++ writel(reg, ®s->ctrl);
++
++ /* print chip status */
++ dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
++ readl(®s->mcr), readl(®s->ctrl));
++}
++
++/*
++ * flexcan_chip_start
++ *
++ * this functions is entered with clocks enabled
++ *
++ */
++static int flexcan_chip_start(struct net_device *dev)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ unsigned int i;
++ int err;
++ u32 reg_mcr, reg_ctrl;
++
++ /* enable module */
++ flexcan_chip_enable(priv);
++
++ /* soft reset */
++ writel(FLEXCAN_MCR_SOFTRST, ®s->mcr);
++ udelay(10);
++
++ reg_mcr = readl(®s->mcr);
++ if (reg_mcr & FLEXCAN_MCR_SOFTRST) {
++ dev_err(dev->dev.parent,
++ "Failed to softreset can module (mcr=0x%08x)\n",
++ reg_mcr);
++ err = -ENODEV;
++ goto out;
++ }
++
++ flexcan_set_bittiming(dev);
++
++ /*
++ * MCR
++ *
++ * enable freeze
++ * enable fifo
++ * halt now
++ * only supervisor access
++ * enable warning int
++ * choose format C
++ *
++ */
++ reg_mcr = readl(®s->mcr);
++ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT |
++ FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN |
++ FLEXCAN_MCR_IDAM_C;
++ dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr);
++ writel(reg_mcr, ®s->mcr);
++
++ /*
++ * CTRL
++ *
++ * disable timer sync feature
++ *
++ * disable auto busoff recovery
++ * transmit lowest buffer first
++ *
++ * enable tx and rx warning interrupt
++ * enable bus off interrupt
++ * (== FLEXCAN_CTRL_ERR_STATE)
++ *
++ * _note_: we enable the "error interrupt"
++ * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any
++ * warning or bus passive interrupts.
++ */
++ reg_ctrl = readl(®s->ctrl);
++ reg_ctrl &= ~FLEXCAN_CTRL_TSYN;
++ reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF |
++ FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK;
++
++ /* save for later use */
++ priv->reg_ctrl_default = reg_ctrl;
++ dev_dbg(dev->dev.parent, "%s: writing ctrl=0x%08x", __func__, reg_ctrl);
++ writel(reg_ctrl, ®s->ctrl);
++
++ for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
++ writel(0, ®s->cantxfg[i].can_ctrl);
++ writel(0, ®s->cantxfg[i].can_id);
++ writel(0, ®s->cantxfg[i].data[0]);
++ writel(0, ®s->cantxfg[i].data[1]);
++
++ /* put MB into rx queue */
++ writel(FLEXCAN_MB_CNT_CODE(0x4), ®s->cantxfg[i].can_ctrl);
++ }
++
++ /* acceptance mask/acceptance code (accept everything) */
++ writel(0x0, ®s->rxgmask);
++ writel(0x0, ®s->rx14mask);
++ writel(0x0, ®s->rx15mask);
++
++ flexcan_transceiver_switch(priv, 1);
++
++ /* synchronize with the can bus */
++ reg_mcr = readl(®s->mcr);
++ reg_mcr &= ~FLEXCAN_MCR_HALT;
++ writel(reg_mcr, ®s->mcr);
++
++ priv->can.state = CAN_STATE_ERROR_ACTIVE;
++
++ /* enable FIFO interrupts */
++ writel(FLEXCAN_IFLAG_DEFAULT, ®s->imask1);
++
++ /* print chip status */
++ dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n",
++ __func__, readl(®s->mcr), readl(®s->ctrl));
++
++ return 0;
++
++ out:
++ flexcan_chip_disable(priv);
++ return err;
++}
++
++/*
++ * flexcan_chip_stop
++ *
++ * this functions is entered with clocks enabled
++ *
++ */
++static void flexcan_chip_stop(struct net_device *dev)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg;
++
++ /* Disable all interrupts */
++ writel(0, ®s->imask1);
++
++ /* Disable + halt module */
++ reg = readl(®s->mcr);
++ reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
++ writel(reg, ®s->mcr);
++
++ flexcan_transceiver_switch(priv, 0);
++ priv->can.state = CAN_STATE_STOPPED;
++
++ return;
++}
++
++static int flexcan_open(struct net_device *dev)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ int err;
++
++ clk_enable(priv->clk);
++
++ err = open_candev(dev);
++ if (err)
++ goto out;
++
++ err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev);
++ if (err)
++ goto out_close;
++
++ /* start chip and queuing */
++ err = flexcan_chip_start(dev);
++ if (err)
++ goto out_close;
++ napi_enable(&priv->napi);
++ netif_start_queue(dev);
++
++ return 0;
++
++ out_close:
++ close_candev(dev);
++ out:
++ clk_disable(priv->clk);
++
++ return err;
++}
++
++static int flexcan_close(struct net_device *dev)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++
++ netif_stop_queue(dev);
++ napi_disable(&priv->napi);
++ flexcan_chip_stop(dev);
++
++ free_irq(dev->irq, dev);
++ clk_disable(priv->clk);
++
++ close_candev(dev);
++
++ return 0;
++}
++
++static int flexcan_set_mode(struct net_device *dev, enum can_mode mode)
++{
++ int err;
++
++ switch (mode) {
++ case CAN_MODE_START:
++ err = flexcan_chip_start(dev);
++ if (err)
++ return err;
++
++ netif_wake_queue(dev);
++ break;
++
++ default:
++ return -EOPNOTSUPP;
++ }
++
++ return 0;
++}
++
++static const struct net_device_ops flexcan_netdev_ops = {
++ .ndo_open = flexcan_open,
++ .ndo_stop = flexcan_close,
++ .ndo_start_xmit = flexcan_start_xmit,
++};
++
++static int __devinit register_flexcandev(struct net_device *dev)
++{
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg, err;
++
++ clk_enable(priv->clk);
++
++ /* select "bus clock", chip must be disabled */
++ flexcan_chip_disable(priv);
++ reg = readl(®s->ctrl);
++ reg |= FLEXCAN_CTRL_CLK_SRC;
++ writel(reg, ®s->ctrl);
++
++ flexcan_chip_enable(priv);
++
++ /* set freeze, halt and activate FIFO, restrict register access */
++ reg = readl(®s->mcr);
++ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
++ FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
++ writel(reg, ®s->mcr);
++
++ /*
++ * Currently we only support newer versions of this core
++ * featuring a RX FIFO. Older cores found on some Coldfire
++ * derivates are not yet supported.
++ */
++ reg = readl(®s->mcr);
++ if (!(reg & FLEXCAN_MCR_FEN)) {
++ dev_err(dev->dev.parent,
++ "Could not enable RX FIFO, unsupported core\n");
++ err = -ENODEV;
++ goto out;
++ }
++
++ err = register_candev(dev);
++
++ out:
++ /* disable core and turn off clocks */
++ flexcan_chip_disable(priv);
++ clk_disable(priv->clk);
++
++ return err;
++}
++
++static void __devexit unregister_flexcandev(struct net_device *dev)
++{
++ unregister_candev(dev);
++}
++
++static int __devinit flexcan_probe(struct platform_device *pdev)
++{
++ struct net_device *dev;
++ struct flexcan_priv *priv;
++ struct resource *mem;
++ struct clk *clk;
++ void __iomem *base;
++ resource_size_t mem_size;
++ int err, irq;
++
++ clk = clk_get(&pdev->dev, NULL);
++ if (IS_ERR(clk)) {
++ dev_err(&pdev->dev, "no clock defined\n");
++ err = PTR_ERR(clk);
++ goto failed_clock;
++ }
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ irq = platform_get_irq(pdev, 0);
++ if (!mem || irq <= 0) {
++ err = -ENODEV;
++ goto failed_get;
++ }
++
++ mem_size = resource_size(mem);
++ if (!request_mem_region(mem->start, mem_size, pdev->name)) {
++ err = -EBUSY;
++ goto failed_req;
++ }
++
++ base = ioremap(mem->start, mem_size);
++ if (!base) {
++ err = -ENOMEM;
++ goto failed_map;
++ }
++
++ dev = alloc_candev(sizeof(struct flexcan_priv), 0);
++ if (!dev) {
++ err = -ENOMEM;
++ goto failed_alloc;
++ }
++
++ dev->netdev_ops = &flexcan_netdev_ops;
++ dev->irq = irq;
++ dev->flags |= IFF_ECHO; /* we support local echo in hardware */
++
++ priv = netdev_priv(dev);
++ priv->can.clock.freq = clk_get_rate(clk);
++ priv->can.bittiming_const = &flexcan_bittiming_const;
++ priv->can.do_set_mode = flexcan_set_mode;
++ priv->can.do_get_berr_counter = flexcan_get_berr_counter;
++ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
++ CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
++ CAN_CTRLMODE_BERR_REPORTING;
++ priv->base = base;
++ priv->dev = dev;
++ priv->clk = clk;
++ priv->pdata = pdev->dev.platform_data;
++
++ netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT);
++
++ dev_set_drvdata(&pdev->dev, dev);
++ SET_NETDEV_DEV(dev, &pdev->dev);
++
++ err = register_flexcandev(dev);
++ if (err) {
++ dev_err(&pdev->dev, "registering netdev failed\n");
++ goto failed_register;
++ }
++
++ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n",
++ priv->base, dev->irq);
++
++ return 0;
++
++ failed_register:
++ free_candev(dev);
++ failed_alloc:
++ iounmap(base);
++ failed_map:
++ release_mem_region(mem->start, mem_size);
++ failed_req:
++ clk_put(clk);
++ failed_get:
++ failed_clock:
++ return err;
++}
++
++static int __devexit flexcan_remove(struct platform_device *pdev)
++{
++ struct net_device *dev = platform_get_drvdata(pdev);
++ struct flexcan_priv *priv = netdev_priv(dev);
++ struct resource *mem;
++
++ unregister_flexcandev(dev);
++ platform_set_drvdata(pdev, NULL);
++ free_candev(dev);
++ iounmap(priv->base);
++
++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ release_mem_region(mem->start, resource_size(mem));
++
++ clk_put(priv->clk);
++
++ return 0;
++}
++
++static struct platform_driver flexcan_driver = {
++ .driver.name = DRV_NAME,
++ .probe = flexcan_probe,
++ .remove = __devexit_p(flexcan_remove),
++};
++
++static int __init flexcan_init(void)
++{
++ pr_info("%s netdevice driver\n", DRV_NAME);
++ return platform_driver_register(&flexcan_driver);
++}
++
++static void __exit flexcan_exit(void)
++{
++ platform_driver_unregister(&flexcan_driver);
++ pr_info("%s: driver removed\n", DRV_NAME);
++}
++
++module_init(flexcan_init);
++module_exit(flexcan_exit);
++
++MODULE_AUTHOR("Sascha Hauer <kernel@pengutronix.de>, "
++ "Marc Kleine-Budde <kernel@pengutronix.de>");
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("CAN port driver for flexcan based chip");
+diff -urN linux.35.old/drivers/net/can/Kconfig linux.35.new/drivers/net/can/Kconfig
+--- linux.35.old/drivers/net/can/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/net/can/Kconfig 2010-12-03 09:51:55.456347637 +0100
+@@ -73,6 +73,15 @@
+ This driver can also be built as a module. If so, the module will be
+ called janz-ican3.ko.
+
++config HAVE_CAN_FLEXCAN
++ bool
++
++config CAN_FLEXCAN
++ tristate "Support for Freescale FLEXCAN based chips"
++ depends on CAN_DEV && HAVE_CAN_FLEXCAN
++ ---help---
++ Say Y here if you want to support for Freescale FlexCAN.
++
+ source "drivers/net/can/mscan/Kconfig"
+
+ source "drivers/net/can/sja1000/Kconfig"
+diff -urN linux.35.old/drivers/net/can/Makefile linux.35.new/drivers/net/can/Makefile
+--- linux.35.old/drivers/net/can/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/net/can/Makefile 2010-12-03 09:51:55.456347637 +0100
+@@ -16,5 +16,6 @@
+ obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
+ obj-$(CONFIG_CAN_BFIN) += bfin_can.o
+ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
++obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
+
+ ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
+diff -urN linux.35.old/drivers/net/fec.c linux.35.new/drivers/net/fec.c
+--- linux.35.old/drivers/net/fec.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/net/fec.c 2010-12-03 09:51:55.460348141 +0100
+@@ -118,6 +118,8 @@
+ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
+ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+
++#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII)
++
+ /* The FEC stores dest/src/type, data, and checksum for receive packets.
+ */
+ #define PKT_MAXBUF_SIZE 1518
+@@ -187,6 +189,7 @@
+ int index;
+ int link;
+ int full_duplex;
++ struct completion mdio_done;
+ };
+
+ static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
+@@ -205,12 +208,12 @@
+ #define FEC_MMFR_TA (2 << 16)
+ #define FEC_MMFR_DATA(v) (v & 0xffff)
+
+-#define FEC_MII_TIMEOUT 10000
++#define FEC_MII_TIMEOUT 1000 /* us */
+
+ /* Transmitter timeout */
+ #define TX_TIMEOUT (2 * HZ)
+
+-static int
++static netdev_tx_t
+ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct fec_enet_private *fep = netdev_priv(dev);
+@@ -334,6 +337,11 @@
+ ret = IRQ_HANDLED;
+ fec_enet_tx(dev);
+ }
++
++ if (int_events & FEC_ENET_MII) {
++ ret = IRQ_HANDLED;
++ complete(&fep->mdio_done);
++ }
+ } while (int_events);
+
+ return ret;
+@@ -608,18 +616,13 @@
+ phy_print_status(phy_dev);
+ }
+
+-/*
+- * NOTE: a MII transaction is during around 25 us, so polling it...
+- */
+ static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+ {
+ struct fec_enet_private *fep = bus->priv;
+- int timeout = FEC_MII_TIMEOUT;
++ unsigned long time_left;
+
+ fep->mii_timeout = 0;
+-
+- /* clear MII end of transfer bit*/
+- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
++ init_completion(&fep->mdio_done);
+
+ /* start a read op */
+ writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+@@ -627,13 +630,12 @@
+ FEC_MMFR_TA, fep->hwp + FEC_MII_DATA);
+
+ /* wait for end of transfer */
+- while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
+- cpu_relax();
+- if (timeout-- < 0) {
+- fep->mii_timeout = 1;
+- printk(KERN_ERR "FEC: MDIO read timeout\n");
+- return -ETIMEDOUT;
+- }
++ time_left = wait_for_completion_timeout(&fep->mdio_done,
++ usecs_to_jiffies(FEC_MII_TIMEOUT));
++ if (time_left == 0) {
++ fep->mii_timeout = 1;
++ printk(KERN_ERR "FEC: MDIO read timeout\n");
++ return -ETIMEDOUT;
+ }
+
+ /* return value */
+@@ -644,12 +646,10 @@
+ u16 value)
+ {
+ struct fec_enet_private *fep = bus->priv;
+- int timeout = FEC_MII_TIMEOUT;
++ unsigned long time_left;
+
+ fep->mii_timeout = 0;
+-
+- /* clear MII end of transfer bit*/
+- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
++ init_completion(&fep->mdio_done);
+
+ /* start a read op */
+ writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+@@ -658,13 +658,12 @@
+ fep->hwp + FEC_MII_DATA);
+
+ /* wait for end of transfer */
+- while (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_MII)) {
+- cpu_relax();
+- if (timeout-- < 0) {
+- fep->mii_timeout = 1;
+- printk(KERN_ERR "FEC: MDIO write timeout\n");
+- return -ETIMEDOUT;
+- }
++ time_left = wait_for_completion_timeout(&fep->mdio_done,
++ usecs_to_jiffies(FEC_MII_TIMEOUT));
++ if (time_left == 0) {
++ fep->mii_timeout = 1;
++ printk(KERN_ERR "FEC: MDIO write timeout\n");
++ return -ETIMEDOUT;
+ }
+
+ return 0;
+@@ -679,30 +678,24 @@
+ {
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phy_dev = NULL;
+- int phy_addr;
++ int ret;
+
+ fep->phy_dev = NULL;
+
+ /* find the first phy */
+- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+- if (fep->mii_bus->phy_map[phy_addr]) {
+- phy_dev = fep->mii_bus->phy_map[phy_addr];
+- break;
+- }
+- }
+-
++ phy_dev = phy_find_first(fep->mii_bus);
+ if (!phy_dev) {
+ printk(KERN_ERR "%s: no PHY found\n", dev->name);
+ return -ENODEV;
+ }
+
+ /* attach the mac to the phy */
+- phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
++ ret = phy_connect_direct(dev, phy_dev,
+ &fec_enet_adjust_link, 0,
+ PHY_INTERFACE_MODE_MII);
+- if (IS_ERR(phy_dev)) {
++ if (ret) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+- return PTR_ERR(phy_dev);
++ return ret;
+ }
+
+ /* mask with MAC supported features */
+@@ -834,7 +827,7 @@
+ if (!phydev)
+ return -ENODEV;
+
+- return phy_mii_ioctl(phydev, if_mii(rq), cmd);
++ return phy_mii_ioctl(phydev, rq, cmd);
+ }
+
+ static void fec_enet_free_buffers(struct net_device *dev)
+@@ -1222,7 +1215,7 @@
+ writel(0, fep->hwp + FEC_R_DES_ACTIVE);
+
+ /* Enable interrupts we wish to service */
+- writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->hwp + FEC_IMASK);
++ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ }
+
+ static void
+@@ -1241,11 +1234,8 @@
+ /* Whack a reset. We should wait for this. */
+ writel(1, fep->hwp + FEC_ECNTRL);
+ udelay(10);
+-
+- /* Clear outstanding MII command interrupts. */
+- writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
+-
+ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
++ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ }
+
+ static int __devinit
+@@ -1365,10 +1355,11 @@
+ return 0;
+ }
+
++#ifdef CONFIG_PM
+ static int
+-fec_suspend(struct platform_device *dev, pm_message_t state)
++fec_suspend(struct device *dev)
+ {
+- struct net_device *ndev = platform_get_drvdata(dev);
++ struct net_device *ndev = dev_get_drvdata(dev);
+ struct fec_enet_private *fep;
+
+ if (ndev) {
+@@ -1381,9 +1372,9 @@
+ }
+
+ static int
+-fec_resume(struct platform_device *dev)
++fec_resume(struct device *dev)
+ {
+- struct net_device *ndev = platform_get_drvdata(dev);
++ struct net_device *ndev = dev_get_drvdata(dev);
+ struct fec_enet_private *fep;
+
+ if (ndev) {
+@@ -1395,15 +1386,26 @@
+ return 0;
+ }
+
++static const struct dev_pm_ops fec_pm_ops = {
++ .suspend = fec_suspend,
++ .resume = fec_resume,
++ .freeze = fec_suspend,
++ .thaw = fec_resume,
++ .poweroff = fec_suspend,
++ .restore = fec_resume,
++};
++#endif
++
+ static struct platform_driver fec_driver = {
+ .driver = {
+- .name = "fec",
+- .owner = THIS_MODULE,
++ .name = "fec",
++ .owner = THIS_MODULE,
++#ifdef CONFIG_PM
++ .pm = &fec_pm_ops,
++#endif
+ },
+- .probe = fec_probe,
+- .remove = __devexit_p(fec_drv_remove),
+- .suspend = fec_suspend,
+- .resume = fec_resume,
++ .probe = fec_probe,
++ .remove = __devexit_p(fec_drv_remove),
+ };
+
+ static int __init
+diff -urN linux.35.old/drivers/net/phy/phy.c linux.35.new/drivers/net/phy/phy.c
+--- linux.35.old/drivers/net/phy/phy.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/net/phy/phy.c 2010-12-03 09:51:55.460348141 +0100
+@@ -309,8 +309,9 @@
+ * current state. Use at own risk.
+ */
+ int phy_mii_ioctl(struct phy_device *phydev,
+- struct mii_ioctl_data *mii_data, int cmd)
++ struct ifreq *ifr, int cmd)
+ {
++ struct mii_ioctl_data *mii_data = if_mii(ifr);
+ u16 val = mii_data->val_in;
+
+ switch (cmd) {
+@@ -360,6 +361,11 @@
+ }
+ break;
+
++ case SIOCSHWTSTAMP:
++ if (phydev->drv->hwtstamp)
++ return phydev->drv->hwtstamp(phydev, ifr);
++ /* fall through */
++
+ default:
+ return -EOPNOTSUPP;
+ }
+diff -urN linux.35.old/drivers/net/phy/phy_device.c linux.35.new/drivers/net/phy/phy_device.c
+--- linux.35.old/drivers/net/phy/phy_device.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/net/phy/phy_device.c 2010-12-03 09:51:55.460348141 +0100
+@@ -460,6 +460,7 @@
+ }
+
+ phydev->attached_dev = dev;
++ dev->phydev = phydev;
+
+ phydev->dev_flags = flags;
+
+@@ -513,6 +514,7 @@
+ */
+ void phy_detach(struct phy_device *phydev)
+ {
++ phydev->attached_dev->phydev = NULL;
+ phydev->attached_dev = NULL;
+
+ /* If the device had no specific driver before (i.e. - it
+diff -urN linux.35.old/drivers/rtc/Kconfig linux.35.new/drivers/rtc/Kconfig
+--- linux.35.old/drivers/rtc/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/rtc/Kconfig 2010-12-03 09:51:55.464349671 +0100
+@@ -548,6 +548,13 @@
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-mxc".
+
++config RTC_DRV_IMXDI
++ tristate "Freescale IMX DryIce Real Time Clock"
++ depends on ARCH_MXC
++ depends on RTC_CLASS
++ help
++ Support for Freescale IMX DryIce RTC
++
+ config RTC_DRV_BQ4802
+ tristate "TI BQ4802"
+ help
+diff -urN linux.35.old/drivers/rtc/Makefile linux.35.new/drivers/rtc/Makefile
+--- linux.35.old/drivers/rtc/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/rtc/Makefile 2010-12-03 09:51:55.464349671 +0100
+@@ -53,6 +53,7 @@
+ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
+ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+ obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
++obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
+ obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+ obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
+ obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+diff -urN linux.35.old/drivers/rtc/rtc-imxdi.c linux.35.new/drivers/rtc/rtc-imxdi.c
+--- linux.35.old/drivers/rtc/rtc-imxdi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/drivers/rtc/rtc-imxdi.c 2010-12-03 09:51:55.468347409 +0100
+@@ -0,0 +1,658 @@
++/*
++ * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/* based on rtc-mc13892.c */
++
++/*
++ * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block
++ * to implement a Linux RTC. Times and alarms are truncated to seconds.
++ * Since the RTC framework performs API locking via rtc->ops_lock the
++ * only simultaneous accesses we need to deal with is updating DryIce
++ * registers while servicing an alarm.
++ *
++ * Note that reading the DSR (DryIce Status Register) automatically clears
++ * the WCF (Write Complete Flag). All DryIce writes are synchronized to the
++ * LP (Low Power) domain and set the WCF upon completion. Writes to the
++ * DIER (DryIce Interrupt Enable Register) are the only exception. These
++ * occur at normal bus speeds and do not set WCF. Periodic interrupts are
++ * not supported by the hardware.
++ */
++
++/* #define DEBUG */
++/* #define DI_DEBUG_REGIO */
++
++#include <linux/io.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/rtc.h>
++#include <linux/workqueue.h>
++#include <linux/slab.h>
++
++/* DryIce Register Definitions */
++
++#define DTCMR 0x00 /* Time Counter MSB Reg */
++#define DTCLR 0x04 /* Time Counter LSB Reg */
++
++#define DCAMR 0x08 /* Clock Alarm MSB Reg */
++#define DCALR 0x0c /* Clock Alarm LSB Reg */
++#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
++
++#define DCR 0x10 /* Control Reg */
++#define DCR_TCE (1 << 3) /* Time Counter Enable */
++
++#define DSR 0x14 /* Status Reg */
++#define DSR_WBF (1 << 10) /* Write Busy Flag */
++#define DSR_WNF (1 << 9) /* Write Next Flag */
++#define DSR_WCF (1 << 8) /* Write Complete Flag */
++#define DSR_WEF (1 << 7) /* Write Error Flag */
++#define DSR_CAF (1 << 4) /* Clock Alarm Flag */
++#define DSR_NVF (1 << 1) /* Non-Valid Flag */
++#define DSR_SVF (1 << 0) /* Security Violation Flag */
++
++#define DIER 0x18 /* Interrupt Enable Reg */
++#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
++#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
++#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
++#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
++
++#ifndef DI_DEBUG_REGIO
++/* dryice read register */
++#define di_read(pdata, reg) __raw_readl((pdata)->ioaddr + (reg))
++
++/* dryice write register */
++#define di_write(pdata, val, reg) __raw_writel((val), (pdata)->ioaddr + (reg))
++#else
++/* dryice read register - debug version */
++static inline u32 di_read(struct rtc_drv_data *pdata, int reg)
++{
++ u32 val = __raw_readl(pdata->ioaddr + reg);
++ pr_info("di_read(0x%02x) = 0x%08x\n", reg, val);
++ return val;
++}
++
++/* dryice write register - debug version */
++static inline void di_write(struct rtc_drv_data *pdata, u32 val, int reg)
++{
++ printk(KERN_INFO "di_write(0x%08x, 0x%02x)\n", val, reg);
++ __raw_writel(val, pdata->ioaddr + reg);
++}
++#endif
++
++/*
++ * dryice write register with wait and error handling.
++ * all registers, except for DIER, should use this method.
++ */
++#define di_write_wait_err(pdata, val, reg, rc, label) \
++ do { \
++ if (di_write_wait((pdata), (val), (reg))) { \
++ rc = -EIO; \
++ goto label; \
++ } \
++ } while (0)
++
++struct rtc_drv_data {
++ struct platform_device *pdev; /* pointer to platform dev */
++ struct rtc_device *rtc; /* pointer to rtc struct */
++ unsigned long baseaddr; /* physical bass address */
++ void __iomem *ioaddr; /* virtual base address */
++ int size; /* size of register region */
++ int irq; /* dryice normal irq */
++ struct clk *clk; /* dryice clock control */
++ u32 dsr; /* copy of dsr reg from isr */
++ wait_queue_head_t write_wait; /* write-complete queue */
++ struct mutex write_mutex; /* force reg writes to be sequential */
++ struct work_struct work; /* schedule alarm work */
++};
++
++static spinlock_t irq_lock = SPIN_LOCK_UNLOCKED; /* irq resource lock */
++
++/*
++ * enable a dryice interrupt
++ */
++static inline void di_int_enable(struct rtc_drv_data *pdata, u32 intr)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&irq_lock, flags);
++ di_write(pdata, di_read(pdata, DIER) | intr, DIER);
++ spin_unlock_irqrestore(&irq_lock, flags);
++}
++
++/*
++ * disable a dryice interrupt
++ */
++static inline void di_int_disable(struct rtc_drv_data *pdata, u32 intr)
++{
++ unsigned long flags;
++
++ spin_lock_irqsave(&irq_lock, flags);
++ di_write(pdata, di_read(pdata, DIER) & ~intr, DIER);
++ spin_unlock_irqrestore(&irq_lock, flags);
++}
++
++/*
++ * This function attempts to clear the dryice write-error flag.
++ *
++ * A dryice write error is similar to a bus fault and should not occur in
++ * normal operation. Clearing the flag requires another write, so the root
++ * cause of the problem may need to be fixed before the flag can be cleared.
++ */
++static void clear_write_error(struct rtc_drv_data *pdata)
++{
++ int cnt;
++
++ dev_warn(&pdata->pdev->dev, "WARNING: Register write error!\n");
++
++ for (;;) {
++ /* clear the write error flag */
++ di_write(pdata, DSR_WEF, DSR);
++
++ /* wait for it to take effect */
++ for (cnt = 0; cnt < 100; cnt++) {
++ if ((di_read(pdata, DSR) & DSR_WEF) == 0)
++ return;
++ udelay(10);
++ }
++ dev_err(&pdata->pdev->dev,
++ "ERROR: Cannot clear write-error flag!\n");
++ }
++}
++
++/*
++ * Write a dryice register and wait until it completes.
++ *
++ * This function uses interrupts to determine when the
++ * write has completed.
++ */
++static int di_write_wait(struct rtc_drv_data *pdata, u32 val, int reg)
++{
++ int ret;
++ int rc = 0;
++
++ /* serialize register writes */
++ mutex_lock(&pdata->write_mutex);
++
++ /* enable the write-complete interrupt */
++ di_int_enable(pdata, DIER_WCIE);
++
++ pdata->dsr = 0;
++
++ /* do the register write */
++ di_write(pdata, val, reg);
++
++ /* wait for the write to finish */
++ ret = wait_event_interruptible_timeout(pdata->write_wait,
++ pdata->dsr & (DSR_WCF | DSR_WEF),
++ 1 * HZ);
++ if (ret == 0)
++ dev_warn(&pdata->pdev->dev, "Write-wait timeout\n");
++
++ /* check for write error */
++ if (pdata->dsr & DSR_WEF) {
++ clear_write_error(pdata);
++ rc = -EIO;
++ }
++ mutex_unlock(&pdata->write_mutex);
++ return rc;
++}
++
++/*
++ * rtc device ioctl
++ *
++ * The rtc framework handles the basic rtc ioctls on behalf
++ * of the driver by calling the functions registered in the
++ * rtc_ops structure.
++ */
++static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm);
++static int dryice_rtc_set_time(struct device *dev, struct rtc_time *tm);
++static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm);
++static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm);
++
++static int dryice_rtc_ioctl(struct device *dev, unsigned int cmd,
++ unsigned long arg)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++
++ dev_dbg(dev, "%s(0x%x)\n", __func__, cmd);
++ switch (cmd) {
++ case RTC_RD_TIME: /* alarm disable */
++ {
++ struct rtc_time rtc_tm;
++ int ret = 0;
++
++ memset(&rtc_tm, 0, sizeof (struct rtc_time));
++ ret = dryice_rtc_read_time(dev, &rtc_tm);
++ if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
++ return -EFAULT;
++ return ret;
++ }
++ case RTC_SET_TIME: /* alarm enable */
++ {
++ struct rtc_time rtc_tm;
++ int ret = 0;
++
++ if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
++ return -EFAULT;
++
++ ret = dryice_rtc_set_time(dev, &rtc_tm);
++ return ret;
++ }
++ case RTC_ALM_READ: /* Read the present alarm time */
++ {
++ struct rtc_wkalrm rtc_wtm;
++ int ret = 0;
++
++ memset(&rtc_wtm, 0, sizeof(struct rtc_wkalrm));
++ ret = dryice_rtc_read_alarm(dev, &rtc_wtm);
++
++ if (copy_to_user((struct rtc_time*)arg, &(rtc_wtm.time), sizeof(struct rtc_time)))
++ return -EFAULT;
++ return ret;
++ }
++ case RTC_WKALM_RD: /* Get wakeup alarm */
++ {
++ struct rtc_wkalrm rtc_wtm;
++ int ret = 0;
++
++ memset(&rtc_wtm, 0, sizeof(struct rtc_wkalrm));
++ ret = dryice_rtc_read_alarm(dev, &rtc_wtm);
++
++ if (copy_to_user((struct rtc_wkalrm*)arg, &rtc_wtm, sizeof(struct rtc_wkalrm)))
++ return -EFAULT;
++ return ret;
++ }
++ case RTC_ALM_SET: /* Set alarm time */
++ {
++ struct rtc_wkalrm rtc_wtm;
++ int ret = 0;
++
++ memset(&rtc_wtm, 0, sizeof(struct rtc_wkalrm));
++ if (copy_from_user(&(rtc_wtm.time), (struct rtc_time*)arg, sizeof(struct rtc_time)))
++ return -EFAULT;
++
++ ret = dryice_rtc_set_alarm(dev, &rtc_wtm);
++ return ret;
++ }
++ case RTC_WKALM_SET: /* Set wakeup alarm */
++ {
++ struct rtc_wkalrm rtc_wtm;
++ int ret = 0;
++
++ if (copy_from_user(&rtc_wtm, (struct rtc_wkalrm*)arg, sizeof(struct rtc_wkalrm)))
++ return -EFAULT;
++
++ ret = dryice_rtc_set_alarm(dev, &rtc_wtm);
++ return ret;
++ }
++ case RTC_AIE_OFF: /* alarm disable */
++ di_int_disable(pdata, DIER_CAIE);
++ return 0;
++
++ case RTC_AIE_ON: /* alarm enable */
++ di_int_enable(pdata, DIER_CAIE);
++ return 0;
++ }
++ return -ENOIOCTLCMD;
++}
++
++/*
++ * read the seconds portion of the current time from the dryice time counter
++ */
++static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ unsigned long now;
++
++ dev_dbg(dev, "%s\n", __func__);
++ now = di_read(pdata, DTCMR);
++ rtc_time_to_tm(now, tm);
++
++ return 0;
++}
++
++/*
++ * set the seconds portion of dryice time counter and clear the
++ * fractional part.
++ */
++static int dryice_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ unsigned long now;
++ int rc;
++
++ dev_dbg(dev, "%s\n", __func__);
++ rc = rtc_tm_to_time(tm, &now);
++ if (rc == 0) {
++ /* zero the fractional part first */
++ di_write_wait_err(pdata, 0, DTCLR, rc, err);
++ di_write_wait_err(pdata, now, DTCMR, rc, err);
++ }
++err:
++ return rc;
++}
++
++/*
++ * read the seconds portion of the alarm register.
++ * the fractional part of the alarm register is always zero.
++ */
++static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ u32 dcamr;
++
++ dev_dbg(dev, "%s\n", __func__);
++ dcamr = di_read(pdata, DCAMR);
++ rtc_time_to_tm(dcamr, &alarm->time);
++
++ /* alarm is enabled if the interrupt is enabled */
++ alarm->enabled = (di_read(pdata, DIER) & DIER_CAIE) != 0;
++
++ /* don't allow the DSR read to mess up DSR_WCF */
++ mutex_lock(&pdata->write_mutex);
++
++ /* alarm is pending if the alarm flag is set */
++ alarm->pending = (di_read(pdata, DSR) & DSR_CAF) != 0;
++
++ mutex_unlock(&pdata->write_mutex);
++
++ return 0;
++}
++
++/*
++ * set the seconds portion of dryice alarm register
++ */
++static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
++{
++ struct rtc_drv_data *pdata = dev_get_drvdata(dev);
++ unsigned long now;
++ unsigned long alarm_time;
++ int rc;
++
++ dev_dbg(dev, "%s\n", __func__);
++ rc = rtc_tm_to_time(&alarm->time, &alarm_time);
++ if (rc)
++ return rc;
++
++ /* don't allow setting alarm in the past */
++ now = di_read(pdata, DTCMR);
++ if (alarm_time < now)
++ return -EINVAL;
++
++ /* write the new alarm time */
++ di_write_wait_err(pdata, (u32)alarm_time, DCAMR, rc, err);
++
++ if (alarm->enabled)
++ di_int_enable(pdata, DIER_CAIE); /* enable alarm intr */
++ else
++ di_int_disable(pdata, DIER_CAIE); /* disable alarm intr */
++err:
++ return rc;
++}
++
++static struct rtc_class_ops dryice_rtc_ops = {
++ .ioctl = dryice_rtc_ioctl,
++ .read_time = dryice_rtc_read_time,
++ .set_time = dryice_rtc_set_time,
++ .read_alarm = dryice_rtc_read_alarm,
++ .set_alarm = dryice_rtc_set_alarm,
++};
++
++/*
++ * dryice "normal" interrupt handler
++ */
++static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
++{
++ struct rtc_drv_data *pdata = dev_id;
++ u32 dsr, dier;
++ irqreturn_t rc = IRQ_NONE;
++
++ dier = di_read(pdata, DIER);
++
++ /* handle write complete and write error cases */
++ if ((dier & DIER_WCIE)) {
++ /*If the write wait queue is empty then there is no pending
++ operations. It means the interrupt is for DryIce -Security.
++ IRQ must be returned as none.*/
++ if (list_empty_careful(&pdata->write_wait.task_list))
++ return rc;
++
++ /* DSR_WCF clears itself on DSR read */
++ dsr = di_read(pdata, DSR);
++ if ((dsr & (DSR_WCF | DSR_WEF))) {
++ /* mask the interrupt */
++ di_int_disable(pdata, DIER_WCIE);
++
++ /* save the dsr value for the wait queue */
++ pdata->dsr |= dsr;
++
++ wake_up_interruptible(&pdata->write_wait);
++ rc = IRQ_HANDLED;
++ }
++ }
++
++ /* handle the alarm case */
++ if ((dier & DIER_CAIE)) {
++ /* DSR_WCF clears itself on DSR read */
++ dsr = di_read(pdata, DSR);
++ if (dsr & DSR_CAF) {
++ /* mask the interrupt */
++ di_int_disable(pdata, DIER_CAIE);
++
++ /* finish alarm in user context */
++ schedule_work(&pdata->work);
++ rc = IRQ_HANDLED;
++ }
++ }
++ return rc;
++}
++
++/*
++ * post the alarm event from user context so it can sleep
++ * on the write completion.
++ */
++static void dryice_work(struct work_struct *work)
++{
++ struct rtc_drv_data *pdata = container_of(work, struct rtc_drv_data,
++ work);
++ int rc;
++
++ /* dismiss the interrupt (ignore error) */
++ di_write_wait_err(pdata, DSR_CAF, DSR, rc, err);
++err:
++ /*
++ * pass the alarm event to the rtc framework. note that
++ * rtc_update_irq expects to be called with interrupts off.
++ */
++ local_irq_disable();
++ rtc_update_irq(pdata->rtc, 1, RTC_AF | RTC_IRQF);
++ local_irq_enable();
++}
++
++/*
++ * probe for dryice rtc device
++ */
++static int dryice_rtc_probe(struct platform_device *pdev)
++{
++ struct rtc_device *rtc;
++ struct resource *res;
++ struct rtc_drv_data *pdata = NULL;
++ void __iomem *ioaddr = NULL;
++ int rc = 0;
++
++ dev_dbg(&pdev->dev, "%s\n", __func__);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res)
++ return -ENODEV;
++
++ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++ if (!pdata)
++ return -ENOMEM;
++
++ pdata->pdev = pdev;
++ pdata->irq = -1;
++ pdata->size = res->end - res->start + 1;
++
++ if (!request_mem_region(res->start, pdata->size, pdev->name)) {
++ rc = -EBUSY;
++ goto err;
++ }
++ pdata->baseaddr = res->start;
++ ioaddr = ioremap(pdata->baseaddr, pdata->size);
++ if (!ioaddr) {
++ rc = -ENOMEM;
++ goto err;
++ }
++ pdata->ioaddr = ioaddr;
++ pdata->irq = platform_get_irq(pdev, 0);
++
++ init_waitqueue_head(&pdata->write_wait);
++
++ INIT_WORK(&pdata->work, dryice_work);
++
++ mutex_init(&pdata->write_mutex);
++
++ pdata->clk = clk_get(&pdev->dev, "dryice_clk");
++ clk_enable(pdata->clk);
++
++ if (pdata->irq >= 0) {
++ if (request_irq(pdata->irq, dryice_norm_irq, IRQF_SHARED,
++ pdev->name, pdata) < 0) {
++ dev_warn(&pdev->dev, "interrupt not available.\n");
++ pdata->irq = -1;
++ goto err;
++ }
++ }
++
++ /*
++ * Initialize dryice hardware
++ */
++
++ /* put dryice into valid state */
++ if (di_read(pdata, DSR) & DSR_NVF)
++ di_write_wait_err(pdata, DSR_NVF | DSR_SVF, DSR, rc, err);
++
++ /* mask alarm interrupt */
++ di_int_disable(pdata, DIER_CAIE);
++
++ /* initialize alarm */
++ di_write_wait_err(pdata, DCAMR_UNSET, DCAMR, rc, err);
++ di_write_wait_err(pdata, 0, DCALR, rc, err);
++
++ /* clear alarm flag */
++ if (di_read(pdata, DSR) & DSR_CAF)
++ di_write_wait_err(pdata, DSR_CAF, DSR, rc, err);
++
++ /* the timer won't count if it has never been written to */
++ if (!di_read(pdata, DTCMR))
++ di_write_wait_err(pdata, 0, DTCMR, rc, err);
++
++ /* start keeping time */
++ if (!(di_read(pdata, DCR) & DCR_TCE))
++ di_write_wait_err(pdata, di_read(pdata, DCR) | DCR_TCE, DCR,
++ rc, err);
++
++ rtc = rtc_device_register(pdev->name, &pdev->dev,
++ &dryice_rtc_ops, THIS_MODULE);
++ if (IS_ERR(rtc)) {
++ rc = PTR_ERR(rtc);
++ goto err;
++ }
++ pdata->rtc = rtc;
++ platform_set_drvdata(pdev, pdata);
++
++ return 0;
++err:
++ if (pdata->rtc)
++ rtc_device_unregister(pdata->rtc);
++
++ if (pdata->irq >= 0)
++ free_irq(pdata->irq, pdata);
++
++ if (pdata->clk) {
++ clk_disable(pdata->clk);
++ clk_put(pdata->clk);
++ }
++
++ if (pdata->ioaddr)
++ iounmap(pdata->ioaddr);
++
++ if (pdata->baseaddr)
++ release_mem_region(pdata->baseaddr, pdata->size);
++
++ kfree(pdata);
++
++ return rc;
++}
++
++static int __exit dryice_rtc_remove(struct platform_device *pdev)
++{
++ struct rtc_drv_data *pdata = platform_get_drvdata(pdev);
++
++ flush_scheduled_work();
++
++ mutex_destroy(&pdata->write_mutex);
++
++ if (pdata->rtc)
++ rtc_device_unregister(pdata->rtc);
++
++ /* mask alarm interrupt */
++ di_int_disable(pdata, DIER_CAIE);
++
++ if (pdata->irq >= 0)
++ free_irq(pdata->irq, pdata);
++
++ if (pdata->clk) {
++ clk_disable(pdata->clk);
++ clk_put(pdata->clk);
++ }
++
++ if (pdata->ioaddr)
++ iounmap(pdata->ioaddr);
++
++ if (pdata->baseaddr)
++ release_mem_region(pdata->baseaddr, pdata->size);
++
++ kfree(pdata);
++
++ return 0;
++}
++
++static struct platform_driver dryice_rtc_driver = {
++ .driver = {
++ .name = "imxdi_rtc",
++ .owner = THIS_MODULE,
++ },
++ .probe = dryice_rtc_probe,
++ .remove = __exit_p(dryice_rtc_remove),
++};
++
++static int __init dryice_rtc_init(void)
++{
++ pr_info("IMXDI Realtime Clock Driver (RTC)\n");
++ return platform_driver_register(&dryice_rtc_driver);
++}
++
++static void __exit dryice_rtc_exit(void)
++{
++ platform_driver_unregister(&dryice_rtc_driver);
++}
++
++module_init(dryice_rtc_init);
++module_exit(dryice_rtc_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("IMXDI Realtime Clock Driver (RTC)");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/drivers/usb/gadget/cdc2.c linux.35.new/drivers/usb/gadget/cdc2.c
+--- linux.35.old/drivers/usb/gadget/cdc2.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/cdc2.c 2010-12-03 09:51:55.468347409 +0100
+@@ -129,7 +129,7 @@
+ /*
+ * We _always_ have both CDC ECM and CDC ACM functions.
+ */
+-static int __init cdc_do_config(struct usb_configuration *c)
++static int __ref cdc_do_config(struct usb_configuration *c)
+ {
+ int status;
+
+@@ -159,7 +159,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init cdc_bind(struct usb_composite_dev *cdev)
++static int __ref cdc_bind(struct usb_composite_dev *cdev)
+ {
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+diff -urN linux.35.old/drivers/usb/gadget/ether.c linux.35.new/drivers/usb/gadget/ether.c
+--- linux.35.old/drivers/usb/gadget/ether.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/ether.c 2010-12-03 09:51:55.468347409 +0100
+@@ -237,7 +237,7 @@
+ * the first one present. That's to make Microsoft's drivers happy,
+ * and to follow DOCSIS 1.0 (cable modem standard).
+ */
+-static int __init rndis_do_config(struct usb_configuration *c)
++static int __ref rndis_do_config(struct usb_configuration *c)
+ {
+ /* FIXME alloc iConfiguration string, set it in c->strings */
+
+@@ -270,7 +270,7 @@
+ /*
+ * We _always_ have an ECM, CDC Subset, or EEM configuration.
+ */
+-static int __init eth_do_config(struct usb_configuration *c)
++static int __ref eth_do_config(struct usb_configuration *c)
+ {
+ /* FIXME alloc iConfiguration string, set it in c->strings */
+
+@@ -297,7 +297,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init eth_bind(struct usb_composite_dev *cdev)
++static int __ref eth_bind(struct usb_composite_dev *cdev)
+ {
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+diff -urN linux.35.old/drivers/usb/gadget/file_storage.c linux.35.new/drivers/usb/gadget/file_storage.c
+--- linux.35.old/drivers/usb/gadget/file_storage.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/file_storage.c 2010-12-03 09:51:55.472347889 +0100
+@@ -3278,7 +3278,7 @@
+ }
+
+
+-static int __init fsg_bind(struct usb_gadget *gadget)
++static int __ref fsg_bind(struct usb_gadget *gadget)
+ {
+ struct fsg_dev *fsg = the_fsg;
+ int rc;
+diff -urN linux.35.old/drivers/usb/gadget/f_loopback.c linux.35.new/drivers/usb/gadget/f_loopback.c
+--- linux.35.old/drivers/usb/gadget/f_loopback.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/f_loopback.c 2010-12-03 09:51:55.472347889 +0100
+@@ -324,7 +324,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init loopback_bind_config(struct usb_configuration *c)
++static int __ref loopback_bind_config(struct usb_configuration *c)
+ {
+ struct f_loopback *loop;
+ int status;
+@@ -346,7 +346,7 @@
+ return status;
+ }
+
+-static struct usb_configuration loopback_driver = {
++static struct usb_configuration loopback_driver = {
+ .label = "loopback",
+ .strings = loopback_strings,
+ .bind = loopback_bind_config,
+diff -urN linux.35.old/drivers/usb/gadget/fsl_mxc_udc.c linux.35.new/drivers/usb/gadget/fsl_mxc_udc.c
+--- linux.35.old/drivers/usb/gadget/fsl_mxc_udc.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/fsl_mxc_udc.c 2010-12-03 09:51:55.472347889 +0100
+@@ -30,7 +30,7 @@
+
+ pdata = pdev->dev.platform_data;
+
+- if (!cpu_is_mx35()) {
++ if (!cpu_is_mx35() && !cpu_is_mx25()) {
+ mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
+ if (IS_ERR(mxc_ahb_clk))
+ return PTR_ERR(mxc_ahb_clk);
+diff -urN linux.35.old/drivers/usb/gadget/f_sourcesink.c linux.35.new/drivers/usb/gadget/f_sourcesink.c
+--- linux.35.old/drivers/usb/gadget/f_sourcesink.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/f_sourcesink.c 2010-12-03 09:51:55.476349329 +0100
+@@ -404,7 +404,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init sourcesink_bind_config(struct usb_configuration *c)
++static int __ref sourcesink_bind_config(struct usb_configuration *c)
+ {
+ struct f_sourcesink *ss;
+ int status;
+diff -urN linux.35.old/drivers/usb/gadget/serial.c linux.35.new/drivers/usb/gadget/serial.c
+--- linux.35.old/drivers/usb/gadget/serial.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/serial.c 2010-12-03 09:51:55.476349329 +0100
+@@ -137,7 +137,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init serial_bind_config(struct usb_configuration *c)
++static int __ref serial_bind_config(struct usb_configuration *c)
+ {
+ unsigned i;
+ int status = 0;
+@@ -161,7 +161,7 @@
+ .bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+ };
+
+-static int __init gs_bind(struct usb_composite_dev *cdev)
++static int __ref gs_bind(struct usb_composite_dev *cdev)
+ {
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+diff -urN linux.35.old/drivers/usb/gadget/zero.c linux.35.new/drivers/usb/gadget/zero.c
+--- linux.35.old/drivers/usb/gadget/zero.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/gadget/zero.c 2010-12-03 09:51:55.476349329 +0100
+@@ -264,7 +264,7 @@
+
+ /*-------------------------------------------------------------------------*/
+
+-static int __init zero_bind(struct usb_composite_dev *cdev)
++static int __ref zero_bind(struct usb_composite_dev *cdev)
+ {
+ int gcnum;
+ struct usb_gadget *gadget = cdev->gadget;
+diff -urN linux.35.old/drivers/usb/host/ehci-mxc.c linux.35.new/drivers/usb/host/ehci-mxc.c
+--- linux.35.old/drivers/usb/host/ehci-mxc.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/usb/host/ehci-mxc.c 2010-12-03 09:51:55.476349329 +0100
+@@ -182,7 +182,7 @@
+ }
+ clk_enable(priv->usbclk);
+
+- if (!cpu_is_mx35()) {
++ if (!cpu_is_mx35() && !cpu_is_mx25()) {
+ priv->ahbclk = clk_get(dev, "usb_ahb");
+ if (IS_ERR(priv->ahbclk)) {
+ ret = PTR_ERR(priv->ahbclk);
+diff -urN linux.35.old/drivers/video/imxfb.c linux.35.new/drivers/video/imxfb.c
+--- linux.35.old/drivers/video/imxfb.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/drivers/video/imxfb.c 2011-01-12 13:27:37.613989923 +0100
+@@ -235,12 +235,13 @@
+ {
+ struct imxfb_info *fbi = info->par;
+ u_int val, ret = 1;
++ int bits = cpu_is_mx1() ? 4 : 6;
+
+ #define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ if (regno < fbi->palette_size) {
+- val = (CNVT_TOHW(red, 4) << 8) |
+- (CNVT_TOHW(green,4) << 4) |
+- CNVT_TOHW(blue, 4);
++ val = (CNVT_TOHW(red, bits) << 2 * bits) |
++ (CNVT_TOHW(green, bits) << bits) |
++ CNVT_TOHW(blue, bits);
+
+ writel(val, fbi->regs + 0x800 + (regno << 2));
+ ret = 0;
+@@ -507,6 +508,19 @@
+ return 0;
+ }
+
++static int imxfb_pan_display(struct fb_var_screeninfo *var,
++ struct fb_info *info)
++{
++ struct imxfb_info *fbi = info->par;
++
++ pr_debug("var: xoffset=%d, yoffset=%d, vmode=%d\n",
++ var->xoffset, var->yoffset, var->vmode);
++
++ writel( fbi->screen_dma + var->xres * var->yoffset * var->bits_per_pixel/8, fbi->regs + LCDC_SSA);
++
++ return 0;
++}
++
+ static struct fb_ops imxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = imxfb_check_var,
+@@ -516,6 +530,7 @@
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = imxfb_blank,
++ .fb_pan_display = imxfb_pan_display,
+ };
+
+ /*
+@@ -533,6 +548,8 @@
+ pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
+ var->yres, var->vsync_len,
+ var->upper_margin, var->lower_margin);
++ pr_debug("var: xres_virtual=%d yres_virtual=%d\n",
++ var->xres_virtual, var->yres_virtual);
+
+ #if DEBUG_VAR
+ if (var->xres < 16 || var->xres > 1024)
+@@ -638,14 +655,14 @@
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.xpanstep = 0;
+- info->fix.ypanstep = 0;
++ info->fix.ypanstep = 1;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->var.nonstd = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+- info->var.width = -1;
++ info->var.width = -1;
+ info->var.accel_flags = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+@@ -663,7 +680,7 @@
+
+ for (i = 0, m = &pdata->mode[0]; i < pdata->num_modes; i++, m++)
+ info->fix.smem_len = max_t(size_t, info->fix.smem_len,
+- m->mode.xres * m->mode.yres * m->bpp / 8);
++ m->mode.xres * 2 * m->mode.yres * m->bpp / 8);
+
+ return 0;
+ }
+@@ -765,7 +782,11 @@
+ * This makes sure that our colour bitfield
+ * descriptors are correctly initialised.
+ */
+- imxfb_check_var(&info->var, info);
++ ret = imxfb_check_var(&info->var, info);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "failed to find framebuffer mode\n");
++ goto failed_cmap;
++ }
+
+ ret = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
+ if (ret < 0)
+diff -urN linux.35.old/include/asm-generic/int-ll64.h linux.35.new/include/asm-generic/int-ll64.h
+--- linux.35.old/include/asm-generic/int-ll64.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/include/asm-generic/int-ll64.h 2010-12-03 09:51:55.480350013 +0100
+@@ -8,7 +8,7 @@
+ #ifndef _ASM_GENERIC_INT_LL64_H
+ #define _ASM_GENERIC_INT_LL64_H
+
+-#include <asm/bitsperlong.h>
++#include <asm-generic/bitsperlong.h>
+
+ #ifndef __ASSEMBLY__
+ /*
+diff -urN linux.35.old/include/linux/can/platform/flexcan.h linux.35.new/include/linux/can/platform/flexcan.h
+--- linux.35.old/include/linux/can/platform/flexcan.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/include/linux/can/platform/flexcan.h 2010-12-03 09:51:55.480350013 +0100
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2010 Marc Kleine-Budde <kernel@pengutronix.de>
++ *
++ * This file is released under the GPLv2
++ *
++ */
++
++#ifndef __CAN_PLATFORM_FLEXCAN_H
++#define __CAN_PLATFORM_FLEXCAN_H
++
++/**
++ * struct flexcan_platform_data - flex CAN controller platform data
++ * @transceiver_enable: - called to power on/off the transceiver
++ *
++ */
++struct flexcan_platform_data {
++ void (*transceiver_switch)(int enable);
++};
++
++#endif /* __CAN_PLATFORM_FLEXCAN_H */
+diff -urN linux.35.old/include/linux/imx_adc.h linux.35.new/include/linux/imx_adc.h
+--- linux.35.old/include/linux/imx_adc.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/include/linux/imx_adc.h 2010-12-03 09:51:55.480350013 +0100
+@@ -0,0 +1,275 @@
++/*
++ * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU Lesser General
++ * Public License. You may obtain a copy of the GNU Lesser General
++ * Public License Version 2.1 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/lgpl-license.html
++ * http://www.gnu.org/copyleft/lgpl.html
++ */
++
++#ifndef __ASM_ARCH_IMX_ADC_H__
++#define __ASM_ARCH_IMX_ADC_H__
++
++/*!
++ * @defgroup IMX_ADC Digitizer Driver
++ * @ingroup IMX_DRVRS
++ */
++
++/*!
++ * @file arch-mxc/imx_adc.h
++ * @brief This is the header of IMX ADC driver.
++ *
++ * @ingroup IMX_ADC
++ */
++
++#include <linux/ioctl.h>
++
++/*!
++ * @enum IMX_ADC_STATUS
++ * @brief Define return values for all IMX_ADC APIs.
++ *
++ * These return values are used by all of the IMX_ADC APIs.
++ *
++ * @ingroup IMX_ADC
++ */
++enum IMX_ADC_STATUS {
++ /*! The requested operation was successfully completed. */
++ IMX_ADC_SUCCESS = 0,
++ /*! The requested operation could not be completed due to an error. */
++ IMX_ADC_ERROR = -1,
++ /*!
++ * The requested operation failed because one or more of the
++ * parameters was invalid.
++ */
++ IMX_ADC_PARAMETER_ERROR = -2,
++ /*!
++ * The requested operation could not be completed because the ADC
++ * hardware does not support it.
++ */
++ IMX_ADC_NOT_SUPPORTED = -3,
++ /*! Error in malloc function */
++ IMX_ADC_MALLOC_ERROR = -5,
++ /*! Error in un-subscribe event */
++ IMX_ADC_UNSUBSCRIBE_ERROR = -6,
++ /*! Event occur and not subscribed */
++ IMX_ADC_EVENT_NOT_SUBSCRIBED = -7,
++ /*! Error - bad call back */
++ IMX_ADC_EVENT_CALL_BACK = -8,
++ /*!
++ * The requested operation could not be completed because there
++ * are too many ADC client requests
++ */
++ IMX_ADC_CLIENT_NBOVERFLOW = -9,
++};
++
++/*
++ * Macros implementing error handling
++ */
++#define CHECK_ERROR(a) \
++do { \
++ int ret = (a); \
++ if (ret != IMX_ADC_SUCCESS) \
++ return ret; \
++} while (0)
++
++#define CHECK_ERROR_KFREE(func, freeptrs) \
++do { \
++ int ret = (func); \
++ if (ret != IMX_ADC_SUCCESS) { \
++ freeptrs; \
++ return ret; \
++ } \
++} while (0)
++
++#define MOD_NAME "mxcadc"
++
++/*!
++ * @name IOCTL user space interface
++ */
++
++/*!
++ * Initialize ADC.
++ * Argument type: none.
++ */
++#define IMX_ADC_INIT _IO('p', 0xb0)
++/*!
++ * De-initialize ADC.
++ * Argument type: none.
++ */
++#define IMX_ADC_DEINIT _IO('p', 0xb1)
++/*!
++ * Convert one channel.
++ * Argument type: pointer to t_adc_convert_param.
++ */
++#define IMX_ADC_CONVERT _IOWR('p', 0xb2, int)
++/*!
++ * Convert multiple channels.
++ * Argument type: pointer to t_adc_convert_param.
++ */
++#define IMX_ADC_CONVERT_MULTICHANNEL _IOWR('p', 0xb4, int)
++
++/*! @{ */
++/*!
++ * @name Touch Screen minimum and maximum values
++ */
++#define IMX_ADC_DEVICE "/dev/imx_adc"
++
++/*
++ * Maximun allowed variation in the three X/Y co-ordinates acquired from
++ * touch screen
++ */
++#define DELTA_Y_MAX 100
++#define DELTA_X_MAX 100
++
++/* Upon clearing the filter, this is the delay in restarting the filter */
++#define FILTER_MIN_DELAY 4
++
++/* Length of X and Y touch screen filters */
++#define FILTLEN 3
++
++#define TS_X_MAX 1000
++#define TS_Y_MAX 1000
++
++#define TS_X_MIN 80
++#define TS_Y_MIN 80
++
++/*! @} */
++/*!
++ * This enumeration defines input channels for IMX ADC
++ */
++
++enum t_channel {
++ TS_X_POS,
++ TS_Y_POS,
++ GER_PURPOSE_ADC0,
++ GER_PURPOSE_ADC1,
++ GER_PURPOSE_ADC2,
++ GER_PURPOSE_MULTICHNNEL,
++};
++
++/*!
++ * This structure is used to report touch screen value.
++ */
++struct t_touch_screen {
++ /* Touch Screen X position */
++ unsigned int x_position;
++ /* Touch Screen X position1 */
++ unsigned int x_position1;
++ /* Touch Screen X position2 */
++ unsigned int x_position2;
++ /* Touch Screen X position3 */
++ unsigned int x_position3;
++ /* Touch Screen Y position */
++ unsigned int y_position;
++ /* Touch Screen Y position1 */
++ unsigned int y_position1;
++ /* Touch Screen Y position2 */
++ unsigned int y_position2;
++ /* Touch Screen Y position3 */
++ unsigned int y_position3;
++ /* Touch Screen contact value */
++ unsigned int contact_resistance;
++ /* Flag indicate the data usability */
++ unsigned int valid_flag;
++};
++
++/*!
++ * This structure is used with IOCTL code \a IMX_ADC_CONVERT,
++ * \a IMX_ADC_CONVERT_8X and \a IMX_ADC_CONVERT_MULTICHANNEL.
++ */
++
++struct t_adc_convert_param {
++ /* channel or channels to be sampled. */
++ enum t_channel channel;
++ /* holds up to 16 sampling results */
++ unsigned short result[16];
++};
++
++/* EXPORTED FUNCTIONS */
++
++#ifdef __KERNEL__
++/* Driver data */
++struct imx_adc_data {
++ u32 irq;
++ struct clk *adc_clk;
++};
++
++/*!
++ * This function initializes all ADC registers with default values. This
++ * function also registers the interrupt events.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_init(void);
++
++/*!
++ * This function disables the ADC, de-registers the interrupt events.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_deinit(void);
++
++/*!
++ * This function triggers a conversion and returns one sampling result of one
++ * channel.
++ *
++ * @param channel The channel to be sampled
++ * @param result The pointer to the conversion result. The memory
++ * should be allocated by the caller of this function.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++
++enum IMX_ADC_STATUS imx_adc_convert(enum t_channel channel,
++ unsigned short *result);
++
++/*!
++ * This function triggers a conversion and returns sampling results of each
++ * specified channel.
++ *
++ * @param channels This input parameter is bitmap to specify channels
++ * to be sampled.
++ * @param result The pointer to array to store sampling result.
++ * The order of the result in the array is from lowest
++ * channel number to highest channel number of the
++ * sampled channels.
++ * The memory should be allocated by the caller of this
++ * function.
++ * Note that the behavior of this function might differ
++ * from one platform to another regarding especially
++ * channels order.
++ *
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++
++enum IMX_ADC_STATUS imx_adc_convert_multichnnel(enum t_channel channels,
++ unsigned short *result);
++
++/*!
++ * This function retrieves the current touch screen operation mode.
++ *
++ * @param touch_sample Pointer to touch sample.
++ * @param wait_tsi if true, we wait until interrupt occurs
++ * @return This function returns IMX_ADC_SUCCESS if successful.
++ */
++enum IMX_ADC_STATUS imx_adc_get_touch_sample(struct t_touch_screen *ts_value,
++ int wait_tsi);
++
++/*!
++ * This function read the touch screen value.
++ *
++ * @param touch_sample return value of touch screen
++ * @param wait_tsi if true, we need wait until interrupt occurs
++ * @return This function returns 0.
++ */
++enum IMX_ADC_STATUS imx_adc_read_ts(struct t_touch_screen *touch_sample,
++ int wait_tsi);
++
++int is_imx_adc_ready(void);
++
++#endif /* _KERNEL */
++#endif /* __ASM_ARCH_IMX_ADC_H__ */
+diff -urN linux.35.old/include/linux/netdevice.h linux.35.new/include/linux/netdevice.h
+--- linux.35.old/include/linux/netdevice.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/include/linux/netdevice.h 2010-12-03 09:51:55.484347691 +0100
+@@ -54,6 +54,7 @@
+
+ struct vlan_group;
+ struct netpoll_info;
++struct phy_device;
+ /* 802.11 specific */
+ struct wireless_dev;
+ /* source back-compat hooks */
+@@ -1057,6 +1058,9 @@
+ #endif
+ /* n-tuple filter list attached to this device */
+ struct ethtool_rx_ntuple_list ethtool_ntuple_list;
++
++ /* phy device may attach itself for hardware timestamping */
++ struct phy_device *phydev;
+ };
+ #define to_net_dev(d) container_of(d, struct net_device, dev)
+
+diff -urN linux.35.old/include/linux/phy.h linux.35.new/include/linux/phy.h
+--- linux.35.old/include/linux/phy.h 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/include/linux/phy.h 2010-12-03 09:51:55.484347691 +0100
+@@ -234,6 +234,8 @@
+ PHY_RESUMING
+ };
+
++struct sk_buff;
++
+ /* phy_device: An instance of a PHY
+ *
+ * drv: Pointer to the driver for this PHY instance
+@@ -402,6 +404,26 @@
+ /* Clears up any memory if needed */
+ void (*remove)(struct phy_device *phydev);
+
++ /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */
++ int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr);
++
++ /*
++ * Requests a Rx timestamp for 'skb'. If the skb is accepted,
++ * the phy driver promises to deliver it using netif_rx() as
++ * soon as a timestamp becomes available. One of the
++ * PTP_CLASS_ values is passed in 'type'. The function must
++ * return true if the skb is accepted for delivery.
++ */
++ bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
++
++ /*
++ * Requests a Tx timestamp for 'skb'. The phy driver promises
++ * to deliver it to the socket's error queue as soon as a
++ * timestamp becomes available. One of the PTP_CLASS_ values
++ * is passed in 'type'.
++ */
++ void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type);
++
+ struct device_driver driver;
+ };
+ #define to_phy_driver(d) container_of(d, struct phy_driver, driver)
+@@ -498,7 +520,7 @@
+ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+ int phy_mii_ioctl(struct phy_device *phydev,
+- struct mii_ioctl_data *mii_data, int cmd);
++ struct ifreq *ifr, int cmd);
+ int phy_start_interrupts(struct phy_device *phydev);
+ void phy_print_status(struct phy_device *phydev);
+ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id);
+diff -urN linux.35.old/sound/soc/codecs/Kconfig linux.35.new/sound/soc/codecs/Kconfig
+--- linux.35.old/sound/soc/codecs/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/codecs/Kconfig 2010-12-03 09:51:55.484347691 +0100
+@@ -269,6 +269,10 @@
+ config SND_SOC_WM9713
+ tristate
+
++config SND_SOC_SGTL5000
++ tristate
++ depends on I2C
++
+ # Amp
+ config SND_SOC_MAX9877
+ tristate
+diff -urN linux.35.old/sound/soc/codecs/Makefile linux.35.new/sound/soc/codecs/Makefile
+--- linux.35.old/sound/soc/codecs/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/codecs/Makefile 2010-12-03 09:51:55.484347691 +0100
+@@ -56,6 +56,7 @@
+ snd-soc-wm9712-objs := wm9712.o
+ snd-soc-wm9713-objs := wm9713.o
+ snd-soc-wm-hubs-objs := wm_hubs.o
++snd-soc-sgtl5000-objs := sgtl5000.o
+
+ # Amp
+ snd-soc-max9877-objs := max9877.o
+@@ -121,6 +122,7 @@
+ obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o
+ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o
+ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
++obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
+
+ # Amp
+ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
+diff -urN linux.35.old/sound/soc/codecs/sgtl5000.c linux.35.new/sound/soc/codecs/sgtl5000.c
+--- linux.35.old/sound/soc/codecs/sgtl5000.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/sound/soc/codecs/sgtl5000.c 2011-01-05 09:37:51.655096053 +0100
+@@ -0,0 +1,1263 @@
++/*
++ * sgtl5000.c -- SGTL5000 ALSA SoC Audio driver
++ *
++ * Copyright 2008-2010 Freescale Semiconductor, 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 version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++#include <mach/hardware.h>
++#include <linux/slab.h>
++
++#include "sgtl5000.h"
++
++#include <linux/jiffies.h>
++/* I2C code related */
++static unsigned i2c_timeout = 250;
++
++struct sgtl5000_priv {
++ int sysclk;
++ int master;
++ int fmt;
++ int rev;
++ int lrclk;
++ int capture_channels;
++ int playback_active;
++ int capture_active;
++ struct snd_pcm_substream *master_substream;
++ struct snd_pcm_substream *slave_substream;
++};
++
++static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
++ enum snd_soc_bias_level level);
++
++#define SGTL5000_MAX_CACHED_REG SGTL5000_CHIP_SHORT_CTRL
++static u16 sgtl5000_regs[(SGTL5000_MAX_CACHED_REG >> 1) + 1];
++
++static unsigned int sgtl5000_read_reg_cache(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ u16 *cache = codec->reg_cache;
++ unsigned int offset = reg >> 1;
++ if (offset >= ARRAY_SIZE(sgtl5000_regs))
++ return -EINVAL;
++ pr_debug("r r:%02x,v:%04x\n", reg, cache[offset]);
++ return cache[offset];
++}
++
++static unsigned int sgtl5000_hw_read(struct snd_soc_codec *codec,
++ unsigned int reg)
++{
++ struct i2c_client *client = codec->control_data;
++ int i2c_ret;
++ u16 value;
++ u8 buf0[2], buf1[2];
++ u16 addr = client->addr;
++ u16 flags = client->flags;
++ struct i2c_msg msg[2] = {
++ {addr, flags, 2, buf0},
++ {addr, flags | I2C_M_RD, 2, buf1},
++ };
++ unsigned long timeout, read_time;
++
++ buf0[0] = (reg & 0xff00) >> 8;
++ buf0[1] = reg & 0xff;
++
++ timeout = jiffies + msecs_to_jiffies(i2c_timeout);
++ do {
++ read_time = jiffies;
++ i2c_ret = i2c_transfer(client->adapter, msg, 2);
++ // REVISIT: at HZ=100, this is sloooow
++ msleep(1);
++ } while (time_before(read_time, timeout) && i2c_ret != 2);
++
++ if (i2c_ret < 0) {
++ pr_err("%s: read reg error : Reg 0x%02x\n", __func__, reg);
++ return 0;
++ }
++
++ value = buf1[0] << 8 | buf1[1];
++
++ pr_debug("r r:%02x,v:%04x\n", reg, value);
++ return value;
++}
++
++static unsigned int sgtl5000_read(struct snd_soc_codec *codec, unsigned int reg)
++{
++ if ((reg == SGTL5000_CHIP_ID) ||
++ (reg == SGTL5000_CHIP_ADCDAC_CTRL) ||
++ (reg == SGTL5000_CHIP_ANA_STATUS) ||
++ (reg > SGTL5000_MAX_CACHED_REG))
++ return sgtl5000_hw_read(codec, reg);
++ else
++ return sgtl5000_read_reg_cache(codec, reg);
++}
++
++static inline void sgtl5000_write_reg_cache(struct snd_soc_codec *codec,
++ u16 reg, unsigned int value)
++{
++ u16 *cache = codec->reg_cache;
++ unsigned int offset = reg >> 1;
++ if (offset < ARRAY_SIZE(sgtl5000_regs))
++ cache[offset] = value;
++}
++
++static int sgtl5000_write(struct snd_soc_codec *codec, unsigned int reg,
++ unsigned int value)
++{
++ struct i2c_client *client = codec->control_data;
++ u16 addr = client->addr;
++ u16 flags = client->flags;
++ u8 buf[4];
++ int i2c_ret;
++ struct i2c_msg msg = { addr, flags, 4, buf };
++ unsigned long timeout, read_time;
++
++ sgtl5000_write_reg_cache(codec, reg, value);
++ pr_debug("w r:%02x,v:%04x\n", reg, value);
++ buf[0] = (reg & 0xff00) >> 8;
++ buf[1] = reg & 0xff;
++ buf[2] = (value & 0xff00) >> 8;
++ buf[3] = value & 0xff;
++
++ timeout = jiffies + msecs_to_jiffies(i2c_timeout);
++ do {
++ read_time = jiffies;
++ i2c_ret = i2c_transfer(client->adapter, &msg, 1);
++ // REVISIT: at HZ=100, this is sloooow
++ msleep(1);
++ } while (time_before(read_time, timeout) && i2c_ret != 1);
++
++ if (i2c_ret < 0) {
++ pr_err("%s: write reg error : Reg 0x%02x = 0x%04x\n",
++ __func__, reg, value);
++ return -EIO;
++ }
++
++ return i2c_ret;
++}
++
++static void sgtl5000_sync_reg_cache(struct snd_soc_codec *codec)
++{
++ int reg;
++ for (reg = 0; reg <= SGTL5000_MAX_CACHED_REG; reg += 2)
++ sgtl5000_write_reg_cache(codec, reg,
++ sgtl5000_hw_read(codec, reg));
++}
++
++static int sgtl5000_restore_reg(struct snd_soc_codec *codec, unsigned int reg)
++{
++ unsigned int cached_val, hw_val;
++
++ cached_val = sgtl5000_read_reg_cache(codec, reg);
++ hw_val = sgtl5000_hw_read(codec, reg);
++
++ if (hw_val != cached_val)
++ return sgtl5000_write(codec, reg, cached_val);
++
++ return 0;
++}
++
++static int all_reg[] = {
++ SGTL5000_CHIP_ID,
++ SGTL5000_CHIP_DIG_POWER,
++ SGTL5000_CHIP_CLK_CTRL,
++ SGTL5000_CHIP_I2S_CTRL,
++ SGTL5000_CHIP_SSS_CTRL,
++ SGTL5000_CHIP_ADCDAC_CTRL,
++ SGTL5000_CHIP_DAC_VOL,
++ SGTL5000_CHIP_PAD_STRENGTH,
++ SGTL5000_CHIP_ANA_ADC_CTRL,
++ SGTL5000_CHIP_ANA_HP_CTRL,
++ SGTL5000_CHIP_ANA_CTRL,
++ SGTL5000_CHIP_LINREG_CTRL,
++ SGTL5000_CHIP_REF_CTRL,
++ SGTL5000_CHIP_MIC_CTRL,
++ SGTL5000_CHIP_LINE_OUT_CTRL,
++ SGTL5000_CHIP_LINE_OUT_VOL,
++ SGTL5000_CHIP_ANA_POWER,
++ SGTL5000_CHIP_PLL_CTRL,
++ SGTL5000_CHIP_CLK_TOP_CTRL,
++ SGTL5000_CHIP_ANA_STATUS,
++ SGTL5000_CHIP_SHORT_CTRL,
++};
++
++#ifdef DEBUG
++static void dump_reg(struct snd_soc_codec *codec)
++{
++ int i, reg;
++ printk(KERN_DEBUG "dump begin\n");
++ for (i = 0; i < 21; i++) {
++ reg = sgtl5000_read(codec, all_reg[i]);
++ printk(KERN_DEBUG "d r %04x, v %04x\n", all_reg[i], reg);
++ }
++ printk(KERN_DEBUG "dump end\n");
++}
++#else
++static void dump_reg(struct snd_soc_codec *codec)
++{
++}
++#endif
++
++static int dac_mux_put(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
++ struct snd_soc_codec *codec = widget->codec;
++ unsigned int reg;
++
++ if (ucontrol->value.enumerated.item[0]) {
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
++ reg |= SGTL5000_INT_OSC_EN;
++ sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
++
++ if (codec->bias_level != SND_SOC_BIAS_ON) {
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
++ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_ON);
++ } else
++ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_CTRL);
++ reg &= ~(SGTL5000_LINE_OUT_MUTE | SGTL5000_HP_MUTE);
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_CTRL, reg);
++ } else {
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
++ reg &= ~SGTL5000_INT_OSC_EN;
++ sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
++
++ snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++ }
++ return 0;
++}
++
++static const char *adc_mux_text[] = {
++ "MIC_IN", "LINE_IN"
++};
++
++static const char *dac_mux_text[] = {
++ "DAC", "LINE_IN"
++};
++
++static const struct soc_enum adc_enum =
++SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text);
++
++static const struct soc_enum dac_enum =
++SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text);
++
++static const struct snd_kcontrol_new adc_mux =
++SOC_DAPM_ENUM("ADC Mux", adc_enum);
++
++static const struct snd_kcontrol_new dac_mux = {
++ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "DAC Mux",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE
++ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = snd_soc_info_enum_double,
++ .get = snd_soc_dapm_get_enum_double,
++ .put = dac_mux_put,
++ .private_value = (unsigned long)&dac_enum,
++};
++
++static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = {
++ SND_SOC_DAPM_INPUT("LINE_IN"),
++ SND_SOC_DAPM_INPUT("MIC_IN"),
++
++ SND_SOC_DAPM_OUTPUT("HP_OUT"),
++ SND_SOC_DAPM_OUTPUT("LINE_OUT"),
++
++ SND_SOC_DAPM_PGA("HP", SGTL5000_CHIP_ANA_CTRL, 4, 1, NULL, 0),
++ SND_SOC_DAPM_PGA("LO", SGTL5000_CHIP_ANA_CTRL, 8, 1, NULL, 0),
++
++ SND_SOC_DAPM_MUX("ADC Mux", SND_SOC_NOPM, 0, 0, &adc_mux),
++ SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux),
++
++ SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_DIG_POWER, 6, 0),
++ SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
++};
++
++static const struct snd_soc_dapm_route audio_map[] = {
++ {"ADC Mux", "LINE_IN", "LINE_IN"},
++ {"ADC Mux", "MIC_IN", "MIC_IN"},
++ {"ADC", NULL, "ADC Mux"},
++ {"DAC Mux", "DAC", "DAC"},
++ {"DAC Mux", "LINE_IN", "LINE_IN"},
++ {"LO", NULL, "DAC"},
++ {"HP", NULL, "DAC Mux"},
++ {"LINE_OUT", NULL, "LO"},
++ {"HP_OUT", NULL, "HP"},
++};
++
++static int sgtl5000_add_widgets(struct snd_soc_codec *codec)
++{
++ snd_soc_dapm_new_controls(codec, sgtl5000_dapm_widgets,
++ ARRAY_SIZE(sgtl5000_dapm_widgets));
++
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ snd_soc_dapm_new_widgets(codec);
++ return 0;
++}
++
++static int dac_info_volsw(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_info *uinfo)
++{
++ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++ uinfo->count = 2;
++ uinfo->value.integer.min = 0;
++ uinfo->value.integer.max = 0xfc - 0x3c;
++ return 0;
++}
++
++static int dac_get_volsw(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ int reg, l, r;
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_DAC_VOL);
++ l = (reg & SGTL5000_DAC_VOL_LEFT_MASK) >> SGTL5000_DAC_VOL_LEFT_SHIFT;
++ r = (reg & SGTL5000_DAC_VOL_RIGHT_MASK) >> SGTL5000_DAC_VOL_RIGHT_SHIFT;
++ l = l < 0x3c ? 0x3c : l;
++ l = l > 0xfc ? 0xfc : l;
++ r = r < 0x3c ? 0x3c : r;
++ r = r > 0xfc ? 0xfc : r;
++ l = 0xfc - l;
++ r = 0xfc - r;
++
++ ucontrol->value.integer.value[0] = l;
++ ucontrol->value.integer.value[1] = r;
++
++ return 0;
++}
++
++static int dac_put_volsw(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++ int reg, l, r;
++
++ l = ucontrol->value.integer.value[0];
++ r = ucontrol->value.integer.value[1];
++
++ l = l < 0 ? 0 : l;
++ l = l > 0xfc - 0x3c ? 0xfc - 0x3c : l;
++ r = r < 0 ? 0 : r;
++ r = r > 0xfc - 0x3c ? 0xfc - 0x3c : r;
++ l = 0xfc - l;
++ r = 0xfc - r;
++
++ reg = l << SGTL5000_DAC_VOL_LEFT_SHIFT |
++ r << SGTL5000_DAC_VOL_RIGHT_SHIFT;
++
++ sgtl5000_write(codec, SGTL5000_CHIP_DAC_VOL, reg);
++
++ return 0;
++}
++
++static const char *mic_gain_text[] = {
++ "0dB", "20dB", "30dB", "40dB"
++};
++
++static const char *adc_m6db_text[] = {
++ "No Change", "Reduced by 6dB"
++};
++
++static const struct soc_enum mic_gain =
++SOC_ENUM_SINGLE(SGTL5000_CHIP_MIC_CTRL, 0, 4, mic_gain_text);
++
++static const struct soc_enum adc_m6db =
++SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_ADC_CTRL, 8, 2, adc_m6db_text);
++
++static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
++ SOC_ENUM("MIC GAIN", mic_gain),
++ SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0),
++ SOC_ENUM("Capture Vol Reduction", adc_m6db),
++ {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
++ .name = "Playback Volume",
++ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
++ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
++ .info = dac_info_volsw,
++ .get = dac_get_volsw,
++ .put = dac_put_volsw,
++ },
++ SOC_DOUBLE("Headphone Volume", SGTL5000_CHIP_ANA_HP_CTRL, 0, 8, 0x7f,
++ 1),
++};
++
++static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ u16 adcdac_ctrl;
++
++ adcdac_ctrl = sgtl5000_read(codec, SGTL5000_CHIP_ADCDAC_CTRL);
++
++ if (mute) {
++ adcdac_ctrl |= SGTL5000_DAC_MUTE_LEFT;
++ adcdac_ctrl |= SGTL5000_DAC_MUTE_RIGHT;
++ } else {
++ adcdac_ctrl &= ~SGTL5000_DAC_MUTE_LEFT;
++ adcdac_ctrl &= ~SGTL5000_DAC_MUTE_RIGHT;
++ }
++
++ sgtl5000_write(codec, SGTL5000_CHIP_ADCDAC_CTRL, adcdac_ctrl);
++ if (!mute)
++ dump_reg(codec);
++ return 0;
++}
++
++static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ u16 i2sctl = 0;
++ pr_debug("%s:fmt=%08x\n", __func__, fmt);
++ sgtl5000->master = 0;
++ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
++ case SND_SOC_DAIFMT_CBS_CFS:
++ break;
++ case SND_SOC_DAIFMT_CBM_CFM:
++ i2sctl |= SGTL5000_I2S_MASTER;
++ sgtl5000->master = 1;
++ break;
++ case SND_SOC_DAIFMT_CBM_CFS:
++ case SND_SOC_DAIFMT_CBS_CFM:
++ return -EINVAL;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
++ case SND_SOC_DAIFMT_DSP_A:
++ i2sctl |= SGTL5000_I2S_MODE_PCM;
++ break;
++ case SND_SOC_DAIFMT_DSP_B:
++ i2sctl |= SGTL5000_I2S_MODE_PCM;
++ i2sctl |= SGTL5000_I2S_LRALIGN;
++ break;
++ case SND_SOC_DAIFMT_I2S:
++ i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
++ break;
++ case SND_SOC_DAIFMT_RIGHT_J:
++ i2sctl |= SGTL5000_I2S_MODE_RJ;
++ i2sctl |= SGTL5000_I2S_LRPOL;
++ break;
++ case SND_SOC_DAIFMT_LEFT_J:
++ i2sctl |= SGTL5000_I2S_MODE_I2S_LJ;
++ i2sctl |= SGTL5000_I2S_LRALIGN;
++ break;
++ default:
++ return -EINVAL;
++ }
++ sgtl5000->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
++
++ /* Clock inversion */
++ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
++ case SND_SOC_DAIFMT_NB_NF:
++ case SND_SOC_DAIFMT_NB_IF:
++ break;
++ case SND_SOC_DAIFMT_IB_IF:
++ case SND_SOC_DAIFMT_IB_NF:
++ i2sctl |= SGTL5000_I2S_SCLK_INV;
++ break;
++ default:
++ return -EINVAL;
++ }
++ sgtl5000_write(codec, SGTL5000_CHIP_I2S_CTRL, i2sctl);
++
++ return 0;
++}
++
++static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
++ int clk_id, unsigned int freq, int dir)
++{
++ struct snd_soc_codec *codec = codec_dai->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++
++ switch (clk_id) {
++ case SGTL5000_SYSCLK:
++ sgtl5000->sysclk = freq;
++ break;
++ case SGTL5000_LRCLK:
++ sgtl5000->lrclk = freq;
++ break;
++ default:
++ return -EINVAL;
++ }
++ return 0;
++}
++
++static int sgtl5000_pcm_prepare(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->card->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ int reg;
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_DIG_POWER);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ reg |= SGTL5000_I2S_IN_POWERUP;
++ else
++ reg |= SGTL5000_I2S_OUT_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_DIG_POWER, reg);
++
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ reg |= SGTL5000_ADC_POWERUP;
++ if (sgtl5000->capture_channels == 1)
++ reg &= ~SGTL5000_ADC_STEREO;
++ else
++ reg |= SGTL5000_ADC_STEREO;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ }
++
++ return 0;
++}
++
++static int sgtl5000_pcm_startup(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->card->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ struct snd_pcm_runtime *master_runtime;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ sgtl5000->playback_active++;
++ else
++ sgtl5000->capture_active++;
++
++ /* The DAI has shared clocks so if we already have a playback or
++ * capture going then constrain this substream to match it.
++ */
++ if (sgtl5000->master_substream) {
++ master_runtime = sgtl5000->master_substream->runtime;
++
++ pr_debug("Constraining to %d bits\n",
++ master_runtime->sample_bits);
++
++ snd_pcm_hw_constraint_minmax(substream->runtime,
++ SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
++ master_runtime->sample_bits,
++ master_runtime->sample_bits);
++
++ sgtl5000->slave_substream = substream;
++ } else
++ sgtl5000->master_substream = substream;
++
++ return 0;
++}
++
++static void sgtl5000_pcm_shutdown(struct snd_pcm_substream *substream,
++ struct snd_soc_dai *dai)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->card->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ int reg, dig_pwr, ana_pwr;
++
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ sgtl5000->playback_active--;
++ else
++ sgtl5000->capture_active--;
++
++ if (sgtl5000->master_substream == substream)
++ sgtl5000->master_substream = sgtl5000->slave_substream;
++
++ sgtl5000->slave_substream = NULL;
++
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
++ ana_pwr = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ ana_pwr &= ~(SGTL5000_ADC_POWERUP | SGTL5000_ADC_STEREO);
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr);
++ }
++
++ dig_pwr = sgtl5000_read(codec, SGTL5000_CHIP_DIG_POWER);
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
++ dig_pwr &= ~SGTL5000_I2S_IN_POWERUP;
++ else
++ dig_pwr &= ~SGTL5000_I2S_OUT_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_DIG_POWER, dig_pwr);
++
++ if (!sgtl5000->playback_active && !sgtl5000->capture_active) {
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_I2S_CTRL);
++ reg &= ~SGTL5000_I2S_MASTER;
++ sgtl5000_write(codec, SGTL5000_CHIP_I2S_CTRL, reg);
++ }
++}
++
++/*
++ * Set PCM DAI bit size and sample rate.
++ * input: params_rate, params_fmt
++ */
++static int sgtl5000_pcm_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_device *socdev = rtd->socdev;
++ struct snd_soc_codec *codec = socdev->card->codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ int channels = params_channels(params);
++ int clk_ctl = 0;
++ int pll_ctl = 0;
++ int i2s_ctl;
++ int div2 = 0;
++ int reg;
++ u32 fs;
++
++ pr_debug("%s channels=%d\n", __func__, channels);
++
++ if (!sgtl5000->sysclk) {
++ pr_err("%s: set sysclk first!\n", __func__);
++ return -EFAULT;
++ }
++
++ if (substream == sgtl5000->slave_substream) {
++ pr_debug("Ignoring hw_params for slave substream\n");
++ return 0;
++ }
++
++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
++ sgtl5000->capture_channels = channels;
++
++ switch (sgtl5000->lrclk) {
++ case 32000:
++ clk_ctl |= SGTL5000_SYS_FS_32k << SGTL5000_SYS_FS_SHIFT;
++ break;
++ case 44100:
++ clk_ctl |= SGTL5000_SYS_FS_44_1k << SGTL5000_SYS_FS_SHIFT;
++ break;
++ case 48000:
++ clk_ctl |= SGTL5000_SYS_FS_48k << SGTL5000_SYS_FS_SHIFT;
++ break;
++ case 96000:
++ clk_ctl |= SGTL5000_SYS_FS_96k << SGTL5000_SYS_FS_SHIFT;
++ break;
++ default:
++ pr_err("%s: sample rate %d not supported\n", __func__,
++ sgtl5000->lrclk);
++ return -EFAULT;
++ }
++ fs = sgtl5000->lrclk;
++ /* SGTL5000 rev1 has a IC bug to prevent switching to MCLK from PLL. */
++ if (!sgtl5000->master) {
++ if (fs * 256 == sgtl5000->sysclk)
++ clk_ctl |= SGTL5000_MCLK_FREQ_256FS << \
++ SGTL5000_MCLK_FREQ_SHIFT;
++ else if (fs * 384 == sgtl5000->sysclk && fs != 96000)
++ clk_ctl |= SGTL5000_MCLK_FREQ_384FS << \
++ SGTL5000_MCLK_FREQ_SHIFT;
++ else if (fs * 512 == sgtl5000->sysclk && fs != 96000)
++ clk_ctl |= SGTL5000_MCLK_FREQ_512FS << \
++ SGTL5000_MCLK_FREQ_SHIFT;
++ else {
++ pr_err("%s: PLL not supported in slave mode\n",
++ __func__);
++ return -EINVAL;
++ }
++ } else
++ clk_ctl |= SGTL5000_MCLK_FREQ_PLL << SGTL5000_MCLK_FREQ_SHIFT;
++
++ if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) {
++ u64 out, t;
++ unsigned int in, int_div, frac_div;
++ if (sgtl5000->sysclk > 17000000) {
++ div2 = 1;
++ in = sgtl5000->sysclk / 2;
++ } else {
++ div2 = 0;
++ in = sgtl5000->sysclk;
++ }
++ if (sgtl5000->lrclk == 44100)
++ out = 180633600;
++ else
++ out = 196608000;
++ t = do_div(out, in);
++ int_div = out;
++ t *= 2048;
++ do_div(t, in);
++ frac_div = t;
++ pll_ctl = int_div << SGTL5000_PLL_INT_DIV_SHIFT |
++ frac_div << SGTL5000_PLL_FRAC_DIV_SHIFT;
++ }
++
++ i2s_ctl = sgtl5000_read(codec, SGTL5000_CHIP_I2S_CTRL);
++ switch (params_format(params)) {
++ case SNDRV_PCM_FORMAT_S16_LE:
++ if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
++ return -EINVAL;
++ i2s_ctl |= SGTL5000_I2S_DLEN_16 << SGTL5000_I2S_DLEN_SHIFT;
++ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_32FS <<
++ SGTL5000_I2S_SCLKFREQ_SHIFT;
++ break;
++ case SNDRV_PCM_FORMAT_S20_3LE:
++ i2s_ctl |= SGTL5000_I2S_DLEN_20 << SGTL5000_I2S_DLEN_SHIFT;
++ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
++ SGTL5000_I2S_SCLKFREQ_SHIFT;
++ break;
++ case SNDRV_PCM_FORMAT_S24_LE:
++ i2s_ctl |= SGTL5000_I2S_DLEN_24 << SGTL5000_I2S_DLEN_SHIFT;
++ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
++ SGTL5000_I2S_SCLKFREQ_SHIFT;
++ break;
++ case SNDRV_PCM_FORMAT_S32_LE:
++ if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J)
++ return -EINVAL;
++ i2s_ctl |= SGTL5000_I2S_DLEN_32 << SGTL5000_I2S_DLEN_SHIFT;
++ i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS <<
++ SGTL5000_I2S_SCLKFREQ_SHIFT;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ pr_debug("fs=%d,clk_ctl=%d,pll_ctl=%d,i2s_ctl=%d,div2=%d\n",
++ sgtl5000->lrclk, clk_ctl, pll_ctl, i2s_ctl, div2);
++
++ if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) {
++ sgtl5000_write(codec, SGTL5000_CHIP_PLL_CTRL, pll_ctl);
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_CLK_TOP_CTRL);
++ if (div2)
++ reg |= SGTL5000_INPUT_FREQ_DIV2;
++ else
++ reg &= ~SGTL5000_INPUT_FREQ_DIV2;
++ sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, reg);
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ reg |= SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ }
++ sgtl5000_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl);
++ sgtl5000_write(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl);
++
++ return 0;
++}
++
++static void sgtl5000_mic_bias(struct snd_soc_codec *codec, int enable)
++{
++ int reg, bias_r = 0;
++ if (enable)
++ bias_r = SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT;
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_MIC_CTRL);
++ if ((reg & SGTL5000_BIAS_R_MASK) != bias_r) {
++ reg &= ~SGTL5000_BIAS_R_MASK;
++ reg |= bias_r;
++ sgtl5000_write(codec, SGTL5000_CHIP_MIC_CTRL, reg);
++ }
++}
++
++static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
++ enum snd_soc_bias_level level)
++{
++ u16 reg, ana_pwr;
++ int delay = 0;
++ pr_debug("dapm level %d\n", level);
++ switch (level) {
++ case SND_SOC_BIAS_ON: /* full On */
++ if (codec->bias_level == SND_SOC_BIAS_ON)
++ break;
++
++ sgtl5000_mic_bias(codec, 1);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ reg |= SGTL5000_VAG_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ msleep(400);
++
++ break;
++
++ case SND_SOC_BIAS_PREPARE: /* partial On */
++ if (codec->bias_level == SND_SOC_BIAS_PREPARE)
++ break;
++
++ sgtl5000_mic_bias(codec, 0);
++
++ /* must power up hp/line out before vag & dac to
++ avoid pops. */
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ if (reg & SGTL5000_VAG_POWERUP)
++ delay = 400;
++ reg &= ~SGTL5000_VAG_POWERUP;
++ reg |= SGTL5000_DAC_POWERUP;
++ reg |= SGTL5000_HP_POWERUP;
++ reg |= SGTL5000_LINE_OUT_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ if (delay)
++ msleep(delay);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_DIG_POWER);
++ reg |= SGTL5000_DAC_EN;
++ sgtl5000_write(codec, SGTL5000_CHIP_DIG_POWER, reg);
++
++ break;
++
++ case SND_SOC_BIAS_STANDBY: /* Off, with power */
++ /* soc doesn't do PREPARE state after record so make sure
++ that anything that needs to be turned OFF gets turned off. */
++ if (codec->bias_level == SND_SOC_BIAS_STANDBY)
++ break;
++
++ /* soc calls digital_mute to unmute before record but doesn't
++ call digital_mute to mute after record. */
++ sgtl5000_digital_mute(&sgtl5000_dai, 1);
++
++ sgtl5000_mic_bias(codec, 0);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ if (reg & SGTL5000_VAG_POWERUP) {
++ reg &= ~SGTL5000_VAG_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ msleep(400);
++ }
++ reg &= ~SGTL5000_DAC_POWERUP;
++ reg &= ~SGTL5000_HP_POWERUP;
++ reg &= ~SGTL5000_LINE_OUT_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_DIG_POWER);
++ reg &= ~SGTL5000_DAC_EN;
++ sgtl5000_write(codec, SGTL5000_CHIP_DIG_POWER, reg);
++
++ break;
++
++ case SND_SOC_BIAS_OFF: /* Off, without power */
++ /* must power down hp/line out after vag & dac to
++ avoid pops. */
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ ana_pwr = reg;
++ reg &= ~SGTL5000_VAG_POWERUP;
++
++ /* Workaround for sgtl5000 rev 0x11 chip audio suspend failure
++ issue on mx25 */
++ reg &= ~SGTL5000_REFTOP_POWERUP;
++
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++ msleep(600);
++
++ reg &= ~SGTL5000_HP_POWERUP;
++ reg &= ~SGTL5000_LINE_OUT_POWERUP;
++ reg &= ~SGTL5000_DAC_POWERUP;
++ reg &= ~SGTL5000_ADC_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, reg);
++
++ /* save ANA POWER register value for resume */
++ sgtl5000_write_reg_cache(codec, SGTL5000_CHIP_ANA_POWER,
++ ana_pwr);
++ break;
++ }
++ codec->bias_level = level;
++ return 0;
++}
++
++#define SGTL5000_RATES (SNDRV_PCM_RATE_32000 |\
++ SNDRV_PCM_RATE_44100 |\
++ SNDRV_PCM_RATE_48000 |\
++ SNDRV_PCM_RATE_96000)
++
++#define SGTL5000_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
++ SNDRV_PCM_FMTBIT_S20_3LE |\
++ SNDRV_PCM_FMTBIT_S24_LE)
++
++struct snd_soc_dai_ops sgtl5000_ops = {
++ .prepare = sgtl5000_pcm_prepare,
++ .startup = sgtl5000_pcm_startup,
++ .shutdown = sgtl5000_pcm_shutdown,
++ .hw_params = sgtl5000_pcm_hw_params,
++ .digital_mute = sgtl5000_digital_mute,
++ .set_fmt = sgtl5000_set_dai_fmt,
++ .set_sysclk = sgtl5000_set_dai_sysclk
++};
++
++struct snd_soc_dai sgtl5000_dai = {
++ .name = "SGTL5000",
++ .playback = {
++ .stream_name = "Playback",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SGTL5000_RATES,
++ .formats = SGTL5000_FORMATS,
++ },
++ .capture = {
++ .stream_name = "Capture",
++ .channels_min = 2,
++ .channels_max = 2,
++ .rates = SGTL5000_RATES,
++ .formats = SGTL5000_FORMATS,
++ },
++ .ops = &sgtl5000_ops,
++ .symmetric_rates = 1,
++};
++EXPORT_SYMBOL_GPL(sgtl5000_dai);
++
++static int sgtl5000_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->card->codec;
++
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
++
++ return 0;
++}
++
++static int sgtl5000_resume(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->card->codec;
++ unsigned int i;
++
++ /* Restore refs first in same order as in sgtl5000_init */
++ sgtl5000_restore_reg(codec, SGTL5000_CHIP_LINREG_CTRL);
++ sgtl5000_restore_reg(codec, SGTL5000_CHIP_ANA_POWER);
++ msleep(10);
++ sgtl5000_restore_reg(codec, SGTL5000_CHIP_REF_CTRL);
++ sgtl5000_restore_reg(codec, SGTL5000_CHIP_LINE_OUT_CTRL);
++
++ /* Restore everythine else */
++ for (i = 1; i < sizeof(all_reg) / sizeof(int); i++)
++ sgtl5000_restore_reg(codec, all_reg[i]);
++
++ sgtl5000_write(codec, SGTL5000_DAP_CTRL, 0);
++
++ /* Bring the codec back up to standby first to minimise pop/clicks */
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++ if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
++ sgtl5000_set_bias_level(codec, codec->suspend_bias_level);
++
++ return 0;
++}
++
++static struct snd_soc_codec *sgtl5000_codec;
++
++/*
++ * initialise the SGTL5000 driver
++ * register the mixer and dsp interfaces with the kernel
++ */
++static int sgtl5000_probe(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = sgtl5000_codec;
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++ u16 reg, ana_pwr, lreg_ctrl, ref_ctrl, lo_ctrl, short_ctrl, sss;
++ int vag;
++ int ret = 0;
++
++ socdev->card->codec = sgtl5000_codec;
++
++ /* register pcms */
++ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
++ if (ret < 0) {
++ dev_err(codec->dev, "failed to create pcms\n");
++ return ret;
++ }
++
++ /* reset value */
++ ana_pwr = SGTL5000_DAC_STEREO |
++ SGTL5000_LINREG_SIMPLE_POWERUP |
++ SGTL5000_STARTUP_POWERUP |
++ SGTL5000_ADC_STEREO | SGTL5000_REFTOP_POWERUP;
++ lreg_ctrl = 0;
++ ref_ctrl = 0;
++ lo_ctrl = 0;
++ short_ctrl = 0;
++ sss = SGTL5000_DAC_SEL_I2S_IN << SGTL5000_DAC_SEL_SHIFT;
++
++ /* workaround for rev 0x11: use vddd linear regulator */
++ if (sgtl5000->rev >= 0x11) {
++ /* set VDDD to 1.2v */
++ lreg_ctrl |= 0x8 << SGTL5000_LINREG_VDDD_SHIFT;
++ /* power internal linear regulator */
++ ana_pwr |= SGTL5000_LINEREG_D_POWERUP;
++ }
++
++ /* Enable VDDC charge pump (VDDIO || VDDA) > 3V */
++ ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP;
++
++ /* VDDC use VDDIO rail */
++ lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD;
++ /* (VDDIO || VDDA) > 3V */
++ lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << SGTL5000_VDDC_MAN_ASSN_SHIFT;
++
++ /* If PLL is powered up (such as on power cycle) leave it on. */
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_POWER);
++ ana_pwr |= reg & (SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP); // MASU FIXME
++
++ /* set ADC/DAC ref voltage to vdda/2 */
++ vag = 3300 / 2;
++ if (vag <= SGTL5000_ANA_GND_BASE)
++ vag = 0;
++ else if (vag >= SGTL5000_ANA_GND_BASE + SGTL5000_ANA_GND_STP *
++ (SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT))
++ vag = SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT;
++ else
++ vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
++ ref_ctrl |= vag << SGTL5000_ANA_GND_SHIFT;
++
++ /* enable small pop */
++ ref_ctrl |= SGTL5000_SMALL_POP;
++
++ /* set line out ref voltage to vddio/2 */
++ vag = 3300 / 2;
++ if (vag <= SGTL5000_LINE_OUT_GND_BASE)
++ vag = 0;
++ else if (vag >= SGTL5000_LINE_OUT_GND_BASE + SGTL5000_LINE_OUT_GND_STP *
++ SGTL5000_LINE_OUT_GND_MAX)
++ vag = SGTL5000_LINE_OUT_GND_MAX;
++ else
++ vag = (vag - SGTL5000_LINE_OUT_GND_BASE) /
++ SGTL5000_LINE_OUT_GND_STP;
++ lo_ctrl |= vag << SGTL5000_LINE_OUT_GND_SHIFT;
++
++ /* Controls the output bias current for the lineout */
++ lo_ctrl |=
++ (SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_CURRENT_SHIFT);
++
++ /* set short detect */
++ ana_pwr |= 0x0000;
++ /* keep default */
++
++ /* set routing */
++ /* keep default, bypass DAP */
++
++ sgtl5000_write(codec, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl);
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr);
++ msleep(10);
++
++ /* For rev 0x11, if vddd linear reg has been enabled, we have
++ to disable simple reg to get proper VDDD voltage. */
++ if ((ana_pwr & SGTL5000_LINEREG_D_POWERUP) && (sgtl5000->rev >= 0x11)) {
++ ana_pwr &= ~SGTL5000_LINREG_SIMPLE_POWERUP;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr);
++ msleep(10);
++ }
++
++ sgtl5000_write(codec, SGTL5000_CHIP_REF_CTRL, ref_ctrl);
++ sgtl5000_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL, lo_ctrl);
++ sgtl5000_write(codec, SGTL5000_CHIP_SHORT_CTRL, short_ctrl);
++ sgtl5000_write(codec, SGTL5000_CHIP_SSS_CTRL, sss);
++ sgtl5000_write(codec, SGTL5000_CHIP_DIG_POWER, 0);
++
++ reg = SGTL5000_DAC_VOL_RAMP_EN |
++ SGTL5000_DAC_MUTE_RIGHT | SGTL5000_DAC_MUTE_LEFT;
++ sgtl5000_write(codec, SGTL5000_CHIP_ADCDAC_CTRL, reg);
++
++#ifdef CONFIG_ARCH_MXC
++ if (cpu_is_mx25())
++ sgtl5000_write(codec, SGTL5000_CHIP_PAD_STRENGTH, 0x01df);
++ else
++#endif
++ sgtl5000_write(codec, SGTL5000_CHIP_PAD_STRENGTH, 0x015f);
++
++ reg = sgtl5000_read(codec, SGTL5000_CHIP_ANA_ADC_CTRL);
++ reg &= ~SGTL5000_ADC_VOL_M6DB;
++ reg &= ~(SGTL5000_ADC_VOL_LEFT_MASK | SGTL5000_ADC_VOL_RIGHT_MASK);
++ reg |= (0xf << SGTL5000_ADC_VOL_LEFT_SHIFT)
++ | (0xf << SGTL5000_ADC_VOL_RIGHT_SHIFT);
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_ADC_CTRL, reg);
++
++ reg = SGTL5000_LINE_OUT_MUTE | SGTL5000_HP_MUTE |
++ SGTL5000_HP_ZCD_EN | SGTL5000_ADC_ZCD_EN;
++ sgtl5000_write(codec, SGTL5000_CHIP_ANA_CTRL, reg);
++
++ sgtl5000_write(codec, SGTL5000_CHIP_MIC_CTRL, 0);
++ sgtl5000_write(codec, SGTL5000_CHIP_CLK_TOP_CTRL, 0);
++ /* disable DAP */
++ sgtl5000_write(codec, SGTL5000_DAP_CTRL, 0);
++ /* TODO: initialize DAP */
++
++ snd_soc_add_controls(codec, sgtl5000_snd_controls,
++ ARRAY_SIZE(sgtl5000_snd_controls));
++ sgtl5000_add_widgets(codec);
++
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
++
++// MASU Do we need this ?
++// ret = snd_soc_init_card(socdev);
++// if (ret < 0) {
++// printk(KERN_ERR "sgtl5000: failed to register card\n");
++// snd_soc_free_pcms(socdev);
++// snd_soc_dapm_free(socdev);
++// return ret;
++// }
++
++ return 0;
++}
++
++/* power down chip */
++static int sgtl5000_remove(struct platform_device *pdev)
++{
++ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
++ struct snd_soc_codec *codec = socdev->card->codec;
++
++ if (codec->control_data)
++ sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF);
++ snd_soc_free_pcms(socdev);
++ snd_soc_dapm_free(socdev);
++
++ return 0;
++}
++
++struct snd_soc_codec_device soc_codec_dev_sgtl5000 = {
++ .probe = sgtl5000_probe,
++ .remove = sgtl5000_remove,
++ .suspend = sgtl5000_suspend,
++ .resume = sgtl5000_resume,
++};
++EXPORT_SYMBOL_GPL(soc_codec_dev_sgtl5000);
++
++static __devinit int sgtl5000_i2c_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct sgtl5000_priv *sgtl5000;
++ struct snd_soc_codec *codec;
++ struct regulator *reg;
++ int ret = 0;
++ u32 val;
++
++ if (sgtl5000_codec) {
++ dev_err(&client->dev,
++ "Multiple SGTL5000 devices not supported\n");
++ return -ENOMEM;
++ }
++
++ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
++ if (codec == NULL)
++ return -ENOMEM;
++
++ sgtl5000 = kzalloc(sizeof(struct sgtl5000_priv), GFP_KERNEL);
++ if (sgtl5000 == NULL) {
++ kfree(codec);
++ return -ENOMEM;
++ }
++
++ codec->drvdata = sgtl5000;
++ mutex_init(&codec->mutex);
++ INIT_LIST_HEAD(&codec->dapm_widgets);
++ INIT_LIST_HEAD(&codec->dapm_paths);
++
++ i2c_set_clientdata(client, codec);
++ codec->control_data = client;
++
++ msleep(1);
++
++ val = sgtl5000_read(codec, SGTL5000_CHIP_ID);
++ if (((val & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) !=
++ SGTL5000_PARTID_PART_ID) {
++ pr_err("Device with ID register %x is not a SGTL5000\n", val);
++ ret = -ENODEV;
++ goto err_codec_reg;
++ }
++
++ sgtl5000->rev = (val & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT;
++ dev_info(&client->dev, "SGTL5000 revision %d\n", sgtl5000->rev);
++
++ codec->dev = &client->dev;
++ codec->name = "SGTL5000";
++ codec->owner = THIS_MODULE;
++ codec->read = sgtl5000_read_reg_cache;
++ codec->write = sgtl5000_write;
++ codec->bias_level = SND_SOC_BIAS_OFF;
++ codec->set_bias_level = sgtl5000_set_bias_level;
++ codec->dai = &sgtl5000_dai;
++ codec->num_dai = 1;
++ codec->reg_cache_size = sizeof(sgtl5000_regs);
++ codec->reg_cache_step = 2;
++ codec->reg_cache = (void *)&sgtl5000_regs;
++
++ sgtl5000_sync_reg_cache(codec);
++
++ sgtl5000_codec = codec;
++ sgtl5000_dai.dev = &client->dev;
++
++ ret = snd_soc_register_codec(codec);
++ if (ret != 0) {
++ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
++ goto err_codec_reg;
++ }
++
++ ret = snd_soc_register_dai(&sgtl5000_dai);
++ if (ret != 0) {
++ dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
++ goto err_codec_reg;
++ }
++
++ return 0;
++
++err_codec_reg:
++ kfree(sgtl5000);
++ kfree(codec);
++ return ret;
++}
++
++static __devexit int sgtl5000_i2c_remove(struct i2c_client *client)
++{
++ struct snd_soc_codec *codec = i2c_get_clientdata(client);
++ struct sgtl5000_priv *sgtl5000 = codec->drvdata;
++
++ if (client->dev.platform_data)
++ clk_disable((struct clk *)client->dev.platform_data);
++
++ snd_soc_unregister_dai(&sgtl5000_dai);
++ snd_soc_unregister_codec(codec);
++
++ kfree(codec);
++ kfree(sgtl5000);
++ sgtl5000_codec = NULL;
++ return 0;
++}
++
++static const struct i2c_device_id sgtl5000_id[] = {
++ {"sgtl5000-i2c", 0},
++ {},
++};
++
++MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
++
++static struct i2c_driver sgtl5000_i2c_driver = {
++ .driver = {
++ .name = "sgtl5000-i2c",
++ .owner = THIS_MODULE,
++ },
++ .probe = sgtl5000_i2c_probe,
++ .remove = __devexit_p(sgtl5000_i2c_remove),
++ .id_table = sgtl5000_id,
++};
++
++static int __init sgtl5000_modinit(void)
++{
++ return i2c_add_driver(&sgtl5000_i2c_driver);
++}
++module_init(sgtl5000_modinit);
++
++static void __exit sgtl5000_exit(void)
++{
++ i2c_del_driver(&sgtl5000_i2c_driver);
++}
++module_exit(sgtl5000_exit);
++
++MODULE_DESCRIPTION("ASoC SGTL5000 driver");
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/sound/soc/codecs/sgtl5000.h linux.35.new/sound/soc/codecs/sgtl5000.h
+--- linux.35.old/sound/soc/codecs/sgtl5000.h 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/sound/soc/codecs/sgtl5000.h 2010-12-03 09:51:55.492348513 +0100
+@@ -0,0 +1,399 @@
++/*
++ * sgtl5000.h - SGTL5000 audio codec interface
++ *
++ * Copyright 2008-2009 Freescale 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.
++ */
++
++#ifndef _SGTL5000_H
++#define _SGTL5000_H
++
++#include <linux/i2c.h>
++
++extern struct snd_soc_dai sgtl5000_dai;
++extern struct snd_soc_codec_device soc_codec_dev_sgtl5000;
++
++/*
++ * Register values.
++ */
++#define SGTL5000_CHIP_ID 0x0000
++#define SGTL5000_CHIP_DIG_POWER 0x0002
++#define SGTL5000_CHIP_CLK_CTRL 0x0004
++#define SGTL5000_CHIP_I2S_CTRL 0x0006
++#define SGTL5000_CHIP_SSS_CTRL 0x000a
++#define SGTL5000_CHIP_ADCDAC_CTRL 0x000e
++#define SGTL5000_CHIP_DAC_VOL 0x0010
++#define SGTL5000_CHIP_PAD_STRENGTH 0x0014
++#define SGTL5000_CHIP_ANA_ADC_CTRL 0x0020
++#define SGTL5000_CHIP_ANA_HP_CTRL 0x0022
++#define SGTL5000_CHIP_ANA_CTRL 0x0024
++#define SGTL5000_CHIP_LINREG_CTRL 0x0026
++#define SGTL5000_CHIP_REF_CTRL 0x0028
++#define SGTL5000_CHIP_MIC_CTRL 0x002a
++#define SGTL5000_CHIP_LINE_OUT_CTRL 0x002c
++#define SGTL5000_CHIP_LINE_OUT_VOL 0x002e
++#define SGTL5000_CHIP_ANA_POWER 0x0030
++#define SGTL5000_CHIP_PLL_CTRL 0x0032
++#define SGTL5000_CHIP_CLK_TOP_CTRL 0x0034
++#define SGTL5000_CHIP_ANA_STATUS 0x0036
++#define SGTL5000_CHIP_SHORT_CTRL 0x003c
++#define SGTL5000_CHIP_ANA_TEST2 0x003a
++#define SGTL5000_DAP_CTRL 0x0100
++#define SGTL5000_DAP_PEQ 0x0102
++#define SGTL5000_DAP_BASS_ENHANCE 0x0104
++#define SGTL5000_DAP_BASS_ENHANCE_CTRL 0x0106
++#define SGTL5000_DAP_AUDIO_EQ 0x0108
++#define SGTL5000_DAP_SURROUND 0x010a
++#define SGTL5000_DAP_FLT_COEF_ACCESS 0x010c
++#define SGTL5000_DAP_COEF_WR_B0_MSB 0x010e
++#define SGTL5000_DAP_COEF_WR_B0_LSB 0x0110
++#define SGTL5000_DAP_EQ_BASS_BAND0 0x0116
++#define SGTL5000_DAP_EQ_BASS_BAND1 0x0118
++#define SGTL5000_DAP_EQ_BASS_BAND2 0x011a
++#define SGTL5000_DAP_EQ_BASS_BAND3 0x011c
++#define SGTL5000_DAP_EQ_BASS_BAND4 0x011e
++#define SGTL5000_DAP_MAIN_CHAN 0x0120
++#define SGTL5000_DAP_MIX_CHAN 0x0122
++#define SGTL5000_DAP_AVC_CTRL 0x0124
++#define SGTL5000_DAP_AVC_THRESHOLD 0x0126
++#define SGTL5000_DAP_AVC_ATTACK 0x0128
++#define SGTL5000_DAP_AVC_DECAY 0x012a
++#define SGTL5000_DAP_COEF_WR_B1_MSB 0x012c
++#define SGTL5000_DAP_COEF_WR_B1_LSB 0x012e
++#define SGTL5000_DAP_COEF_WR_B2_MSB 0x0130
++#define SGTL5000_DAP_COEF_WR_B2_LSB 0x0132
++#define SGTL5000_DAP_COEF_WR_A1_MSB 0x0134
++#define SGTL5000_DAP_COEF_WR_A1_LSB 0x0136
++#define SGTL5000_DAP_COEF_WR_A2_MSB 0x0138
++#define SGTL5000_DAP_COEF_WR_A2_LSB 0x013a
++
++/*
++ * Field Definitions.
++ */
++
++/*
++ * SGTL5000_CHIP_ID
++ */
++#define SGTL5000_PARTID_MASK 0xff00
++#define SGTL5000_PARTID_SHIFT 8
++#define SGTL5000_PARTID_WIDTH 8
++#define SGTL5000_PARTID_PART_ID 0xa0
++#define SGTL5000_REVID_MASK 0x00ff
++#define SGTL5000_REVID_SHIFT 0
++#define SGTL5000_REVID_WIDTH 8
++
++/*
++ * SGTL5000_CHIP_DIG_POWER
++ */
++#define SGTL5000_ADC_EN 0x0040
++#define SGTL5000_DAC_EN 0x0020
++#define SGTL5000_DAP_POWERUP 0x0010
++#define SGTL5000_I2S_OUT_POWERUP 0x0002
++#define SGTL5000_I2S_IN_POWERUP 0x0001
++
++/*
++ * SGTL5000_CHIP_CLK_CTRL
++ */
++#define SGTL5000_SYS_FS_MASK 0x00c0
++#define SGTL5000_SYS_FS_SHIFT 2
++#define SGTL5000_SYS_FS_WIDTH 2
++#define SGTL5000_SYS_FS_32k 0x0
++#define SGTL5000_SYS_FS_44_1k 0x1
++#define SGTL5000_SYS_FS_48k 0x2
++#define SGTL5000_SYS_FS_96k 0x3
++#define SGTL5000_MCLK_FREQ_MASK 0x0003
++#define SGTL5000_MCLK_FREQ_SHIFT 0
++#define SGTL5000_MCLK_FREQ_WIDTH 2
++#define SGTL5000_MCLK_FREQ_256FS 0x0
++#define SGTL5000_MCLK_FREQ_384FS 0x1
++#define SGTL5000_MCLK_FREQ_512FS 0x2
++#define SGTL5000_MCLK_FREQ_PLL 0x3
++
++/*
++ * SGTL5000_CHIP_I2S_CTRL
++ */
++#define SGTL5000_I2S_SCLKFREQ_MASK 0x0100
++#define SGTL5000_I2S_SCLKFREQ_SHIFT 8
++#define SGTL5000_I2S_SCLKFREQ_WIDTH 1
++#define SGTL5000_I2S_SCLKFREQ_64FS 0x0
++#define SGTL5000_I2S_SCLKFREQ_32FS 0x1 /* Not for RJ mode */
++#define SGTL5000_I2S_MASTER 0x0080
++#define SGTL5000_I2S_SCLK_INV 0x0040
++#define SGTL5000_I2S_DLEN_MASK 0x0030
++#define SGTL5000_I2S_DLEN_SHIFT 4
++#define SGTL5000_I2S_DLEN_WIDTH 2
++#define SGTL5000_I2S_DLEN_32 0x0
++#define SGTL5000_I2S_DLEN_24 0x1
++#define SGTL5000_I2S_DLEN_20 0x2
++#define SGTL5000_I2S_DLEN_16 0x3
++#define SGTL5000_I2S_MODE_MASK 0x000c
++#define SGTL5000_I2S_MODE_SHIFT 2
++#define SGTL5000_I2S_MODE_WIDTH 2
++#define SGTL5000_I2S_MODE_I2S_LJ 0x0
++#define SGTL5000_I2S_MODE_RJ 0x1
++#define SGTL5000_I2S_MODE_PCM 0x2
++#define SGTL5000_I2S_LRALIGN 0x0002
++#define SGTL5000_I2S_LRPOL 0x0001 /* set for which mode */
++
++/*
++ * SGTL5000_CHIP_SSS_CTRL
++ */
++#define SGTL5000_DAP_MIX_LRSWAP 0x4000
++#define SGTL5000_DAP_LRSWAP 0x2000
++#define SGTL5000_DAC_LRSWAP 0x1000
++#define SGTL5000_I2S_OUT_LRSWAP 0x0400
++#define SGTL5000_DAP_MIX_SEL_MASK 0x0300
++#define SGTL5000_DAP_MIX_SEL_SHIFT 8
++#define SGTL5000_DAP_MIX_SEL_WIDTH 2
++#define SGTL5000_DAP_MIX_SEL_ADC 0x0
++#define SGTL5000_DAP_MIX_SEL_I2S_IN 0x1
++#define SGTL5000_DAP_SEL_MASK 0x00c0
++#define SGTL5000_DAP_SEL_SHIFT 6
++#define SGTL5000_DAP_SEL_WIDTH 2
++#define SGTL5000_DAP_SEL_ADC 0x0
++#define SGTL5000_DAP_SEL_I2S_IN 0x1
++#define SGTL5000_DAC_SEL_MASK 0x0030
++#define SGTL5000_DAC_SEL_SHIFT 4
++#define SGTL5000_DAC_SEL_WIDTH 2
++#define SGTL5000_DAC_SEL_ADC 0x0
++#define SGTL5000_DAC_SEL_I2S_IN 0x1
++#define SGTL5000_DAC_SEL_DAP 0x3
++#define SGTL5000_I2S_OUT_SEL_MASK 0x0003
++#define SGTL5000_I2S_OUT_SEL_SHIFT 0
++#define SGTL5000_I2S_OUT_SEL_WIDTH 2
++#define SGTL5000_I2S_OUT_SEL_ADC 0x0
++#define SGTL5000_I2S_OUT_SEL_I2S_IN 0x1
++#define SGTL5000_I2S_OUT_SEL_DAP 0x3
++
++/*
++ * SGTL5000_CHIP_ADCDAC_CTRL
++ */
++#define SGTL5000_VOL_BUSY_DAC_RIGHT 0x2000
++#define SGTL5000_VOL_BUSY_DAC_LEFT 0x1000
++#define SGTL5000_DAC_VOL_RAMP_EN 0x0200
++#define SGTL5000_DAC_VOL_RAMP_EXPO 0x0100
++#define SGTL5000_DAC_MUTE_RIGHT 0x0008
++#define SGTL5000_DAC_MUTE_LEFT 0x0004
++#define SGTL5000_ADC_HPF_FREEZE 0x0002
++#define SGTL5000_ADC_HPF_BYPASS 0x0001
++
++/*
++ * SGTL5000_CHIP_DAC_VOL
++ */
++#define SGTL5000_DAC_VOL_RIGHT_MASK 0xff00
++#define SGTL5000_DAC_VOL_RIGHT_SHIFT 8
++#define SGTL5000_DAC_VOL_RIGHT_WIDTH 8
++#define SGTL5000_DAC_VOL_LEFT_MASK 0x00ff
++#define SGTL5000_DAC_VOL_LEFT_SHIFT 0
++#define SGTL5000_DAC_VOL_LEFT_WIDTH 8
++
++/*
++ * SGTL5000_CHIP_PAD_STRENGTH
++ */
++#define SGTL5000_PAD_I2S_LRCLK_MASK 0x0300
++#define SGTL5000_PAD_I2S_LRCLK_SHIFT 8
++#define SGTL5000_PAD_I2S_LRCLK_WIDTH 2
++#define SGTL5000_PAD_I2S_SCLK_MASK 0x00c0
++#define SGTL5000_PAD_I2S_SCLK_SHIFT 6
++#define SGTL5000_PAD_I2S_SCLK_WIDTH 2
++#define SGTL5000_PAD_I2S_DOUT_MASK 0x0030
++#define SGTL5000_PAD_I2S_DOUT_SHIFT 4
++#define SGTL5000_PAD_I2S_DOUT_WIDTH 2
++#define SGTL5000_PAD_I2C_SDA_MASK 0x000c
++#define SGTL5000_PAD_I2C_SDA_SHIFT 2
++#define SGTL5000_PAD_I2C_SDA_WIDTH 2
++#define SGTL5000_PAD_I2C_SCL_MASK 0x0003
++#define SGTL5000_PAD_I2C_SCL_SHIFT 0
++#define SGTL5000_PAD_I2C_SCL_WIDTH 2
++
++/*
++ * SGTL5000_CHIP_ANA_ADC_CTRL
++ */
++#define SGTL5000_ADC_VOL_M6DB 0x0100
++#define SGTL5000_ADC_VOL_RIGHT_MASK 0x00f0
++#define SGTL5000_ADC_VOL_RIGHT_SHIFT 4
++#define SGTL5000_ADC_VOL_RIGHT_WIDTH 4
++#define SGTL5000_ADC_VOL_LEFT_MASK 0x000f
++#define SGTL5000_ADC_VOL_LEFT_SHIFT 0
++#define SGTL5000_ADC_VOL_LEFT_WIDTH 4
++
++/*
++ * SGTL5000_CHIP_ANA_HP_CTRL
++ */
++#define SGTL5000_HP_VOL_RIGHT_MASK 0x7f00
++#define SGTL5000_HP_VOL_RIGHT_SHIFT 8
++#define SGTL5000_HP_VOL_RIGHT_WIDTH 7
++#define SGTL5000_HP_VOL_LEFT_MASK 0x007f
++#define SGTL5000_HP_VOL_LEFT_SHIFT 0
++#define SGTL5000_HP_VOL_LEFT_WIDTH 7
++
++/*
++ * SGTL5000_CHIP_ANA_CTRL
++ */
++#define SGTL5000_LINE_OUT_MUTE 0x0100
++#define SGTL5000_HP_SEL_MASK 0x0040
++#define SGTL5000_HP_SEL_SHIFT 6
++#define SGTL5000_HP_SEL_WIDTH 1
++#define SGTL5000_HP_SEL_DAC 0x0
++#define SGTL5000_HP_SEL_LINE_IN 0x1
++#define SGTL5000_HP_ZCD_EN 0x0020
++#define SGTL5000_HP_MUTE 0x0010
++#define SGTL5000_ADC_SEL_MASK 0x0004
++#define SGTL5000_ADC_SEL_SHIFT 2
++#define SGTL5000_ADC_SEL_WIDTH 1
++#define SGTL5000_ADC_SEL_MIC 0x0
++#define SGTL5000_ADC_SEL_LINE_IN 0x1
++#define SGTL5000_ADC_ZCD_EN 0x0002
++#define SGTL5000_ADC_MUTE 0x0001
++
++/*
++ * SGTL5000_CHIP_LINREG_CTRL
++ */
++#define SGTL5000_VDDC_MAN_ASSN_MASK 0x0040
++#define SGTL5000_VDDC_MAN_ASSN_SHIFT 6
++#define SGTL5000_VDDC_MAN_ASSN_WIDTH 1
++#define SGTL5000_VDDC_MAN_ASSN_VDDA 0x0
++#define SGTL5000_VDDC_MAN_ASSN_VDDIO 0x1
++#define SGTL5000_VDDC_ASSN_OVRD 0x0020
++#define SGTL5000_LINREG_VDDD_MASK 0x000f
++#define SGTL5000_LINREG_VDDD_SHIFT 0
++#define SGTL5000_LINREG_VDDD_WIDTH 4
++
++/*
++ * SGTL5000_CHIP_REF_CTRL
++ */
++#define SGTL5000_ANA_GND_MASK 0x01f0
++#define SGTL5000_ANA_GND_SHIFT 4
++#define SGTL5000_ANA_GND_WIDTH 5
++#define SGTL5000_ANA_GND_BASE 800 /* mv */
++#define SGTL5000_ANA_GND_STP 25 /*mv */
++#define SGTL5000_BIAS_CTRL_MASK 0x000e
++#define SGTL5000_BIAS_CTRL_SHIFT 1
++#define SGTL5000_BIAS_CTRL_WIDTH 3
++#define SGTL5000_SMALL_POP 0x0001
++
++/*
++ * SGTL5000_CHIP_MIC_CTRL
++ */
++#define SGTL5000_BIAS_R_MASK 0x0200
++#define SGTL5000_BIAS_R_SHIFT 8
++#define SGTL5000_BIAS_R_WIDTH 2
++#define SGTL5000_BIAS_R_off 0x0
++#define SGTL5000_BIAS_R_2K 0x1
++#define SGTL5000_BIAS_R_4k 0x2
++#define SGTL5000_BIAS_R_8k 0x3
++#define SGTL5000_BIAS_VOLT_MASK 0x0070
++#define SGTL5000_BIAS_VOLT_SHIFT 4
++#define SGTL5000_BIAS_VOLT_WIDTH 3
++#define SGTL5000_MIC_GAIN_MASK 0x0003
++#define SGTL5000_MIC_GAIN_SHIFT 0
++#define SGTL5000_MIC_GAIN_WIDTH 2
++
++/*
++ * SGTL5000_CHIP_LINE_OUT_CTRL
++ */
++#define SGTL5000_LINE_OUT_CURRENT_MASK 0x0f00
++#define SGTL5000_LINE_OUT_CURRENT_SHIFT 8
++#define SGTL5000_LINE_OUT_CURRENT_WIDTH 4
++#define SGTL5000_LINE_OUT_CURRENT_180u 0x0
++#define SGTL5000_LINE_OUT_CURRENT_270u 0x1
++#define SGTL5000_LINE_OUT_CURRENT_360u 0x3
++#define SGTL5000_LINE_OUT_CURRENT_450u 0x7
++#define SGTL5000_LINE_OUT_CURRENT_540u 0xf
++#define SGTL5000_LINE_OUT_GND_MASK 0x003f
++#define SGTL5000_LINE_OUT_GND_SHIFT 0
++#define SGTL5000_LINE_OUT_GND_WIDTH 6
++#define SGTL5000_LINE_OUT_GND_BASE 800 /* mv */
++#define SGTL5000_LINE_OUT_GND_STP 25
++#define SGTL5000_LINE_OUT_GND_MAX 0x23
++
++/*
++ * SGTL5000_CHIP_LINE_OUT_VOL
++ */
++#define SGTL5000_LINE_OUT_VOL_RIGHT_MASK 0x1f00
++#define SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT 8
++#define SGTL5000_LINE_OUT_VOL_RIGHT_WIDTH 5
++#define SGTL5000_LINE_OUT_VOL_LEFT_MASK 0x001f
++#define SGTL5000_LINE_OUT_VOL_LEFT_SHIFT 0
++#define SGTL5000_LINE_OUT_VOL_LEFT_WIDTH 5
++
++/*
++ * SGTL5000_CHIP_ANA_POWER
++ */
++#define SGTL5000_DAC_STEREO 0x4000
++#define SGTL5000_LINREG_SIMPLE_POWERUP 0x2000
++#define SGTL5000_STARTUP_POWERUP 0x1000
++#define SGTL5000_VDDC_CHRGPMP_POWERUP 0x0800
++#define SGTL5000_PLL_POWERUP 0x0400
++#define SGTL5000_LINEREG_D_POWERUP 0x0200
++#define SGTL5000_VCOAMP_POWERUP 0x0100
++#define SGTL5000_VAG_POWERUP 0x0080
++#define SGTL5000_ADC_STEREO 0x0040
++#define SGTL5000_REFTOP_POWERUP 0x0020
++#define SGTL5000_HP_POWERUP 0x0010
++#define SGTL5000_DAC_POWERUP 0x0008
++#define SGTL5000_CAPLESS_HP_POWERUP 0x0004
++#define SGTL5000_ADC_POWERUP 0x0002
++#define SGTL5000_LINE_OUT_POWERUP 0x0001
++
++/*
++ * SGTL5000_CHIP_PLL_CTRL
++ */
++#define SGTL5000_PLL_INT_DIV_MASK 0xf800
++#define SGTL5000_PLL_INT_DIV_SHIFT 11
++#define SGTL5000_PLL_INT_DIV_WIDTH 5
++#define SGTL5000_PLL_FRAC_DIV_MASK 0x0700
++#define SGTL5000_PLL_FRAC_DIV_SHIFT 0
++#define SGTL5000_PLL_FRAC_DIV_WIDTH 11
++
++/*
++ * SGTL5000_CHIP_CLK_TOP_CTRL
++ */
++#define SGTL5000_INT_OSC_EN 0x0800
++#define SGTL5000_INPUT_FREQ_DIV2 0x0008
++
++/*
++ * SGTL5000_CHIP_ANA_STATUS
++ */
++#define SGTL5000_HP_LRSHORT 0x0200
++#define SGTL5000_CAPLESS_SHORT 0x0100
++#define SGTL5000_PLL_LOCKED 0x0010
++
++/*
++ * SGTL5000_CHIP_SHORT_CTRL
++ */
++#define SGTL5000_LVLADJR_MASK 0x7000
++#define SGTL5000_LVLADJR_SHIFT 12
++#define SGTL5000_LVLADJR_WIDTH 3
++#define SGTL5000_LVLADJL_MASK 0x0700
++#define SGTL5000_LVLADJL_SHIFT 8
++#define SGTL5000_LVLADJL_WIDTH 3
++#define SGTL5000_LVLADJC_MASK 0x0070
++#define SGTL5000_LVLADJC_SHIFT 4
++#define SGTL5000_LVLADJC_WIDTH 3
++#define SGTL5000_LR_SHORT_MOD_MASK 0x000c
++#define SGTL5000_LR_SHORT_MOD_SHIFT 2
++#define SGTL5000_LR_SHORT_MOD_WIDTH 2
++#define SGTL5000_CM_SHORT_MOD_MASK 0x0003
++#define SGTL5000_CM_SHORT_MOD_SHIFT 0
++#define SGTL5000_CM_SHORT_MOD_WIDTH 2
++
++/*
++ *SGTL5000_CHIP_ANA_TEST2
++ */
++#define SGTL5000_MONO_DAC 0x1000
++
++/*
++ * SGTL5000_DAP_CTRL
++ */
++#define SGTL5000_DAP_MIX_EN 0x0010
++#define SGTL5000_DAP_EN 0x0001
++
++#define SGTL5000_SYSCLK 0x00
++#define SGTL5000_LRCLK 0x01
++
++#endif
+diff -urN linux.35.old/sound/soc/imx/imx-3stack-sgtl5000.c linux.35.new/sound/soc/imx/imx-3stack-sgtl5000.c
+--- linux.35.old/sound/soc/imx/imx-3stack-sgtl5000.c 1970-01-01 01:00:00.000000000 +0100
++++ linux.35.new/sound/soc/imx/imx-3stack-sgtl5000.c 2010-12-03 09:51:55.492348513 +0100
+@@ -0,0 +1,654 @@
++/*
++ * imx-3stack-sgtl5000.c -- i.MX 3Stack Driver for Freescale SGTL5000 Codec
++ *
++ * Copyright (C) 2008-2010 Freescale Semiconductor, 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.
++ *
++ * Revision history
++ * 21th Oct 2008 Initial version.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/pm.h>
++#include <linux/bitops.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/err.h>
++#include <linux/irq.h>
++#include <linux/io.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/pcm_params.h>
++#include <sound/soc.h>
++#include <sound/soc-dapm.h>
++#include <sound/initval.h>
++
++#include <mach/dma.h>
++#include <mach/clock.h>
++#include <mach/ssi.h>
++
++#include "../codecs/sgtl5000.h"
++#include "imx-ssi.h"
++//#include "imx-pcm.h"
++
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++#include <linux/mxc_asrc.h>
++
++static unsigned int sgtl5000_rates[] = {
++ 0,
++ 32000,
++ 44100,
++ 48000,
++ 96000,
++};
++
++struct asrc_esai {
++ unsigned int cpu_dai_rates;
++ unsigned int codec_dai_rates;
++ enum asrc_pair_index asrc_index;
++ unsigned int output_sample_rate;
++};
++
++static struct asrc_esai asrc_ssi_data;
++#endif
++
++/* SSI BCLK and LRC master */
++#define SGTL5000_SSI_MASTER 1
++
++struct imx_3stack_priv {
++ int sysclk;
++ int hw;
++ struct platform_device *pdev;
++};
++
++static struct imx_3stack_priv card_priv;
++
++static int imx_3stack_audio_hw_params(struct snd_pcm_substream *substream,
++ struct snd_pcm_hw_params *params)
++{
++ struct snd_soc_pcm_runtime *rtd = substream->private_data;
++ struct snd_soc_dai_link *machine = rtd->dai;
++ struct snd_soc_dai *cpu_dai = machine->cpu_dai;
++ struct snd_soc_dai *codec_dai = machine->codec_dai;
++ struct imx_3stack_priv *priv = &card_priv;
++ unsigned int rate = params_rate(params);
++ struct imx_ssi *ssi_mode = (struct imx_ssi *)cpu_dai->private_data;
++ int ret = 0;
++
++ unsigned int channels = params_channels(params);
++ u32 dai_format;
++
++ /* only need to do this once as capture and playback are sync */
++ if (priv->hw)
++ return 0;
++ priv->hw = 1;
++
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++ if ((asrc_ssi_data.output_sample_rate != 0)
++ && (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) {
++ unsigned int asrc_input_rate = rate;
++ unsigned int channel = params_channels(params);
++ struct mxc_runtime_data *pcm_data =
++ substream->runtime->private_data;
++ struct asrc_config config;
++ struct mxc_audio_platform_data *plat;
++ struct imx_3stack_priv *priv = &card_priv;
++ int retVal = 0;
++ retVal = asrc_req_pair(channel, &asrc_ssi_data.asrc_index);
++ if (retVal < 0) {
++ pr_err("asrc_req_pair fail\n");
++ return -1;
++ }
++ config.pair = asrc_ssi_data.asrc_index;
++ config.channel_num = channel;
++ config.input_sample_rate = asrc_input_rate;
++ config.output_sample_rate = asrc_ssi_data.output_sample_rate;
++ config.inclk = INCLK_NONE;
++ config.word_width = 32;
++ plat = priv->pdev->dev.platform_data;
++ if (plat->src_port == 1)
++ config.outclk = OUTCLK_SSI1_TX;
++ else
++ config.outclk = OUTCLK_SSI2_TX;
++ retVal = asrc_config_pair(&config);
++ if (retVal < 0) {
++ pr_err("Fail to config asrc\n");
++ asrc_release_pair(asrc_ssi_data.asrc_index);
++ return retVal;
++ }
++ rate = asrc_ssi_data.output_sample_rate;
++ pcm_data->asrc_index = asrc_ssi_data.asrc_index;
++ pcm_data->asrc_enable = 1;
++ }
++#endif
++
++ snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, priv->sysclk, 0);
++ snd_soc_dai_set_sysclk(codec_dai, SGTL5000_LRCLK, rate, 0);
++
++#if SGTL5000_SSI_MASTER
++ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBM_CFM;
++#else
++ dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
++ SND_SOC_DAIFMT_CBS_CFS;
++#endif
++
++ ssi_mode->flags = IMX_SSI_SYN;
++ if (channels == 1)
++ ssi_mode->flags &= ~IMX_SSI_NET;
++ else
++ ssi_mode->flags |= IMX_SSI_NET;
++
++ /* set codec DAI configuration */
++ ret = snd_soc_dai_set_fmt(codec_dai, dai_format);
++ if (ret < 0)
++ return ret;
++
++ /* set i.MX active slot mask */
++ switch (channels) {
++ case 2:
++ snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0);
++ break;
++ case 1:
++ snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffe, 0xffffffe, 1, 0);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ /* set cpu DAI configuration */
++ ret = snd_soc_dai_set_fmt(cpu_dai, dai_format);
++ if (ret < 0)
++ return ret;
++
++ /* set the SSI system clock as input (unused) */
++ snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, SND_SOC_CLOCK_IN);
++
++ return 0;
++}
++
++static int imx_3stack_startup(struct snd_pcm_substream *substream)
++{
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ if (asrc_ssi_data.output_sample_rate != 0) {
++ struct snd_soc_pcm_runtime *rtd =
++ substream->private_data;
++ struct snd_soc_dai_link *pcm_link = rtd->dai;
++ struct snd_soc_dai *cpu_dai = pcm_link->cpu_dai;
++ struct snd_soc_dai *codec_dai = pcm_link->codec_dai;
++ asrc_ssi_data.cpu_dai_rates = cpu_dai->playback.rates;
++ asrc_ssi_data.codec_dai_rates =
++ codec_dai->playback.rates;
++ cpu_dai->playback.rates =
++ SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT;
++ codec_dai->playback.rates =
++ SNDRV_PCM_RATE_8000_192000 | SNDRV_PCM_RATE_KNOT;
++ }
++ }
++#endif
++ return 0;
++}
++
++static void imx_3stack_shutdown(struct snd_pcm_substream *substream)
++{
++ struct imx_3stack_priv *priv = &card_priv;
++
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
++ if (asrc_ssi_data.output_sample_rate != 0) {
++ struct snd_soc_pcm_runtime *rtd =
++ substream->private_data;
++ struct snd_soc_dai_link *pcm_link = rtd->dai;
++ struct snd_soc_dai *cpu_dai = pcm_link->cpu_dai;
++ struct snd_soc_dai *codec_dai = pcm_link->codec_dai;
++ codec_dai->playback.rates =
++ asrc_ssi_data.codec_dai_rates;
++ cpu_dai->playback.rates = asrc_ssi_data.cpu_dai_rates;
++ asrc_release_pair(asrc_ssi_data.asrc_index);
++ }
++ }
++#endif
++
++ priv->hw = 0;
++}
++
++/*
++ * imx_3stack SGTL5000 audio DAI opserations.
++ */
++static struct snd_soc_ops imx_3stack_ops = {
++ .startup = imx_3stack_startup,
++ .shutdown = imx_3stack_shutdown,
++ .hw_params = imx_3stack_audio_hw_params,
++};
++
++/* imx_3stack machine connections to the codec pins */
++static const struct snd_soc_dapm_route audio_map[] = {
++
++ /* Mic Jack --> MIC_IN (with automatic bias) */
++ {"MIC_IN", NULL, "Mic Jack"},
++
++ /* Line in Jack --> LINE_IN */
++ {"LINE_IN", NULL, "Line In Jack"},
++
++ /* HP_OUT --> Headphone Jack */
++ {"Headphone Jack", NULL, "HP_OUT"},
++
++ /* LINE_OUT --> Ext Speaker */
++ {"Ext Spk", NULL, "LINE_OUT"},
++};
++
++static int sgtl5000_jack_func;
++static int sgtl5000_spk_func;
++static int sgtl5000_line_in_func;
++
++static void headphone_detect_handler(struct work_struct *work)
++{
++ struct imx_3stack_priv *priv = &card_priv;
++ struct platform_device *pdev = priv->pdev;
++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
++ int hp_status;
++
++ sysfs_notify(&pdev->dev.kobj, NULL, "headphone");
++ hp_status = plat->hp_status();
++ if (hp_status)
++ set_irq_type(plat->hp_irq, IRQ_TYPE_EDGE_FALLING);
++ else
++ set_irq_type(plat->hp_irq, IRQ_TYPE_EDGE_RISING);
++ enable_irq(plat->hp_irq);
++}
++
++static DECLARE_DELAYED_WORK(hp_event, headphone_detect_handler);
++
++static irqreturn_t imx_headphone_detect_handler(int irq, void *data)
++{
++ disable_irq_nosync(irq);
++ schedule_delayed_work(&hp_event, msecs_to_jiffies(200));
++ return IRQ_HANDLED;
++}
++
++static ssize_t show_headphone(struct device_driver *dev, char *buf)
++{
++ struct imx_3stack_priv *priv = &card_priv;
++ struct platform_device *pdev = priv->pdev;
++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
++ u16 hp_status;
++
++ /* determine whether hp is plugged in */
++ hp_status = plat->hp_status();
++
++ if (hp_status == 0)
++ strcpy(buf, "speaker\n");
++ else
++ strcpy(buf, "headphone\n");
++
++ return strlen(buf);
++}
++
++static DRIVER_ATTR(headphone, S_IRUGO | S_IWUSR, show_headphone, NULL);
++
++static const char *jack_function[] = { "off", "on"};
++
++static const char *spk_function[] = { "off", "on" };
++
++static const char *line_in_function[] = { "off", "on" };
++
++static const struct soc_enum sgtl5000_enum[] = {
++ SOC_ENUM_SINGLE_EXT(2, jack_function),
++ SOC_ENUM_SINGLE_EXT(2, spk_function),
++ SOC_ENUM_SINGLE_EXT(2, line_in_function),
++};
++
++static int sgtl5000_get_jack(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.enumerated.item[0] = sgtl5000_jack_func;
++ return 0;
++}
++
++static int sgtl5000_set_jack(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (sgtl5000_jack_func == ucontrol->value.enumerated.item[0])
++ return 0;
++
++ sgtl5000_jack_func = ucontrol->value.enumerated.item[0];
++ if (sgtl5000_jack_func)
++ snd_soc_dapm_enable_pin(codec, "Headphone Jack");
++ else
++ snd_soc_dapm_disable_pin(codec, "Headphone Jack");
++
++ snd_soc_dapm_sync(codec);
++ return 1;
++}
++
++static int sgtl5000_get_spk(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.enumerated.item[0] = sgtl5000_spk_func;
++ return 0;
++}
++
++static int sgtl5000_set_spk(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (sgtl5000_spk_func == ucontrol->value.enumerated.item[0])
++ return 0;
++
++ sgtl5000_spk_func = ucontrol->value.enumerated.item[0];
++ if (sgtl5000_spk_func)
++ snd_soc_dapm_enable_pin(codec, "Ext Spk");
++ else
++ snd_soc_dapm_disable_pin(codec, "Ext Spk");
++
++ snd_soc_dapm_sync(codec);
++ return 1;
++}
++
++static int sgtl5000_get_line_in(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.enumerated.item[0] = sgtl5000_line_in_func;
++ return 0;
++}
++
++static int sgtl5000_set_line_in(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
++
++ if (sgtl5000_line_in_func == ucontrol->value.enumerated.item[0])
++ return 0;
++
++ sgtl5000_line_in_func = ucontrol->value.enumerated.item[0];
++ if (sgtl5000_line_in_func)
++ snd_soc_dapm_enable_pin(codec, "Line In Jack");
++ else
++ snd_soc_dapm_disable_pin(codec, "Line In Jack");
++
++ snd_soc_dapm_sync(codec);
++ return 1;
++}
++
++static int spk_amp_event(struct snd_soc_dapm_widget *w,
++ struct snd_kcontrol *kcontrol, int event)
++{
++ struct imx_3stack_priv *priv = &card_priv;
++ struct platform_device *pdev = priv->pdev;
++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
++
++ if (plat->amp_enable == NULL)
++ return 0;
++
++ if (SND_SOC_DAPM_EVENT_ON(event))
++ plat->amp_enable(1);
++ else
++ plat->amp_enable(0);
++
++ return 0;
++}
++
++/* imx_3stack card dapm widgets */
++static const struct snd_soc_dapm_widget imx_3stack_dapm_widgets[] = {
++ SND_SOC_DAPM_MIC("Mic Jack", NULL),
++ SND_SOC_DAPM_LINE("Line In Jack", NULL),
++ SND_SOC_DAPM_SPK("Ext Spk", spk_amp_event),
++ SND_SOC_DAPM_HP("Headphone Jack", NULL),
++};
++
++static const struct snd_kcontrol_new sgtl5000_machine_controls[] = {
++ SOC_ENUM_EXT("Jack Function", sgtl5000_enum[0], sgtl5000_get_jack,
++ sgtl5000_set_jack),
++ SOC_ENUM_EXT("Speaker Function", sgtl5000_enum[1], sgtl5000_get_spk,
++ sgtl5000_set_spk),
++ SOC_ENUM_EXT("Line In Function", sgtl5000_enum[1], sgtl5000_get_line_in,
++ sgtl5000_set_line_in),
++};
++
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++static int asrc_func;
++
++static const char *asrc_function[] =
++ { "disable", "32KHz", "44.1KHz", "48KHz", "96KHz" };
++
++static const struct soc_enum asrc_enum[] = {
++ SOC_ENUM_SINGLE_EXT(5, asrc_function),
++};
++
++static int asrc_get_rate(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ ucontrol->value.enumerated.item[0] = asrc_func;
++ return 0;
++}
++
++static int asrc_set_rate(struct snd_kcontrol *kcontrol,
++ struct snd_ctl_elem_value *ucontrol)
++{
++ if (asrc_func == ucontrol->value.enumerated.item[0])
++ return 0;
++
++ asrc_func = ucontrol->value.enumerated.item[0];
++ asrc_ssi_data.output_sample_rate = sgtl5000_rates[asrc_func];
++
++ return 1;
++}
++
++static const struct snd_kcontrol_new asrc_controls[] = {
++ SOC_ENUM_EXT("ASRC", asrc_enum[0], asrc_get_rate,
++ asrc_set_rate),
++};
++#endif
++
++static int imx_3stack_sgtl5000_init(struct snd_soc_codec *codec)
++{
++ int i, ret;
++
++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE)
++ for (i = 0; i < ARRAY_SIZE(asrc_controls); i++) {
++ ret = snd_ctl_add(codec->card,
++ snd_soc_cnew(&asrc_controls[i], codec, NULL));
++ if (ret < 0)
++ return ret;
++ }
++ asrc_ssi_data.output_sample_rate = sgtl5000_rates[asrc_func];
++#endif
++
++ /* Add imx_3stack specific controls */
++ for (i = 0; i < ARRAY_SIZE(sgtl5000_machine_controls); i++) {
++ ret = snd_ctl_add(codec->card,
++ snd_soc_cnew(&sgtl5000_machine_controls[i],
++ codec, NULL));
++ if (ret < 0)
++ return ret;
++ }
++
++ /* Add imx_3stack specific widgets */
++ snd_soc_dapm_new_controls(codec, imx_3stack_dapm_widgets,
++ ARRAY_SIZE(imx_3stack_dapm_widgets));
++
++ /* Set up imx_3stack specific audio path audio_map */
++ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
++
++ snd_soc_dapm_disable_pin(codec, "Line In Jack");
++
++ snd_soc_dapm_sync(codec);
++
++ return 0;
++}
++
++/* imx_3stack digital audio interface glue - connects codec <--> CPU */
++static struct snd_soc_dai_link imx_3stack_dai = {
++ .name = "SGTL5000",
++ .stream_name = "SGTL5000",
++ .codec_dai = &sgtl5000_dai,
++ .init = imx_3stack_sgtl5000_init,
++ .ops = &imx_3stack_ops,
++};
++
++static int imx_3stack_card_remove(struct platform_device *pdev)
++{
++ struct imx_3stack_priv *priv = &card_priv;
++ struct mxc_audio_platform_data *plat;
++ if (priv->pdev) {
++ plat = priv->pdev->dev.platform_data;
++ if (plat->finit)
++ plat->finit();
++ }
++
++ return 0;
++}
++
++static struct snd_soc_card snd_soc_card_imx_3stack = {
++ .name = "imx-3stack",
++ .platform = &imx_soc_platform,
++ .dai_link = &imx_3stack_dai,
++ .num_links = 1,
++ .remove = imx_3stack_card_remove,
++};
++
++static struct snd_soc_device imx_3stack_snd_devdata = {
++ .card = &snd_soc_card_imx_3stack,
++ .codec_dev = &soc_codec_dev_sgtl5000,
++};
++
++static int __devinit imx_3stack_sgtl5000_probe(struct platform_device *pdev)
++{
++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
++ struct imx_3stack_priv *priv = &card_priv;
++ struct snd_soc_dai *sgtl5000_cpu_dai;
++ int ret = 0;
++
++ priv->pdev = pdev;
++
++ //gpio_activate_audio_ports();
++
++// if (plat->src_port == 2) // MASU S1
++// sgtl5000_cpu_dai = &imx_ssi_dai[2]; // MASU S1
++// else // MASU S1
++// sgtl5000_cpu_dai = &imx_ssi_dai[0]; // MASU S1
++sgtl5000_cpu_dai = &imx_ssi_pcm_dai[0]; // MASU S1
++
++ imx_3stack_dai.cpu_dai = sgtl5000_cpu_dai;
++
++ ret = driver_create_file(pdev->dev.driver, &driver_attr_headphone);
++ if (ret < 0) {
++ pr_err("%s:failed to create driver_attr_headphone\n", __func__);
++ goto sysfs_err;
++ }
++
++ if (plat->init) {
++ ret = plat->init();
++ if (ret)
++ goto err_plat_init;
++ }
++
++ priv->sysclk = plat->sysclk;
++
++ /* The SGTL5000 has an internal reset that is deasserted 8 SYS_MCLK
++ cycles after all power rails have been brought up. After this time
++ communication can start */
++
++ if ((plat->hp_status != NULL)) {
++ if (plat->hp_status())
++ ret = request_irq(plat->hp_irq,
++ imx_headphone_detect_handler,
++ IRQ_TYPE_EDGE_FALLING, pdev->name, priv);
++ else
++ ret = request_irq(plat->hp_irq,
++ imx_headphone_detect_handler,
++ IRQ_TYPE_EDGE_RISING, pdev->name, priv);
++ if (ret < 0) {
++ pr_err("%s: request irq failed\n", __func__);
++ goto err_card_reg;
++ }
++ sgtl5000_jack_func = 1;
++ } else {
++ sgtl5000_jack_func = 0;
++ }
++ sgtl5000_spk_func = 1;
++ sgtl5000_line_in_func = 0;
++
++ return 0;
++
++err_card_reg:
++ if (plat->finit)
++ plat->finit();
++err_plat_init:
++ driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
++sysfs_err:
++ return ret;
++}
++
++static int imx_3stack_sgtl5000_remove(struct platform_device *pdev)
++{
++ struct mxc_audio_platform_data *plat = pdev->dev.platform_data;
++ struct imx_3stack_priv *priv = &card_priv;
++
++ if (plat->hp_status != NULL)
++ free_irq(plat->hp_irq, priv);
++
++ if (plat->finit)
++ plat->finit();
++
++ driver_remove_file(pdev->dev.driver, &driver_attr_headphone);
++
++ return 0;
++}
++
++static struct platform_driver imx_3stack_sgtl5000_audio_driver = {
++ .probe = imx_3stack_sgtl5000_probe,
++ .remove = imx_3stack_sgtl5000_remove,
++ .driver = {
++ .name = "imx-3stack-sgtl5000",
++ },
++};
++
++static struct platform_device *imx_3stack_snd_device;
++
++static int __init imx_3stack_init(void)
++{
++ int ret;
++
++ ret = platform_driver_register(&imx_3stack_sgtl5000_audio_driver);
++ if (ret)
++ return -ENOMEM;
++
++ imx_3stack_snd_device = platform_device_alloc("soc-audio", 2);
++ if (!imx_3stack_snd_device)
++ return -ENOMEM;
++
++ platform_set_drvdata(imx_3stack_snd_device, &imx_3stack_snd_devdata);
++ imx_3stack_snd_devdata.dev = &imx_3stack_snd_device->dev;
++ ret = platform_device_add(imx_3stack_snd_device);
++
++ if (ret)
++ platform_device_put(imx_3stack_snd_device);
++
++ return ret;
++}
++
++static void __exit imx_3stack_exit(void)
++{
++ platform_driver_unregister(&imx_3stack_sgtl5000_audio_driver);
++ platform_device_unregister(imx_3stack_snd_device);
++}
++
++module_init(imx_3stack_init);
++module_exit(imx_3stack_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("SGTL5000 Driver for i.MX 3STACK");
++MODULE_LICENSE("GPL");
+diff -urN linux.35.old/sound/soc/imx/imx-pcm-fiq.c linux.35.new/sound/soc/imx/imx-pcm-fiq.c
+--- linux.35.old/sound/soc/imx/imx-pcm-fiq.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/imx/imx-pcm-fiq.c 2010-12-03 09:51:55.496348495 +0100
+@@ -192,6 +192,8 @@
+ int ret;
+
+ iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
++ if (iprtd == NULL)
++ return -ENOMEM;
+ runtime->private_data = iprtd;
+
+ iprtd->substream = substream;
+@@ -202,8 +204,10 @@
+
+ ret = snd_pcm_hw_constraint_integer(substream->runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+- if (ret < 0)
++ if (ret < 0) {
++ kfree(iprtd);
+ return ret;
++ }
+
+ snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
+ return 0;
+diff -urN linux.35.old/sound/soc/imx/imx-ssi.c linux.35.new/sound/soc/imx/imx-ssi.c
+--- linux.35.old/sound/soc/imx/imx-ssi.c 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/imx/imx-ssi.c 2010-12-03 09:51:55.496348495 +0100
+@@ -23,7 +23,7 @@
+ * between pcm data and GPIO status data changes. Our FIQ handler is not
+ * able to handle this, hence this driver only works with 48000Hz sampling
+ * rate.
+- * Reading and writing AC97 registers is another challange. The core
++ * Reading and writing AC97 registers is another challenge. The core
+ * provides us status bits when the read register is updated with *another*
+ * value. When we read the same register two times (and the register still
+ * contains the same value) these status bits are not set. We work
+@@ -83,8 +83,6 @@
+ /*
+ * SSI DAI format configuration.
+ * Should only be called when port is inactive (i.e. SSIEN = 0).
+- * Note: We don't use the I2S modes but instead manually configure the
+- * SSI for I2S because the I2S mode is only a register preset.
+ */
+ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
+ {
+@@ -99,6 +97,10 @@
+ /* data on rising edge of bclk, frame low 1clk before data */
+ strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
+ scr |= SSI_SCR_NET;
++ if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
++ scr &= ~SSI_I2S_MODE_MASK;
++ scr |= SSI_SCR_I2S_MODE_SLAVE;
++ }
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ /* data on rising edge of bclk, frame high with data */
+@@ -143,6 +145,11 @@
+
+ strcr |= SSI_STCR_TFEN0;
+
++ if (ssi->flags & IMX_SSI_NET)
++ scr |= SSI_SCR_NET;
++ if (ssi->flags & IMX_SSI_SYN)
++ scr |= SSI_SCR_SYN;
++
+ writel(strcr, ssi->base + SSI_STCR);
+ writel(strcr, ssi->base + SSI_SRCR);
+ writel(scr, ssi->base + SSI_SCR);
+diff -urN linux.35.old/sound/soc/imx/Kconfig linux.35.new/sound/soc/imx/Kconfig
+--- linux.35.old/sound/soc/imx/Kconfig 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/imx/Kconfig 2010-12-03 09:51:55.496348495 +0100
+@@ -1,4 +1,4 @@
+-config SND_IMX_SOC
++menuconfig SND_IMX_SOC
+ tristate "SoC Audio for Freescale i.MX CPUs"
+ depends on ARCH_MXC
+ select SND_PCM
+@@ -8,14 +8,12 @@
+ Say Y or M if you want to add support for codecs attached to
+ the i.MX SSI interface.
+
+-config SND_MXC_SOC_SSI
+- tristate
++if SND_IMX_SOC
+
+ config SND_MXC_SOC_WM1133_EV1
+ tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
+- depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
++ depends on MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
+ select SND_SOC_WM8350
+- select SND_MXC_SOC_SSI
+ help
+ Enable support for audio on the i.MX31ADS with the WM1133-EV1
+ PMIC board with WM8835x fitted.
+@@ -23,8 +21,16 @@
+ config SND_SOC_PHYCORE_AC97
+ tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+ depends on MACH_PCM043 || MACH_PCA100
+- select SND_MXC_SOC_SSI
+ select SND_SOC_WM9712
+ help
+ Say Y if you want to add support for SoC audio on Phytec phyCORE
+ and phyCARD boards in AC97 mode
++
++config SND_SOC_IMX_3STACK_SGTL5000
++ tristate "SoC Audio support for IMX - SGTL5000"
++ select SND_SOC_SGTL5000
++ help
++ Say Y if you want to add support for SoC audio on IMX 3STACK
++ with the SGTL5000.
++
++endif # SND_IMX_SOC
+diff -urN linux.35.old/sound/soc/imx/Makefile linux.35.new/sound/soc/imx/Makefile
+--- linux.35.old/sound/soc/imx/Makefile 2010-08-02 00:11:14.000000000 +0200
++++ linux.35.new/sound/soc/imx/Makefile 2010-12-03 09:51:55.496348495 +0100
+@@ -8,8 +8,10 @@
+ obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
+
+ # i.MX Machine Support
++snd-soc-imx-3stack-sgtl5000-objs := imx-3stack-sgtl5000.o
+ snd-soc-phycore-ac97-objs := phycore-ac97.o
+ snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+
++obj-$(CONFIG_SND_SOC_IMX_3STACK_SGTL5000) += snd-soc-imx-3stack-sgtl5000.o
+ obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
+ obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
--
1.7.0.4
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] linux: vmx25 module (i.mx25) kernel patches * defconfig - default kernel config for vmx25 * linux-patch - add partial support for vmx25 baseboard pheripherals Signed-off-by: sujak.marek <sujak.marek@gmail.com>
2011-01-28 9:19 [PATCH] linux: vmx25 module (i.mx25) kernel patches * defconfig - default kernel config for vmx25 * linux-patch - add partial support for vmx25 baseboard pheripherals Signed-off-by: sujak.marek <sujak.marek@gmail.com> sujak.marek
@ 2011-01-28 11:52 ` Petr Štetiar
2011-01-28 12:16 ` Marek Sujak
0 siblings, 1 reply; 3+ messages in thread
From: Petr Štetiar @ 2011-01-28 11:52 UTC (permalink / raw)
To: openembedded-devel
Hi,
it looks like, that most of your patches got malformed somewhere in the
transit or you've forget to add newline after the first line in your git
commit message, so the description of the commit is now part of the
subject[1].
1. http://comments.gmane.org/gmane.comp.handhelds.openembedded/41958
-- ynezz
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] linux: vmx25 module (i.mx25) kernel patches * defconfig - default kernel config for vmx25 * linux-patch - add partial support for vmx25 baseboard pheripherals Signed-off-by: sujak.marek <sujak.marek@gmail.com>
2011-01-28 11:52 ` Petr Štetiar
@ 2011-01-28 12:16 ` Marek Sujak
0 siblings, 0 replies; 3+ messages in thread
From: Marek Sujak @ 2011-01-28 12:16 UTC (permalink / raw)
To: openembedded-devel
Hi,
Thank you, I think that now is much more clear to me how to send it. I will
try to re-commit this patch.
Best regards,
masu
On Fri, Jan 28, 2011 at 12:52 PM, Petr Štetiar <ynezz@true.cz> wrote:
> Hi,
>
> it looks like, that most of your patches got malformed somewhere in the
> transit or you've forget to add newline after the first line in your git
> commit message, so the description of the commit is now part of the
> subject[1].
>
> 1. http://comments.gmane.org/gmane.comp.handhelds.openembedded/41958
>
> -- ynezz
>
> _______________________________________________
> Openembedded-devel mailing list
> Openembedded-devel@lists.openembedded.org
> http://lists.linuxtogo.org/cgi-bin/mailman/listinfo/openembedded-devel
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2011-01-28 12:17 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-28 9:19 [PATCH] linux: vmx25 module (i.mx25) kernel patches * defconfig - default kernel config for vmx25 * linux-patch - add partial support for vmx25 baseboard pheripherals Signed-off-by: sujak.marek <sujak.marek@gmail.com> sujak.marek
2011-01-28 11:52 ` Petr Štetiar
2011-01-28 12:16 ` Marek Sujak
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.