aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch')
-rw-r--r--recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch28459
1 files changed, 28459 insertions, 0 deletions
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 0000000000..edbde2da8b
--- /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)&param);
++
++ 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)&param);
++
++ /* 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) 213*1000 > 222,
++ * (2) host->timeout_clk < 216
++ * =>
++ * (1) / (2) > 26
++ */
++ 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(&regs->mcr);
++ reg &= ~FLEXCAN_MCR_MDIS;
++ writel(reg, &regs->mcr);
++
++ udelay(10);
++}
++
++static inline void flexcan_chip_disable(struct flexcan_priv *priv)
++{
++ struct flexcan_regs __iomem *regs = priv->base;
++ u32 reg;
++
++ reg = readl(&regs->mcr);
++ reg |= FLEXCAN_MCR_MDIS;
++ writel(reg, &regs->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(&regs->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, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[0]);
++ }
++ if (cf->can_dlc > 3) {
++ u32 data = be32_to_cpup((__be32 *)&cf->data[4]);
++ writel(data, &regs->cantxfg[FLEXCAN_TX_BUF_ID].data[1]);
++ }
++
++ writel(can_id, &regs->cantxfg[FLEXCAN_TX_BUF_ID].can_id);
++ writel(ctrl, &regs->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 = &regs->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, &regs->iflag1);
++ readl(&regs->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(&regs->esr) | priv->reg_esr;
++
++ /* handle state changes */
++ work_done += flexcan_poll_state(dev, reg_esr);
++
++ /* handle RX-FIFO */
++ reg_iflag1 = readl(&regs->iflag1);
++ while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE &&
++ work_done < quota) {
++ work_done += flexcan_read_frame(dev);
++ reg_iflag1 = readl(&regs->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, &regs->imask1);
++ writel(priv->reg_ctrl_default, &regs->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(&regs->iflag1);
++ reg_esr = readl(&regs->esr);
++ writel(FLEXCAN_ESR_ERR_INT, &regs->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,
++ &regs->imask1);
++ writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL,
++ &regs->ctrl);
++ napi_schedule(&priv->napi);
++ }
++
++ /* FIFO overflow */
++ if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) {
++ writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, &regs->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), &regs->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(&regs->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, &regs->ctrl);
++
++ /* print chip status */
++ dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__,
++ readl(&regs->mcr), readl(&regs->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, &regs->mcr);
++ udelay(10);
++
++ reg_mcr = readl(&regs->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(&regs->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, &regs->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(&regs->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, &regs->ctrl);
++
++ for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) {
++ writel(0, &regs->cantxfg[i].can_ctrl);
++ writel(0, &regs->cantxfg[i].can_id);
++ writel(0, &regs->cantxfg[i].data[0]);
++ writel(0, &regs->cantxfg[i].data[1]);
++
++ /* put MB into rx queue */
++ writel(FLEXCAN_MB_CNT_CODE(0x4), &regs->cantxfg[i].can_ctrl);
++ }
++
++ /* acceptance mask/acceptance code (accept everything) */
++ writel(0x0, &regs->rxgmask);
++ writel(0x0, &regs->rx14mask);
++ writel(0x0, &regs->rx15mask);
++
++ flexcan_transceiver_switch(priv, 1);
++
++ /* synchronize with the can bus */
++ reg_mcr = readl(&regs->mcr);
++ reg_mcr &= ~FLEXCAN_MCR_HALT;
++ writel(reg_mcr, &regs->mcr);
++
++ priv->can.state = CAN_STATE_ERROR_ACTIVE;
++
++ /* enable FIFO interrupts */
++ writel(FLEXCAN_IFLAG_DEFAULT, &regs->imask1);
++
++ /* print chip status */
++ dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n",
++ __func__, readl(&regs->mcr), readl(&regs->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, &regs->imask1);
++
++ /* Disable + halt module */
++ reg = readl(&regs->mcr);
++ reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT;
++ writel(reg, &regs->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(&regs->ctrl);
++ reg |= FLEXCAN_CTRL_CLK_SRC;
++ writel(reg, &regs->ctrl);
++
++ flexcan_chip_enable(priv);
++
++ /* set freeze, halt and activate FIFO, restrict register access */
++ reg = readl(&regs->mcr);
++ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT |
++ FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV;
++ writel(reg, &regs->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(&regs->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