From e03b29400325613a8f48a802839fdebe920bb23a Mon Sep 17 00:00:00 2001 From: Marek Sujak Date: Fri, 28 Jan 2011 14:54:50 +0100 Subject: kernel: added support for vmx25 into recipe 2.6.35 kernel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * modified recipe linux_2.6.35.bb * added kernel-2.6.35 defconfig for vmx25 * added kernel-2.6.35 patch for vmx25 ** Most of significant pheripherals was tested on (x11-image, qt4e image) ** ethernet -> ok ** video -> 640x480, 800x480, 800x600 ** sd -> ok ** audio -> ok Signed-off-by: Marek Sujak Signed-off-by: Eric BĂ©nard --- recipes/linux/linux-2.6.35/vmx25/defconfig | 1771 ++ .../vmx25/linux-2.6.35-vmx25-20110112.patch | 28459 +++++++++++++++++++ recipes/linux/linux_2.6.35.bb | 3 + 3 files changed, 30233 insertions(+) create mode 100644 recipes/linux/linux-2.6.35/vmx25/defconfig create mode 100644 recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch diff --git a/recipes/linux/linux-2.6.35/vmx25/defconfig b/recipes/linux/linux-2.6.35/vmx25/defconfig new file mode 100644 index 0000000000..cbd23c5c18 --- /dev/null +++ b/recipes/linux/linux-2.6.35/vmx25/defconfig @@ -0,0 +1,1771 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.35 +# Thu Jan 27 12:12:40 2011 +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +CONFIG_GENERIC_TIME=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y +CONFIG_VECTORS_BASE=0xffff0000 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_CONSTRUCTORS=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +CONFIG_KERNEL_GZIP=y +# CONFIG_KERNEL_BZIP2 is not set +# CONFIG_KERNEL_LZMA is not set +# CONFIG_KERNEL_LZO is not set +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +CONFIG_POSIX_MQUEUE=y +CONFIG_POSIX_MQUEUE_SYSCTL=y +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set + +# +# RCU Subsystem +# +# CONFIG_TREE_RCU is not set +# CONFIG_TREE_PREEMPT_RCU is not set +CONFIG_TINY_RCU=y +# CONFIG_TREE_RCU_TRACE is not set +# CONFIG_IKCONFIG is not set +CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_CGROUPS is not set +# CONFIG_SYSFS_DEPRECATED_V2 is not set +# CONFIG_RELAY is not set +# CONFIG_NAMESPACES is not set +# CONFIG_BLK_DEV_INITRD is not set +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +CONFIG_SYSCTL_SYSCALL=y +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +# CONFIG_AIO is not set +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +# CONFIG_VM_EVENT_COUNTERS is not set +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +# CONFIG_SLUB is not set +CONFIG_SLOB=y +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_CLK=y + +# +# GCOV-based kernel profiling +# +# CONFIG_SLOW_WORK is not set +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +# CONFIG_MODULES is not set +CONFIG_BLOCK=y +# CONFIG_LBDAF is not set +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_AAEC2000 is not set +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +CONFIG_ARCH_MXC=y +# CONFIG_ARCH_STMP3XXX is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_NS9XXX is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P6440 is not set +# CONFIG_ARCH_S5P6442 is not set +# CONFIG_ARCH_S5PC100 is not set +# CONFIG_ARCH_S5PV210 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_LH7A40X is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +CONFIG_IMX_HAVE_PLATFORM_FLEXCAN=y +CONFIG_IMX_HAVE_PLATFORM_IMX_I2C=y +CONFIG_IMX_HAVE_PLATFORM_IMX_UART=y +CONFIG_IMX_HAVE_PLATFORM_MXC_NAND=y +CONFIG_IMX_HAVE_PLATFORM_SPI_IMX=y + +# +# Freescale MXC Implementations +# +# CONFIG_ARCH_MX1 is not set +# CONFIG_ARCH_MX2 is not set +CONFIG_ARCH_MX25=y +# CONFIG_ARCH_MX3 is not set +# CONFIG_ARCH_MXC91231 is not set +# CONFIG_ARCH_MX5 is not set + +# +# MX25 platforms: +# +# CONFIG_MACH_MX25_3DS is not set +CONFIG_MACH_VMX25=y +CONFIG_MACH_VMX_BASEBOARD=y +# CONFIG_VMX_SD_ON_MODULE is not set +CONFIG_VMX_SD_ON_BOARD=y +CONFIG_MXC_SDMA_API=y +CONFIG_MXC_IRQ_PRIOR=y +CONFIG_MXC_PWM=y +CONFIG_ARCH_MXC_IOMUX_V3=y +CONFIG_ARCH_MXC_AUDMUX_V2=y +CONFIG_MXC_SSI_PORTS=y + +# +# Processor Type +# +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y +CONFIG_CPU_ABRT_EV5TJ=y +CONFIG_CPU_PABRT_LEGACY=y +CONFIG_CPU_CACHE_VIVT=y +CONFIG_CPU_COPY_V4WB=y +CONFIG_CPU_TLB_V4WBI=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_WRITETHROUGH is not set +# CONFIG_CPU_CACHE_ROUND_ROBIN is not set +CONFIG_ARM_L1_CACHE_SHIFT=5 +CONFIG_COMMON_CLKDEV=y + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_HZ=100 +CONFIG_AEABI=y +# CONFIG_OABI_COMPAT is not set +# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set +# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_FLATMEM_MANUAL=y +# CONFIG_DISCONTIGMEM_MANUAL is not set +# CONFIG_SPARSEMEM_MANUAL is not set +CONFIG_FLATMEM=y +CONFIG_FLAT_NODE_MEM_MAP=y +CONFIG_PAGEFLAGS_EXTENDED=y +CONFIG_SPLIT_PTLOCK_CPUS=999999 +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +# CONFIG_KSM is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set + +# +# Boot options +# +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttymxc0,115200 mem=32M@0x80000000 mem=32M@0x90000000 ip=dhcp ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs otg_mode=host video=imxfb:VGA-16@60" +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set + +# +# CPU Power Management +# +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_VFP is not set + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_MISC is not set + +# +# Power management options +# +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_PM_SLEEP=y +CONFIG_SUSPEND_NVS=y +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_APM_EMULATION=y +# CONFIG_PM_RUNTIME is not set +CONFIG_PM_OPS=y +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +# CONFIG_IP_ADVANCED_ROUTER is not set +CONFIG_IP_FIB_HASH=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +# CONFIG_IP_PNP_BOOTP is not set +# CONFIG_IP_PNP_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_PHONET is not set +# CONFIG_IEEE802154 is not set +# CONFIG_NET_SCHED is not set +# CONFIG_DCB is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +CONFIG_CAN=y +CONFIG_CAN_RAW=y +CONFIG_CAN_BCM=y + +# +# CAN Device Drivers +# +# CONFIG_CAN_VCAN is not set +CONFIG_CAN_DEV=y +CONFIG_CAN_CALC_BITTIMING=y +CONFIG_CAN_MCP251X=y +CONFIG_HAVE_CAN_FLEXCAN=y +CONFIG_CAN_FLEXCAN=y +# CONFIG_CAN_SJA1000 is not set + +# +# CAN USB interfaces +# +# CONFIG_CAN_EMS_USB is not set +CONFIG_CAN_DEBUG_DEVICES=y +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set +# CONFIG_WIRELESS is not set +# CONFIG_WIMAX is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +# CONFIG_DEVTMPFS_MOUNT is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +# CONFIG_FW_LOADER is not set +# CONFIG_SYS_HYPERVISOR is not set + +# +# MXC support drivers +# + +# +# i.MX ADC support +# +# CONFIG_IMX_ADC is not set +CONFIG_CONNECTOR=y +CONFIG_PROC_EVENTS=y +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_REDBOOT_PARTS is not set +CONFIG_MTD_CMDLINE_PARTS=y +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +# CONFIG_MTD_BLKDEVS is not set +# CONFIG_MTD_BLOCK is not set +# CONFIG_MTD_BLOCK_RO is not set +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +CONFIG_MTD_M25P80=y +# CONFIG_M25PXX_USE_FAST_READ is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +CONFIG_MTD_NAND_ECC=y +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_SM_COMMON is not set +# CONFIG_MTD_NAND_MUSEUM_IDS is not set +CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018 +# CONFIG_MTD_NAND_GPIO is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_MTD_NAND_DISKONCHIP is not set +# CONFIG_MTD_NAND_NANDSIM is not set +# CONFIG_MTD_NAND_PLATFORM is not set +# CONFIG_MTD_ALAUDA is not set +CONFIG_MTD_NAND_MXC=y +# CONFIG_MTD_ONENAND is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set + +# +# UBI - Unsorted block images +# +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_WL_THRESHOLD=4096 +CONFIG_MTD_UBI_BEB_RESERVE=1 +CONFIG_MTD_UBI_GLUEBI=y + +# +# UBI debugging options +# +# CONFIG_MTD_UBI_DEBUG is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set +# CONFIG_BLK_DEV_DRBD is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_ISL29003 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +CONFIG_EEPROM_AT24=y +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +CONFIG_SCSI_MULTI_LUN=y +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +# CONFIG_SCSI_LOWLEVEL is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +CONFIG_PHYLIB=y + +# +# MII PHY device drivers +# +# CONFIG_MARVELL_PHY is not set +# CONFIG_DAVICOM_PHY is not set +# CONFIG_QSEMI_PHY is not set +# CONFIG_LXT_PHY is not set +# CONFIG_CICADA_PHY is not set +# CONFIG_VITESSE_PHY is not set +CONFIG_SMSC_PHY=y +# CONFIG_BROADCOM_PHY is not set +# CONFIG_ICPLUS_PHY is not set +# CONFIG_REALTEK_PHY is not set +# CONFIG_NATIONAL_PHY is not set +# CONFIG_STE10XP is not set +# CONFIG_LSI_ET1011C_PHY is not set +# CONFIG_MICREL_PHY is not set +# CONFIG_FIXED_PHY is not set +# CONFIG_MDIO_BITBANG is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_SMC91X is not set +# CONFIG_DM9000 is not set +# CONFIG_ENC28J60 is not set +# CONFIG_ETHOC is not set +# CONFIG_SMC911X is not set +# CONFIG_SMSC911X is not set +# CONFIG_DNET is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set +# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set +# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set +# CONFIG_B44 is not set +# CONFIG_KS8842 is not set +# CONFIG_KS8851 is not set +# CONFIG_KS8851_MLL is not set +CONFIG_FEC=y +# CONFIG_FEC2 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set +# CONFIG_WLAN is not set + +# +# Enable WiMAX (Networking options) to see the WiMAX drivers +# + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +CONFIG_INPUT_MOUSEDEV=y +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_APMPOWER is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_CONSOLE_TRANSLATIONS=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_DEVKMEM is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +# CONFIG_SERIAL_MAX3100 is not set +CONFIG_SERIAL_IMX=y +CONFIG_SERIAL_IMX_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_HW_RANDOM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +# CONFIG_I2C_COMPAT is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_HELPER_AUTO is not set +# CONFIG_I2C_SMBUS is not set + +# +# I2C Algorithms +# +# CONFIG_I2C_ALGOBIT is not set +# CONFIG_I2C_ALGOPCF is not set +# CONFIG_I2C_ALGOPCA is not set + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +# CONFIG_I2C_GPIO is not set +CONFIG_I2C_IMX=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +# CONFIG_SPI_GPIO is not set +CONFIG_SPI_IMX=y +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +CONFIG_SPI_SPIDEV=y +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO expanders: +# +# CONFIG_GPIO_IT8761E is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +CONFIG_W1=y +CONFIG_W1_CON=y + +# +# 1-wire Bus Masters +# +# CONFIG_W1_MASTER_DS2490 is not set +# CONFIG_W1_MASTER_DS2482 is not set +CONFIG_W1_MASTER_MXC=y +# CONFIG_W1_MASTER_DS1WM is not set +# CONFIG_W1_MASTER_GPIO is not set + +# +# 1-wire Slaves +# +# CONFIG_W1_SLAVE_THERM is not set +CONFIG_W1_SLAVE_SMEM=y +# CONFIG_W1_SLAVE_DS2431 is not set +# CONFIG_W1_SLAVE_DS2433 is not set +# CONFIG_W1_SLAVE_DS2760 is not set +# CONFIG_W1_SLAVE_BQ27000 is not set +# CONFIG_POWER_SUPPLY is not set +CONFIG_HWMON=y +# CONFIG_HWMON_VID is not set +# CONFIG_HWMON_DEBUG_CHIP is not set + +# +# Native drivers +# +# CONFIG_SENSORS_AD7414 is not set +# CONFIG_SENSORS_AD7418 is not set +# CONFIG_SENSORS_ADCXX is not set +# CONFIG_SENSORS_ADM1021 is not set +# CONFIG_SENSORS_ADM1025 is not set +# CONFIG_SENSORS_ADM1026 is not set +# CONFIG_SENSORS_ADM1029 is not set +# CONFIG_SENSORS_ADM1031 is not set +# CONFIG_SENSORS_ADM9240 is not set +# CONFIG_SENSORS_ADT7411 is not set +# CONFIG_SENSORS_ADT7462 is not set +# CONFIG_SENSORS_ADT7470 is not set +# CONFIG_SENSORS_ADT7475 is not set +# CONFIG_SENSORS_ASC7621 is not set +# CONFIG_SENSORS_ATXP1 is not set +# CONFIG_SENSORS_DS1621 is not set +# CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set +# CONFIG_SENSORS_F75375S is not set +# CONFIG_SENSORS_G760A is not set +# CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM63 is not set +# CONFIG_SENSORS_LM70 is not set +# CONFIG_SENSORS_LM73 is not set +# CONFIG_SENSORS_LM75 is not set +# CONFIG_SENSORS_LM77 is not set +# CONFIG_SENSORS_LM78 is not set +# CONFIG_SENSORS_LM80 is not set +# CONFIG_SENSORS_LM83 is not set +# CONFIG_SENSORS_LM85 is not set +# CONFIG_SENSORS_LM87 is not set +# CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set +# CONFIG_SENSORS_LM93 is not set +# CONFIG_SENSORS_LTC4215 is not set +# CONFIG_SENSORS_LTC4245 is not set +# CONFIG_SENSORS_LM95241 is not set +# CONFIG_SENSORS_MAX1111 is not set +# CONFIG_SENSORS_MAX1619 is not set +# CONFIG_SENSORS_MAX6650 is not set +# CONFIG_SENSORS_PC87360 is not set +# CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_SHT15 is not set +# CONFIG_SENSORS_DME1737 is not set +# CONFIG_SENSORS_EMC1403 is not set +# CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47M192 is not set +# CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_ADS7828 is not set +# CONFIG_SENSORS_ADS7871 is not set +# CONFIG_SENSORS_AMC6821 is not set +# CONFIG_SENSORS_THMC50 is not set +# CONFIG_SENSORS_TMP102 is not set +# CONFIG_SENSORS_TMP401 is not set +# CONFIG_SENSORS_TMP421 is not set +# CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_W83781D is not set +# CONFIG_SENSORS_W83791D is not set +# CONFIG_SENSORS_W83792D is not set +# CONFIG_SENSORS_W83793 is not set +# CONFIG_SENSORS_W83L785TS is not set +# CONFIG_SENSORS_W83L786NG is not set +# CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +# CONFIG_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y + +# +# Watchdog Device Drivers +# +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_MAX63XX_WATCHDOG is not set +CONFIG_IMX2_WDT=y + +# +# USB-based Watchdog Cards +# +# CONFIG_USBPCWATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +# CONFIG_MFD_SUPPORT is not set +# CONFIG_REGULATOR is not set +# CONFIG_MEDIA_SUPPORT is not set + +# +# Graphics support +# +CONFIG_HAVE_FB_IMX=y +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_MODE_HELPERS=y +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +CONFIG_FB_IMX=y +# CONFIG_FB_UVESA is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_MB862XX is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +# CONFIG_BACKLIGHT_ADP8860 is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +# CONFIG_VGA_CONSOLE is not set +CONFIG_DUMMY_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_6x11 is not set +# CONFIG_FONT_7x14 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set +# CONFIG_FONT_MINI_4x6 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_SUN12x22 is not set +# CONFIG_FONT_10x18 is not set +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_LOGO_LINUX_CLUT224=y +CONFIG_SOUND=y +CONFIG_SOUND_OSS_CORE=y +# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +CONFIG_SND_OSSEMUL=y +CONFIG_SND_MIXER_OSS=y +CONFIG_SND_PCM_OSS=y +CONFIG_SND_PCM_OSS_PLUGINS=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SUPPORT_OLD_API=y +# CONFIG_SND_VERBOSE_PROCFS is not set +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +# CONFIG_SND_DRIVERS is not set +# CONFIG_SND_ARM is not set +# CONFIG_SND_SPI is not set +# CONFIG_SND_USB is not set +CONFIG_SND_SOC=y +CONFIG_SND_SOC_AC97_BUS=y +CONFIG_SND_IMX_SOC=y +CONFIG_SND_SOC_IMX_3STACK_SGTL5000=y +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_SGTL5000=y +# CONFIG_SOUND_PRIME is not set +CONFIG_AC97_BUS=y +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_HID_PID is not set +# CONFIG_USB_HIDDEV is not set + +# +# Special HID drivers +# +# CONFIG_HID_3M_PCT is not set +# CONFIG_HID_A4TECH is not set +# CONFIG_HID_APPLE is not set +# CONFIG_HID_BELKIN is not set +# CONFIG_HID_CANDO is not set +# CONFIG_HID_CHERRY is not set +# CONFIG_HID_CHICONY is not set +# CONFIG_HID_PRODIKEYS is not set +# CONFIG_HID_CYPRESS is not set +# CONFIG_HID_DRAGONRISE is not set +# CONFIG_HID_EGALAX is not set +# CONFIG_HID_EZKEY is not set +# CONFIG_HID_KYE is not set +# CONFIG_HID_GYRATION is not set +# CONFIG_HID_TWINHAN is not set +# CONFIG_HID_KENSINGTON is not set +# CONFIG_HID_LOGITECH is not set +# CONFIG_HID_MICROSOFT is not set +# CONFIG_HID_MOSART is not set +# CONFIG_HID_MONTEREY is not set +# CONFIG_HID_NTRIG is not set +# CONFIG_HID_ORTEK is not set +# CONFIG_HID_PANTHERLORD is not set +# CONFIG_HID_PETALYNX is not set +# CONFIG_HID_PICOLCD is not set +# CONFIG_HID_QUANTA is not set +# CONFIG_HID_ROCCAT is not set +# CONFIG_HID_ROCCAT_KONE is not set +# CONFIG_HID_SAMSUNG is not set +# CONFIG_HID_SONY is not set +# CONFIG_HID_STANTUM is not set +# CONFIG_HID_SUNPLUS is not set +# CONFIG_HID_GREENASIA is not set +# CONFIG_HID_SMARTJOYPLUS is not set +# CONFIG_HID_TOPSEED is not set +# CONFIG_HID_THRUSTMASTER is not set +# CONFIG_HID_ZEROPLUS is not set +# CONFIG_HID_ZYDACRON is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +CONFIG_USB_DEBUG=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +CONFIG_USB_DEVICEFS=y +# CONFIG_USB_DEVICE_CLASS is not set +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +CONFIG_USB_MON=y +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +# CONFIG_USB_EHCI_TT_NEWSCHED is not set +CONFIG_USB_EHCI_MXC=y +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set +# CONFIG_USB_GADGET_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +CONFIG_USB_ACM=y +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_ONETOUCH is not set +# CONFIG_USB_STORAGE_KARMA is not set +# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_SISUSBVGA is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_VBUS_DRAW=300 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +CONFIG_USB_GADGET_FSL_USB2=y +CONFIG_USB_FSL_USB2=y +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_PXA25X is not set +# CONFIG_USB_GADGET_R8A66597 is not set +# CONFIG_USB_GADGET_PXA27X is not set +# CONFIG_USB_GADGET_S3C_HSOTG is not set +# CONFIG_USB_GADGET_IMX is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_FSL_QE is not set +# CONFIG_USB_GADGET_CI13XXX is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LANGWELL is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +CONFIG_USB_ETH=y +CONFIG_USB_ETH_RNDIS=y +# CONFIG_USB_ETH_EEM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +CONFIG_USB_OTG_UTILS=y +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +CONFIG_NOP_USB_XCEIV=y +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +# CONFIG_MMC_UNSAFE_RESUME is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +# CONFIG_MMC_MXC is not set +# CONFIG_MMC_SPI is not set +CONFIG_MMC_SDHCI_MXC=y +# CONFIG_MMC_SDHCI_MXC_SELECT2 is not set +# CONFIG_MMC_SDHCI_MXC_PIO_MODE is not set +# CONFIG_MEMSTICK is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y + +# +# LED drivers +# +# CONFIG_LEDS_PCA9532 is not set +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_GPIO_PLATFORM=y +# CONFIG_LEDS_LP3944 is not set +# CONFIG_LEDS_PCA955X is not set +# CONFIG_LEDS_DAC124S085 is not set +# CONFIG_LEDS_PWM is not set +# CONFIG_LEDS_BD2802 is not set +# CONFIG_LEDS_LT3593 is not set +CONFIG_LEDS_TRIGGERS=y + +# +# LED Triggers +# +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y + +# +# iptables trigger is under Netfilter config (LED target) +# +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc1" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +CONFIG_RTC_DRV_DS1307=y +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_MXC is not set +CONFIG_RTC_DRV_IMXDI=y +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +# CONFIG_STAGING is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +CONFIG_EXT3_FS=y +# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +# CONFIG_EXT3_FS_XATTR is not set +CONFIG_EXT4_FS=y +# CONFIG_EXT4_FS_XATTR is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD=y +CONFIG_JBD2=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY=y +CONFIG_INOTIFY_USER=y +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLB_PAGE is not set +CONFIG_CONFIGFS_FS=y +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS2_FS is not set +CONFIG_UBIFS_FS=y +# CONFIG_UBIFS_FS_XATTR is not set +# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set +CONFIG_UBIFS_FS_LZO=y +CONFIG_UBIFS_FS_ZLIB=y +# CONFIG_UBIFS_FS_DEBUG is not set +# CONFIG_LOGFS is not set +# CONFIG_CRAMFS is not set +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +# CONFIG_NFS_V3_ACL is not set +# CONFIG_NFS_V4 is not set +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_RPCSEC_GSS_KRB5 is not set +# CONFIG_RPCSEC_GSS_SPKM3 is not set +# CONFIG_SMB_FS is not set +# CONFIG_CEPH_FS is not set +# CONFIG_CIFS is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-15" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +CONFIG_NLS_CODEPAGE_850=y +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +CONFIG_NLS_CODEPAGE_1250=y +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_ISO8859_2=y +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +CONFIG_NLS_UTF8=y +# CONFIG_DLM is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +CONFIG_DEBUG_BUGVERBOSE=y +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_FRAME_POINTER=y +# CONFIG_LATENCYTOP is not set +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_ARM_UNWIND is not set +CONFIG_DEBUG_USER=y +# CONFIG_OC_ETM is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +# CONFIG_DEFAULT_SECURITY_SELINUX is not set +# CONFIG_DEFAULT_SECURITY_SMACK is not set +# CONFIG_DEFAULT_SECURITY_TOMOYO is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_MANAGER2 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_AUTHENC is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_GHASH is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_TWOFISH is not set + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +CONFIG_CRYPTO_LZO=y + +# +# Random Number Generation +# +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_RATIONAL=y +CONFIG_GENERIC_FIND_LAST_BIT=y +# CONFIG_CRC_CCITT is not set +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +CONFIG_GENERIC_ATOMIC64=y diff --git a/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch b/recipes/linux/linux-2.6.35/vmx25/linux-2.6.35-vmx25-20110112.patch new file mode 100644 index 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 + #include + #include ++#include + +-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 ++ * ++ * This program is free software; you can redistribute it and/or modify it under ++ * the terms of the GNU General Public License version 2 as published by the ++ * Free Software Foundation. ++ */ ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++ ++//#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 + #include + #include +-#include "devices.h" + #include + +-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 ++ * ++ * Based on arch/arm/mach-mx25/karo-tx25.c ++ * Copyright (C) 2009 Lothar Wassmann ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_MTD) || defined(CONFIG_MTD_MODULE) ++#include ++#include ++#include ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#if defined(CONFIG_TOUCHSCREEN_MXC_TSC) || defined(CONFIG_TOUCHSCREEN_MXC_TSC_MODULE) ++#include ++#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: */ ++ .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 +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 ++ * ++ * Based on arch/arm/mach-mx25/stk5-baseboard.c ++ * Copyright (C) 2009 Lothar Wassmann ++ * ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++#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 ++#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 ++#include ++#include ++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 +@@ -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 ++ * ++ * 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 ++ ++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 ++ * ++ * 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 ++ ++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 ++ * ++ * 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 ++ ++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 ++ * ++ * This program is free software; you can redistribute it and/or modify it under ++ * the terms of the GNU General Public License version 2 as published by the ++ * Free Software Foundation. ++ */ ++#include ++#include ++ ++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 + #include ++#include + #include + #include + +@@ -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 +@@ -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 ++ * ++ * 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 ++ * ++ * This program is free software; you can redistribute it and/or modify it under ++ * the terms of the GNU General Public License version 2 as published by the ++ * Free Software Foundation. ++ */ ++#include ++#include ++#include ++ ++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 ++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 ++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 ++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 ++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 ++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 ++#else ++#include ++#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 ++ ++/* ++ * 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 ++ * ++ * 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 ++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 ++#include ++ ++#include ++#include ++ ++/*! ++ * 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 ++ * ++ * 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 + + 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 ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#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 ++#include ++#include ++#include ++#endif ++ ++#include ++#include ++ ++/* 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 ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef MCU ++#include ++#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 ++#include ++ ++/* **************************************************************************** ++ * 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 ++#elif OS == LINUX ++#include ++#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; /* ++ ++/* **************************************************************************** ++ * 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 ++#include ++#include ++#include ++ ++#include ++#include ++ ++#ifdef DEBUG ++#include ++#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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Notes:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Notes:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Notes:\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. ++ * Algorithm:\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. ++ * ++ * Notes:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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 ++ ++#include ++#include ++ ++/** ++ * 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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\n ++ * - Loop doing nothing but checking the I.API global variable to indicate ++ * that the channel has been completed (interrupt from SDMA) ++ * ++ * Notes:\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) ++ * ++ * Algorithm:\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) ++ * ++ * Algorithm: ++ * - Bit numbered "channel" of DspEnStopReg register is cleared ++ * ++ * Notes:\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 ++#include ++ ++#include ++#include ++ ++/* **************************************************************************** ++ * 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. ++ * ++ * Notes\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) ++ * ++ * Algorithm:\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) ++ * ++ * Algorithm: ++ * - Bit numbered "channel" of HostEnStopReg register is cleared ++ * ++ * Notes:\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 ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\n ++ * - Setup BD with appropiate parameters (C0_GETPM) ++ * - Start channel ++ * - Poll for answer ++ * ++ * Notes\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 ++ * ++ * Algorithm:\n ++ * - Setup BD with appropiate parameters (C0_SETPM) ++ * - Start channel ++ * - Poll for answer ++ * ++ * Notes\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 ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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) ++ * ++ * ++ * Algorithm:\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 ++#include ++ ++#include ++#include ++#include ++ ++/* **************************************************************************** ++ * 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. ++ * ++ * Algorithm:\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. ++ * ++ * Algorithm:\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 ++ * ++ * Algorithm:\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 ++#include ++ ++#include ++#include ++ ++/* **************************************************************************** ++ * 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 ++#include ++ ++/** ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#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 ++ ++static void sdma_sleep_channel(int channel) ++{ ++ int ret; ++ ++ DBG(1, "%s: Waiting for channel %d to drain\n", ++ __FUNCTION__, channel); ++ BUG_ON(irqs_disabled()); ++ ++ ret = wait_event_interruptible_timeout(sdma_sleep_queue[channel], ++ iapi_SDMAIntr & (1 << channel), HZ); ++ if (ret == 0 && !(iapi_SDMAIntr & (1 << channel))) { ++ DBG(-1, "%s: Wait for channel %d done timed out: %08lx\n", ++ __FUNCTION__, channel, iapi_SDMAIntr); ++ } else if (ret < 0) { ++ DBG(-1, "%s: Wait for channel %d aborted: %08lx, %d\n", ++ __FUNCTION__, channel, iapi_SDMAIntr, ret); ++ } else { ++ DBG(1, "%s: Wait for channel %d done finished after %u ticks: %08lx\n", ++ __FUNCTION__, channel, HZ - ret, iapi_SDMAIntr); ++ } ++} ++ ++/* ++ * Wake up channel from sleep ++ * ++ * @param channel channel number ++ */ ++static void sdma_wakeup_channel(int channel) ++{ ++ DBG(1, "%s: Waking up channel %d\n", __FUNCTION__, channel); ++ wake_up_interruptible(&sdma_sleep_queue[channel]); ++} ++ ++/* ++ * Sdma interrupt handler routine. ++ * Calls channels callback function ++ * ++ * @param irq the interrupt number ++ * @param dev_id driver private data ++ * @return the function returns \b IRQ_RETVAL(1) - interrupt was handled ++ */ ++static irqreturn_t sdma_int_handler(int irq, void *dev_id) ++{ ++ DBG(2, "%s: IRQ %d\n", __FUNCTION__, irq); ++ IRQ_Handler(); ++ DBG(2, "%s: Done\n", __FUNCTION__); ++ return IRQ_HANDLED; ++} ++ ++/* ++ * I.API channel callback function ++ * ++ * @param cd channel descriptor structure ++ * @param channel_data SDMA struct of the current channel ++ */ ++static void iapi_interrupt_callback(channelDescriptor *cd, ++ sdma_struct *channel_data) ++{ ++ int channel; ++ dma_callback_t callback; ++ void *arg; ++ ++ DBG(2, "%s: cd=%p\n", __FUNCTION__, cd); ++ channel = channel_data->channel; ++ ++ channel_data->running = 0; ++ ++ arg = channel_data->arg; ++ ++ if (arg == NULL) { ++ arg = &channel; ++ } ++ ++ callback = channel_data->callback; ++ ++ if (callback != NULL) { ++ DBG(2, "%s: Calling %p\n", __FUNCTION__, callback); ++ callback(arg); ++ } ++} ++ ++/* ++ * Returns pc of SDMA script according to peripheral and transfer type ++ * ++ * @param peripheral_type peripheral type ++ * @param transfer_type transfer type ++ * ++ * @return PC of SDMA script ++*/ ++static unsigned short sdma_get_pc(sdma_periphT peripheral_type, ++ sdma_transferT transfer_type) ++{ ++ int res = 0; ++ ++ if (peripheral_type == MEMORY) { ++ switch (transfer_type) { ++ case emi_2_int: ++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; ++ break; ++ case emi_2_emi: ++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; ++ break; ++ case int_2_emi: ++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == DSP) { ++ switch (transfer_type) { ++ case emi_2_dsp: ++ res = sdma_script_addrs.mxc_sdma_ap_2_bp_addr; ++ break; ++ case dsp_2_emi: ++ res = sdma_script_addrs.mxc_sdma_bp_2_ap_addr; ++ break; ++ case dsp_2_emi_loop: ++ res = ++ sdma_script_addrs. ++ mxc_sdma_loopback_on_dsp_side_addr; ++ break; ++ case emi_2_dsp_loop: ++ res = ++ sdma_script_addrs.mxc_sdma_mcu_interrupt_only_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == FIRI) { ++ switch (transfer_type) { ++ case per_2_int: ++ res = sdma_script_addrs.mxc_sdma_firi_2_per_addr; ++ break; ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_firi_2_mcu_addr; ++ break; ++ case int_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_firi_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_firi_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == UART) { ++ switch (transfer_type) { ++ case per_2_int: ++ res = sdma_script_addrs.mxc_sdma_uart_2_per_addr; ++ break; ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_uart_2_mcu_addr; ++ break; ++ case int_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_app_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == UART_SP) { ++ switch (transfer_type) { ++ case per_2_int: ++ res = sdma_script_addrs.mxc_sdma_uartsh_2_per_addr; ++ break; ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_uartsh_2_mcu_addr; ++ break; ++ case int_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == ATA) { ++ switch (transfer_type) { ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_ata_2_mcu_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_ata_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == CSPI || peripheral_type == EXT || ++ peripheral_type == SSI) { ++ switch (transfer_type) { ++ case per_2_int: ++ res = sdma_script_addrs.mxc_sdma_app_2_per_addr; ++ break; ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_app_2_mcu_addr; ++ break; ++ case int_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_app_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_app_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == SSI_SP || peripheral_type == MMC || ++ peripheral_type == SDHC || peripheral_type == CSPI_SP || ++ peripheral_type == ESAI || peripheral_type == MSHC_SP) { ++ switch (transfer_type) { ++ case per_2_int: ++ res = sdma_script_addrs.mxc_sdma_shp_2_per_addr; ++ break; ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_shp_2_mcu_addr; ++ break; ++ case int_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_shp_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_shp_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == ASRC) { ++ switch (transfer_type) { ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_asrc_2_mcu_addr; ++ break; ++ case per_2_per: ++ res = sdma_script_addrs.mxc_sdma_per_2_per_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == MSHC) { ++ switch (transfer_type) { ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_mshc_2_mcu_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_mshc_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == CCM) { ++ switch (transfer_type) { ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_dptc_dvfs_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == FIFO_MEMORY) { ++ res = sdma_script_addrs.mxc_sdma_ap_2_ap_fixed_addr; ++ } else if (peripheral_type == SPDIF) { ++ switch (transfer_type) { ++ case per_2_emi: ++ res = sdma_script_addrs.mxc_sdma_spdif_2_mcu_addr; ++ break; ++ case emi_2_per: ++ res = sdma_script_addrs.mxc_sdma_mcu_2_spdif_addr; ++ break; ++ default: ++ res = -EINVAL; ++ } ++ } else if (peripheral_type == IPU_MEMORY) { ++ if (transfer_type == emi_2_per) { ++ res = sdma_script_addrs.mxc_sdma_ext_mem_2_ipu_addr; ++ } else { ++ res = -EINVAL; ++ } ++ } ++ ++ if (res < 0) { ++ printk(KERN_ERR "SDMA script not found\n"); ++ } else { ++ DBG(1, "%s: PC[%d,%d]=%04x\n", __FUNCTION__, ++ peripheral_type, transfer_type, res); ++ } ++ return res; ++ ++} ++ ++static inline int sdma_asrc_set_info(dma_channel_params *p, ++ script_data *pcontext, int eflags) ++{ ++ dma_channel_ext_params *ep = (dma_channel_ext_params *)p; ++ unsigned int wml, tmp, wml1, wml2; ++ struct dma_channel_asrc_info *info = &ep->info.asrc; ++ ++ wml = 0; ++ if (p->transfer_type == per_2_per) { ++ if (!p->ext) ++ return wml; ++ wml1 = p->watermark_level; ++ wml2 = ep->watermark_level2; ++ if (info->channs) { ++ wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << ++ SDMA_ASRC_INFO_N_OFF; ++ if (ep->p2p_dir) ++ wml2 *= info->channs & SDMA_ASRC_INFO_N_MASK; ++ else ++ wml1 *= info->channs & SDMA_ASRC_INFO_N_MASK; ++ } ++ if (info->channs & 1) { ++ if (ep->p2p_dir) ++ wml |= SDMA_ASRC_P2P_INFO_PS; ++ else ++ wml |= SDMA_ASRC_P2P_INFO_PA; ++ } ++ if (wml1 > wml2) { ++ tmp = wml2 & SDMA_ASRC_P2P_INFO_LWML_MASK; ++ wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; ++ tmp = wml1 & SDMA_ASRC_P2P_INFO_HWML_MASK; ++ wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; ++ if (eflags & (1 << 31)) ++ wml |= SDMA_ASRC_P2P_INFO_LWE; ++ if (eflags & (1 << 30)) ++ wml |= SDMA_ASRC_P2P_INFO_HWE; ++ } else { ++ tmp = wml1 & SDMA_ASRC_P2P_INFO_LWML_MASK; ++ wml |= tmp << SDMA_ASRC_P2P_INFO_LWML_OFF; ++ tmp = wml2 & SDMA_ASRC_P2P_INFO_HWML_MASK; ++ wml |= tmp << SDMA_ASRC_P2P_INFO_HWML_OFF; ++ wml |= eflags >> 2; ++ tmp = pcontext->event_mask2; ++ pcontext->event_mask2 = pcontext->event_mask1; ++ pcontext->event_mask1 = tmp; ++ } ++ } else { ++ if (p->ext && info->channs) { ++ wml |= (info->channs & SDMA_ASRC_INFO_N_MASK) << ++ SDMA_ASRC_INFO_N_OFF; ++ tmp = (info->channs * p->watermark_level) & ++ SDMA_ASRC_INFO_WML_MASK; ++ wml |= tmp << SDMA_ASRC_INFO_WML_OFF; ++ } else { ++ tmp = (p->watermark_level & SDMA_ASRC_INFO_WML_MASK); ++ wml |= tmp << SDMA_ASRC_INFO_WML_OFF; ++ } ++ ++ if (p->transfer_type == per_2_emi) ++ wml |= SDMA_ASRC_INFO_TXFR_DIR; ++ ++ if (p->ext && (info->channs & 1)) { ++ if (p->transfer_type == per_2_emi) ++ wml |= SDMA_ASRC_INFO_PS; ++ else ++ wml |= SDMA_ASRC_INFO_PA; ++ } ++ wml |= eflags; ++ } ++ return wml; ++} ++ ++/* ++ * Downloads channel context according to channel parameters ++ * ++ * @param channel channel number ++ * @param p channel parameters ++ */ ++static int sdma_load_context(int channel, dma_channel_params *p) ++{ ++ script_data context; ++ int res; ++ int event1_greater_than_32; ++ int event2_greater_than_32; ++ dma_channel_ext_params *ep = (dma_channel_ext_params *)p; ++ ++ res = 0; ++ ++ memset(&context, 0, sizeof(script_data)); ++ context.load_address = sdma_get_pc(p->peripheral_type, ++ p->transfer_type); ++ ++ if (context.load_address > 0) { ++ if ((p->peripheral_type != MEMORY) && ++ (p->peripheral_type != DSP)) { ++ /* Handle multiple event channels differently */ ++ if (p->event_id2) { ++ if (p->event_id2 < 32) { ++ context.event_mask2 = ++ 0x1 << p->event_id2; ++ event2_greater_than_32 = 0; ++ } else { ++ context.event_mask2 = ++ 0x1 << (p->event_id2 - 32); ++ event2_greater_than_32 = 1 << 31; ++ } ++ if (p->event_id < 32) { ++ context.event_mask1 = ++ 0x1 << p->event_id; ++ event1_greater_than_32 = 0; ++ } else { ++ context.event_mask1 = ++ 0x1 << (p->event_id - 32); ++ event1_greater_than_32 = 1 << 30; ++ } ++ } else { ++ event1_greater_than_32 = 0; ++ event2_greater_than_32 = 0; ++ if (p->event_id < 32) { ++ context.event_mask1 = ++ 0x1 << p->event_id; ++ context.event_mask2 = 0; ++ } else { ++ context.event_mask1 = 0; ++ context.event_mask2 = ++ 0x1 << (p->event_id - 32); ++ } ++ } ++ ++ if (p->ext) ++ context.wml = ep->info_bits; ++ /* Watermark Level */ ++ if (p->peripheral_type == ASRC) { ++ context.wml |= sdma_asrc_set_info(p, ++ &context, ++ event2_greater_than_32 ++ | ++ event1_greater_than_32); ++ } else ++ context.wml |= event2_greater_than_32 | ++ event1_greater_than_32 | p->watermark_level; ++ ++ /* Address */ ++ context.shp_addr = p->per_address; ++ iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_PERIPHADDR, p->per_address); ++ } else { ++ context.wml = M3_BASE_ADDRESS; ++ } ++ ++ sdma_data[channel].transfer_type = p->transfer_type; ++ sdma_data[channel].peripheral_type = p->peripheral_type; ++ sdma_data[channel].watermark_level = p->watermark_level; ++ iapi_AssignScript(sdma_data[channel].cd, &context); ++ } else { ++ res = context.load_address; ++ } ++ ++ return res; ++} ++ ++/* ++ * Setup channel according to parameters. Must be called once after mxc_request_dma() ++ * ++ * @param channel channel number ++ * @param p channel parameters pointer ++ * @return 0 on success, error code on fail ++ */ ++int mxc_dma_setup_channel(int channel, dma_channel_params *p) ++{ ++ int err = 0; ++ int i; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ mxc_dma_stop(channel); ++ ++ for (i = 0; i < sdma_data[channel].bd_number; i++) { ++ iapi_IoCtl(sdma_data[channel].cd, ++ (i << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_STATUS, 0); ++ } ++ ++ DBG(0, "%s: Changing number of BDs for channel %d from %u to %u\n", ++ __FUNCTION__, channel, sdma_data[channel].bd_number, ++ p->bd_number <= 0 ? 1 : p->bd_number); ++ sdma_data[channel].bd_number = (p->bd_number <= 0) ? 1 : p->bd_number; ++ ++ sdma_data[channel].word_size = p->word_size; ++ ++ sdma_data[channel].event_id = p->event_id; ++ sdma_data[channel].event_id2 = p->event_id2; ++ ++ sdma_data[channel].callback = p->callback; ++ ++ sdma_data[channel].arg = p->arg; ++ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_BDNUM, sdma_data[channel].bd_number); ++ if (err < 0) { ++ printk(KERN_ERR "Failed to allocate buffer descriptors: %d\n", ++ err); ++ err = -ENOMEM; ++ goto setup_channel_fail; ++ } ++ ++ if (channel != 0) { ++ switch (p->transfer_type) { ++ case dsp_2_per: ++ break; ++ case emi_2_per: ++ case int_2_per: ++ case per_2_int: ++ case per_2_emi: ++ case per_2_per: ++ /* ++ * Peripheral <------> Memory ++ * evtOvr = 0 dspOvr = 1 ++ */ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_OWNERSHIP, ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ if (err) ++ goto setup_channel_fail; ++ if (p->event_id) { ++ err = iapi_SetChannelEventMapping(p->event_id, ++ 1 << channel); ++ if (err) ++ goto setup_channel_fail; ++ } ++ if (p->event_id2) { ++ err = iapi_SetChannelEventMapping(p->event_id2, ++ 1 << channel); ++ } ++ break; ++ case emi_2_dsp: ++ case int_2_dsp: ++ case dsp_2_int: ++ case dsp_2_emi: ++ case dsp_2_dsp: ++ /* ++ * DSP <-----------> Memory ++ * evtOvr = 1 dspOvr = 0 ++ */ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_OWNERSHIP, ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ break; ++ case emi_2_int: ++ case emi_2_emi: ++ case int_2_int: ++ case int_2_emi: ++ case emi_2_dsp_loop: ++ case dsp_2_emi_loop: ++ /* evtOvr = 1 dspOvr = 1 */ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_OWNERSHIP, ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ break; ++ case per_2_dsp: ++ /* evtOvr = 0 dspOvr = 0 */ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_OWNERSHIP, ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ if (err) ++ goto setup_channel_fail; ++ err = iapi_SetChannelEventMapping(p->event_id, ++ 1 << channel); ++ break; ++ default: ++ break; ++ printk(KERN_ERR "Wrong SDMA transfer type\n"); ++ err = -EINVAL; ++ } ++ if (err) ++ goto setup_channel_fail; ++ ++ err = sdma_load_context(channel, p); ++ if (err) ++ goto setup_channel_fail; ++ ++ err = iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, ++ MXC_SDMA_DEFAULT_PRIORITY); ++ } ++setup_channel_fail: ++ return err; ++} ++EXPORT_SYMBOL(mxc_dma_setup_channel); ++ ++/* ++ * Setup the channel priority. This can be used to change the default priority ++ * for the channel. ++ * ++ * @param channel channel number ++ * @param priority priority to be set for the channel ++ * ++ * @return 0 on success, error code on failure ++ */ ++int mxc_dma_set_channel_priority(unsigned int channel, unsigned int priority) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ if (priority < MXC_SDMA_MIN_PRIORITY ++ || priority > MXC_SDMA_MAX_PRIORITY) { ++ return -EINVAL; ++ } ++ return iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, ++ priority); ++} ++EXPORT_SYMBOL(mxc_dma_set_channel_priority); ++ ++/* ++ * Allocates dma channel. ++ * If channel's value is 0, then the function allocates a free channel ++ * dynamically and sets its value to channel. ++ * Else allocates requested channel if it is free. ++ * If the channel is busy or no free channels (in dynamic allocation) -EBUSY returned. ++ * ++ * @param channel pointer to channel number ++ * @param devicename device name ++ * @return 0 on success, error code on fail ++ */ ++int mxc_request_dma(int *channel, const char *devicename) ++{ ++ int i, res = -EBUSY; ++ ++ if (sdma_base_addr == NULL) ++ return -ENOSYS; ++ ++ if (channel == NULL || *channel < 0 || *channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ down(&sdma_status_mutex); ++ ++ /* Dynamic allocation */ ++ if (*channel == 0) { ++ for (i = MAX_DMA_CHANNELS - 1; i > 0; i--) { ++#ifdef CONFIG_SDMA_IRAM ++ /*TODO:It will be removed after DPTC used UDMA interface */ ++ if (i >= MXC_DMA_CHANNEL_IRAM) ++ continue; ++#endif /* CONFIG_SDMA_IRAM */ ++ if (!sdma_data[i].in_use) { ++ *channel = i; ++ res = 0; ++ break; ++ } ++ } ++ } else { ++ if (sdma_data[*channel].in_use) ++ return -EBUSY; ++ res = 0; ++ } ++ if (res) ++ return res; ++ ++ DBG(1, "%s: Opening channel %d\n", __FUNCTION__, *channel); ++ ++ res = iapi_Open(sdma_data[0].cd, *channel); ++ if (res < 0) { ++ printk(KERN_ERR "Failed iapi_Open channel %d, 0x%x\n", ++ *channel, res); ++ } else { ++ sdma_data[*channel].in_use = 1; ++ strlcpy(sdma_data[*channel].devicename, devicename, ++ sizeof(sdma_data[*channel].devicename)); ++ sdma_data[*channel].cd = CHAD(*channel); ++ ++ iapi_IoCtl(sdma_data[*channel].cd, IAPI_CHANGE_SYNCH, ++ CALLBACK_ISR); ++ iapi_IoCtl(sdma_data[*channel].cd, ++ IAPI_CHANGE_CALLBACKFUNC, ++ (unsigned long)iapi_interrupt_callback); ++ iapi_IoCtl(sdma_data[*channel].cd, ++ IAPI_CHANGE_USER_ARG, ++ (unsigned long)&sdma_data[*channel]); ++ } ++ ++ up(&sdma_status_mutex); ++ ++ return res; ++} ++EXPORT_SYMBOL(mxc_request_dma); ++ ++/* ++ * Configures request parameters. Can be called multiple times after ++ * mxc_request_dma() and mxc_dma_setup_channel(). ++ * ++ * ++ * @param channel channel number ++ * @param p request parameters pointer ++ * @param bd_index index of buffer descriptor to set ++ * @return 0 on success, error code on fail ++ */ ++int mxc_dma_set_config(int channel, dma_request_t *p, int bd_index) ++{ ++ int ret; ++ unsigned long param; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ if (!sdma_data[channel].in_use) { ++ return -EINVAL; ++ } ++ DBG(0, "%s: dma_request: src: %08x dst: %08x cont=%d wrap=%d\n", ++ __FUNCTION__, p->sourceAddr, p->destAddr, ++ p->bd_cont, p->bd_wrap); ++ ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_TRANSFER_CD, sdma_data[channel].word_size); ++ if (ret < 0) ++ return ret; ++ ++ param = BD_DONE | BD_INTR | BD_EXTD; ++ ++ if (sdma_data[channel].bd_number > 1 && p->bd_cont) { ++ param |= BD_CONT; ++ } ++ ++ if (bd_index == sdma_data[channel].bd_number - 1 || p->bd_wrap) { ++ param |= BD_WRAP; ++ } ++ ++ switch (sdma_data[channel].transfer_type) { ++ case emi_2_per: ++ case dsp_2_per: ++ case int_2_per: ++ case emi_2_dsp: ++ case int_2_dsp: ++ case emi_2_dsp_loop: ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_BUFFERADDR, ++ (unsigned long)p->sourceAddr); ++ break; ++ case per_2_int: ++ case per_2_emi: ++ case per_2_dsp: ++ case dsp_2_int: ++ case dsp_2_emi: ++ case dsp_2_dsp: ++ case dsp_2_emi_loop: ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_BUFFERADDR, ++ (unsigned long)p->destAddr); ++ break; ++ case emi_2_int: ++ case emi_2_emi: ++ case int_2_int: ++ case int_2_emi: ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_BUFFERADDR, ++ (unsigned long)p->sourceAddr); ++ if (ret < 0) ++ return ret; ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_EXTDBUFFERADDR, ++ (unsigned long)p->destAddr); ++ break; ++ case per_2_per: ++ case dvfs_pll: ++ case dvfs_pdr: ++ return -EINVAL; ++ } ++ if (ret < 0) ++ return ret; ++ ++ /* Change the endianness for DSP to MCU Data transfers */ ++ if (sdma_data[channel].transfer_type == dsp_2_emi || ++ sdma_data[channel].transfer_type == emi_2_dsp) { ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ IAPI_CHANGE_SET_ENDIANNESS, ++ SET_BIT_ALL); ++ if (ret < 0) ++ return ret; ++ } ++ ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_COUNT, p->count); ++ if (ret < 0) ++ return ret; ++ ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, ++ param); ++ return ret; ++} ++EXPORT_SYMBOL(mxc_dma_set_config); ++ ++/* ++ * Configures the BD_INTR bit on a buffer descriptor parameters. ++ * ++ * ++ * @param channel channel number ++ * @param bd_index index of buffer descriptor to set ++ * @param bd_intr flag to set or clear the BD_INTR bit ++ * @return 0 on success, error code on fail ++ */ ++void mxc_dma_set_bd_intr(int channel, int bd_index, int bd_intr) ++{ ++ unsigned long param; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return; ++ ++ iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); ++ ++ if (bd_intr) { ++ param |= BD_INTR; ++ } else { ++ param &= ~BD_INTR; ++ } ++ iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | IAPI_CHANGE_SET_STATUS, param); ++} ++EXPORT_SYMBOL(mxc_dma_set_bd_intr); ++ ++/* ++ * Gets the BD_INTR bit on a buffer descriptor. ++ * ++ * ++ * @param channel channel number ++ * @param bd_index index of buffer descriptor to set ++ * ++ * @return returns the BD_INTR bit status ++ */ ++int mxc_dma_get_bd_intr(int channel, int bd_index) ++{ ++ int ret; ++ unsigned long bd_status = 0; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ ret = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); ++ ++ return ret == 0 ? !!(bd_status & BD_INTR) : ret; ++} ++EXPORT_SYMBOL(mxc_dma_get_bd_intr); ++ ++/* ++ * Stop the current transfer ++ * ++ * @param channel channel number ++ * @param buffer_number number of buffers (beginning with 0), ++ * whose done bits should be reset to 0 ++ */ ++int mxc_dma_reset(int channel, int buffer_number) ++{ ++ unsigned char param = 0; ++ int i = 0; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ if (!sdma_data[channel].in_use) { ++ return -EINVAL; ++ } ++ ++ /* clear the BD_DONE bits for all the necessary buffers */ ++ for (i = 0; i < buffer_number; i++) { ++ ++ iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_STATUS, (unsigned long)¶m); ++ ++ /* clear the BD_DONE bit of the buffer */ ++ param &= ~BD_DONE; ++ ++ iapi_IoCtl(sdma_data[channel].cd, (i << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_STATUS, param); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(mxc_dma_reset); ++ ++/* ++ * Returns request parameters. ++ * ++ * @param channel channel number ++ * @param p request parameters pointer ++ * @param bd_index index of buffer descriptor to get ++ * @return 0 on success, error code on fail ++ */ ++int mxc_dma_get_config(int channel, dma_request_t *p, int bd_index) ++{ ++ int err = 0; ++ unsigned long bd_status; ++ unsigned long bd_count; ++ dma_addr_t sourceAddr; ++ dma_addr_t destAddr; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ memset(p, 0, sizeof(*p)); ++ ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_STATUS, (unsigned long)&bd_status); ++ if (err) ++ return err; ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_COUNT, (unsigned long)&bd_count); ++ if (err) ++ return err; ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_BUFFERADDR, (unsigned long)&sourceAddr); ++ if (err) ++ return err; ++ ++ switch (sdma_data[channel].transfer_type) { ++ case emi_2_per: ++ case dsp_2_per: ++ case int_2_per: ++ case emi_2_dsp: ++ case int_2_dsp: ++ case emi_2_dsp_loop: ++ p->sourceAddr = sourceAddr; ++ break; ++ case per_2_int: ++ case per_2_emi: ++ case per_2_dsp: ++ case dsp_2_int: ++ case dsp_2_emi: ++ case dsp_2_dsp: ++ case dsp_2_emi_loop: ++ p->destAddr = sourceAddr; ++ break; ++ case emi_2_int: ++ case emi_2_emi: ++ case int_2_int: ++ case int_2_emi: ++ p->sourceAddr = sourceAddr; ++ err = iapi_IoCtl(sdma_data[channel].cd, ++ (bd_index << BD_NUM_OFFSET) | ++ IAPI_CHANGE_GET_EXTDBUFFERADDR, ++ (unsigned long)&destAddr); ++ if (err) ++ return err; ++ p->destAddr = destAddr; ++ break; ++ default: ++ break; ++ } ++ ++ p->count = bd_count; ++ p->bd_done = !!(bd_status & BD_DONE); ++ p->bd_cont = !!(bd_status & BD_CONT); ++ p->bd_error = !!(bd_status & BD_RROR); ++ p->bd_wrap = !!(bd_status & BD_WRAP); ++ ++ return err; ++} ++EXPORT_SYMBOL(mxc_dma_get_config); ++ ++/* ++ * This function is used by MXC IPC's write_ex2. It passes the pointer to the ++ * data control structure to iapi_write_ipcv2() ++ * ++ * @param channel SDMA channel number ++ * @param ctrl_ptr Data Control structure pointer ++ */ ++int mxc_sdma_write_ipcv2(int channel, void *ctrl_ptr) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ return iapi_Write_ipcv2(sdma_data[channel].cd, ctrl_ptr); ++} ++EXPORT_SYMBOL(mxc_sdma_write_ipcv2); ++ ++/* ++ * This function is used by MXC IPC's read_ex2. It passes the pointer to the ++ * data control structure to iapi_read_ipcv2() ++ * ++ * @param channel SDMA channel number ++ * @param ctrl_ptr Data Control structure pointer ++ */ ++int mxc_sdma_read_ipcv2(int channel, void *ctrl_ptr) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ return iapi_Read_ipcv2(sdma_data[channel].cd, ctrl_ptr); ++} ++EXPORT_SYMBOL(mxc_sdma_read_ipcv2); ++ ++/* ++ * Starts dma channel. ++ * ++ * @param channel channel number ++ */ ++int mxc_dma_start(int channel) ++{ ++ DBG(1, "%s: Starting DMA channel %d\n", __FUNCTION__, channel); ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ if (!sdma_data[channel].running) { ++ sdma_data[channel].running = 1; ++ iapi_StartChannel(channel); ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(mxc_dma_start); ++ ++/* ++ * Stops dma channel. ++ * ++ * @param channel channel number ++ */ ++int mxc_dma_stop(int channel) ++{ ++ DBG(1, "%s: Stopping DMA channel %d\n", __FUNCTION__, channel); ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ iapi_StopChannel(channel); ++ sdma_data[channel].running = 0; ++ ++ return 0; ++} ++EXPORT_SYMBOL(mxc_dma_stop); ++ ++/* ++ * Frees dma channel. ++ * ++ * @param channel channel number ++ */ ++void mxc_free_dma(int channel) ++{ ++ int i; ++ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return; ++ ++ mxc_dma_stop(channel); ++ ++ if (sdma_data[channel].event_id != 0) { ++ iapi_SetChannelEventMapping(sdma_data[channel].event_id, 0x0); ++ } ++ if (sdma_data[channel].event_id2 != 0) { ++ iapi_SetChannelEventMapping(sdma_data[channel].event_id2, 0x0); ++ } ++ ++ sdma_data[channel].event_id = 0; ++ ++ iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_PRIORITY, 0x0); ++ iapi_IoCtl(sdma_data[channel].cd, IAPI_CHANGE_OWNERSHIP, ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ ++ for (i = 0; i < sdma_data[channel].bd_number; i++) { ++ iapi_IoCtl(sdma_data[channel].cd, ++ (i << BD_NUM_OFFSET) | ++ IAPI_CHANGE_SET_STATUS, 0); ++ } ++ ++ iapi_Close(sdma_data[channel].cd); ++ ++ strlcpy(sdma_data[channel].devicename, "not used", ++ sizeof(sdma_data[channel].devicename)); ++ ++ sdma_data[channel].in_use = 0; ++} ++EXPORT_SYMBOL(mxc_free_dma); ++ ++/* ++ * Initializes channel's priorities ++ * ++ */ ++static void __init init_priorities(void) ++{ ++ iapi_IoCtl(sdma_data[0].cd, IAPI_CHANGE_PRIORITY, 0x7); ++} ++ ++/* ++ * Initializes events table ++ */ ++static void __init init_event_table(void) ++{ ++ int channel; ++ ++ for (channel = 0; channel < MAX_DMA_CHANNELS; channel++) { ++ iapi_SetChannelEventMapping(channel, 0); ++ } ++} ++ ++/* ++ * Sets callback function. Used with standard dma api ++ * for supporting interrupts ++ * ++ * @param channel channel number ++ * @param callback callback function pointer ++ * @param arg argument for callback function ++ */ ++void mxc_dma_set_callback(int channel, dma_callback_t callback, void *arg) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return; ++ ++ sdma_data[channel].callback = callback; ++ sdma_data[channel].arg = arg; ++} ++EXPORT_SYMBOL(mxc_dma_set_callback); ++ ++/* ++ * Synchronization function used by I.API ++ * ++ * @param channel channel number ++ */ ++static int getChannel(int channel) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ ++ if (irqs_disabled() || in_atomic()) { ++ if (down_trylock(&sdma_synch_mutex[channel])) { ++ return -EBUSY; ++ } ++ } else { ++ if (down_interruptible(&sdma_synch_mutex[channel])) { ++ return -EBUSY; ++ } ++ } ++ ++ return 0; ++} ++ ++/* ++ * Synchronization function used by I.API ++ * ++ * @param channel channel number ++ */ ++static int releaseChannel(int channel) ++{ ++ if (channel < 0 || channel >= MAX_DMA_CHANNELS) ++ return -EINVAL; ++ up(&sdma_synch_mutex[channel]); ++ return 0; ++} ++ ++/* ++ * Unmask interrupt function. Used by I.API ++ * ++ */ ++//static unsigned long flags; ++static void unmask_sdma_interrupt(void) ++{ ++ /* Commented out to take care of the PREEMPT_RT option ++ * local_irq_restore(flags); ++ */ ++} ++ ++/* ++ * Mask interrupt function. Used by I.API ++ * ++ */ ++static void mask_sdma_interrupt(void) ++{ ++ /* Commented to take of the PREEMPT_RT option ++ * local_irq_save(flags); ++ */ ++} ++ ++#ifdef DEBUG ++static void *sdma_memcpy(void *dst, const void *src, size_t len) ++{ ++ DBG(1, "%s: Copying %u byte from %p..%p to %p..%p\n", __FUNCTION__, ++ len, src, src + len - 1, dst, dst + len - 1); ++ memcpy(dst, src, len); ++ return dst; ++} ++#endif ++ ++/* ++ * Initializes I.API ++ */ ++static int __init init_iapi_struct(void) ++{ ++ printk(KERN_INFO "Using SDMA I.API\n"); ++ ++ iapi_Malloc = &sdma_malloc; ++#ifdef CONFIG_SDMA_IRAM ++ iapi_iram_Malloc = &sdma_iram_malloc; ++#endif /* CONFIG_SDMA_IRAM */ ++ ++ iapi_Free = &sdma_free; ++ iapi_Virt2Phys = sdma_virt_to_phys; ++ iapi_Phys2Virt = sdma_phys_to_virt; ++ iapi_memset = &memset; ++#ifndef DEBUG ++ iapi_memcpy = &memcpy; ++#else ++ iapi_memcpy = &sdma_memcpy; ++#endif ++ iapi_GotoSleep = &sdma_sleep_channel; ++ iapi_WakeUp = &sdma_wakeup_channel; ++ iapi_InitSleep = &sdma_init_sleep; ++ iapi_ReleaseChannel = &releaseChannel; ++ iapi_GetChannel = &getChannel; ++ ++ iapi_EnableInterrupts = &unmask_sdma_interrupt; ++ iapi_DisableInterrupts = &mask_sdma_interrupt; ++ ++ sdma_data[0].cd = kzalloc(sizeof(channelDescriptor), GFP_KERNEL); ++ if (sdma_data[0].cd == NULL) ++ return -ENOMEM; ++ return 0; ++} ++ ++/* ++ * Initializes channel synchronization mutexes ++ */ ++static void __init sdma_init_mutexes(void) ++{ ++ int i; ++ ++ for (i = 0; i < MAX_DMA_CHANNELS; i++) { ++ init_MUTEX(&sdma_synch_mutex[i]); ++ } ++ ++ init_MUTEX(&sdma_status_mutex); ++} ++ ++/* ++ * Channels status read proc file system function ++ * ++ * @param buf pointer to the buffer the data shuld be written to. ++ * @param start pointer to the pointer where the new data is ++ * written to. ++ * procedure should update the start pointer to point to ++ * where in the buffer the data was written. ++ * @param offset offset from start of the file ++ * @param count number of bytes to read. ++ * @param eof pointer to eof flag. sould be set to 1 when ++ * reaching eof. ++ * @param data driver specific data pointer. ++ * ++ * @return number byte read from the log buffer. ++ */ ++static int proc_read_channels(char *buf, char **start, off_t offset, int count, ++ int *eof, void *data) ++{ ++ char *log; ++ char *log_ptr; ++ char tmp[48]; ++ int i; ++//#define LOG_BUF_SIZE 4096 ++ ++#ifdef LOG_BUF_SIZE ++ log = kzalloc(LOG_BUF_SIZE, GFP_KERNEL); ++ if (log == NULL) { ++ return -ENOMEM; ++ } ++#else ++ log = buf; ++#endif ++ log_ptr = log; ++ ++ for (i = 0; i < MAX_DMA_CHANNELS; i++) { ++ if (sdma_data[i].in_use == 0) { ++ continue; ++ } ++ ++ memset(tmp, 0, sizeof(tmp)); ++ snprintf(tmp, sizeof(tmp), "Channel %d: %s\n", i, ++ sdma_data[i].devicename); ++#ifndef LOG_BUF_SIZE ++ strlcpy(log_ptr, tmp, PAGE_SIZE - (log_ptr - log)); ++#else ++ strlcpy(log_ptr, tmp, LOG_BUF_SIZE - (log_ptr - log)); ++#endif ++ log_ptr += strlen(tmp); ++ if (log_ptr - log >= PAGE_SIZE) ++ break; ++ } ++ ++ if (offset > (log_ptr - log)) { ++ *eof = 1; ++ count = 0; ++ } else { ++ if (offset + count > (log_ptr - log)) { ++ count = (log_ptr - log) - offset; ++ *eof = 1; ++ } else { ++ *eof = 0; ++ } ++ ++ memcpy(buf, log, count); ++ *start = buf; ++ } ++#ifdef LOG_BUF_SIZE ++ kfree(log); ++#endif ++ return count; ++} ++ ++/* ++ * SDMA proc file system read function ++ */ ++static int __init init_proc_fs(void) ++{ ++ struct proc_dir_entry *sdma_proc_dir; ++ int res; ++ ++ res = 0; ++ ++ sdma_proc_dir = proc_mkdir("sdma", NULL); ++ create_proc_read_entry("channels", 0, sdma_proc_dir, ++ proc_read_channels, NULL); ++ ++ if (res < 0) { ++ printk(KERN_WARNING "Failed create SDMA proc entry\n"); ++ } ++ ++ return res; ++} ++ ++/* ++ * Initializes SDMA private data ++ */ ++static void __init init_sdma_data(void) ++{ ++ int i; ++ ++ sdma_data[0].in_use = 1; ++ strcpy(sdma_data[0].devicename, "MCU"); ++ ++ for (i = 0; i < MAX_DMA_CHANNELS; i++) { ++ sdma_data[i].channel = i; ++ } ++} ++ ++#if defined(CONFIG_MXC_SUPER_GEM) ++/* ++ * Initialize the Super GEM SDMA channel ++ * ++ * @return returns NO FUCKING -1 on error, 0 on success. ++ */ ++static int __init init_super_gem(void) ++{ ++ channelDescriptor *cd; ++ script_data context; ++ int res = 0; ++ ++ res = iapi_Open(sdma_data[0].cd, MXC_DMA_CHANNEL_GEM); ++ if (res < 0) { ++ return res; ++ } ++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 1; ++ cd = CHAD(MXC_DMA_CHANNEL_GEM); ++ memset(&context, 0, sizeof(script_data)); ++ context.load_address = sdma_script_addrs.mxc_sdma_utra_addr; ++ context.wml = M3_BASE_ADDRESS; ++ res = iapi_AssignScript(cd, &context); ++ if (res < 0) { ++ iapi_Close(cd); ++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; ++ return res; ++ } ++ res = iapi_IoCtl(cd, IAPI_CHANGE_OWNERSHIP, ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_EVT) | ++ (DONT_OWN_CHANNEL << CH_OWNSHP_OFFSET_MCU) | ++ (OWN_CHANNEL << CH_OWNSHP_OFFSET_DSP)); ++ if (res < 0) { ++ iapi_Close(cd); ++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; ++ return res; ++ } ++ /* Set EP=1, which is required to start SuperGem script the first time */ ++ /* This can be done only on the AP side */ ++ SDMA_H_EVTPEND |= 1 << MXC_DMA_CHANNEL_GEM; ++ ++ res = iapi_SetChannelEventMapping(DMA_REQ_GEM, ++ 1 << MXC_DMA_CHANNEL_GEM); ++ if (res < 0) { ++ iapi_Close(cd); ++ sdma_data[MXC_DMA_CHANNEL_GEM].in_use = 0; ++ return res; ++ } ++ ++ return 0; ++} ++#endif ++ ++/* ++ * Initializes dma ++ */ ++int __init sdma_init(void) ++{ ++ int res; ++ configs_data confreg_data; ++ struct clk *ahb_clk; ++ ++ sdma_base_addr = ioremap(SDMA_BASE_ADDR, SZ_16K); ++ if (sdma_base_addr == NULL) ++ return -ENOMEM; ++ ++ /* Initialize to the default values */ ++ confreg_data = iapi_ConfigDefaults; ++ ++#ifdef MXC_SDMA_DSPDMA ++ confreg_data.dspdma = MXC_SDMA_DSPDMA; ++#endif ++ /* Set ACR bit */ ++ mxc_sdma_clk = clk_get_sys(NULL, "sdma"); ++ if (IS_ERR(mxc_sdma_clk)) { ++ res = PTR_ERR(mxc_sdma_clk); ++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res); ++ goto clk_fail; ++ } ++ ++ ahb_clk = clk_get_sys(NULL, "ahb"); ++ if (IS_ERR(ahb_clk)) { ++ res = PTR_ERR(ahb_clk); ++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res); ++ goto clk_fail; ++ } ++ clk_enable(mxc_sdma_clk); ++ clk_enable(ahb_clk); ++ printk(KERN_INFO "AHB clock rate: %lu.%03luMHz SDMA clock rate: %lu.%03luMHz\n", ++ clk_get_rate(ahb_clk) / 1000000, ++ clk_get_rate(ahb_clk) / 1000 % 1000, ++ clk_get_rate(mxc_sdma_clk) / 1000000, ++ clk_get_rate(mxc_sdma_clk) / 1000 % 1000); ++ if (clk_get_rate(ahb_clk) / clk_get_rate(mxc_sdma_clk) != 2) { ++ printk(KERN_INFO "Setting SDMA ACR\n"); ++ confreg_data.acr = 1; ++ } ++ clk_disable(ahb_clk); ++ clk_put(ahb_clk); ++ ++ init_sdma_data(); ++ ++ init_sdma_pool(); ++ ++ res = request_irq(MXC_INT_SDMA, sdma_int_handler, 0, "mxc-sdma", NULL); ++ if (res) { ++ printk(KERN_EMERG "Failed to get SDMA clock: %d\n", res); ++ goto sdma_init_fail; ++ } ++ ++ sdma_init_mutexes(); ++ ++ res = init_iapi_struct(); ++ if (res) ++ goto free_irq; ++ ++ mxc_sdma_get_script_info(&sdma_script_addrs); ++ ++ res = iapi_Init(sdma_data[0].cd, &confreg_data, ++ sdma_script_addrs.mxc_sdma_start_addr, ++ sdma_script_addrs.mxc_sdma_ram_code_size * 2, ++ sdma_script_addrs.mxc_sdma_ram_code_start_addr, 0x50); ++ if (res < 0) { ++ printk(KERN_EMERG "Failed to init SDMA API: %d\n", res); ++ goto free_mem; ++ } ++ ++ init_priorities(); ++ ++ init_event_table(); ++ ++#if defined(CONFIG_MXC_SUPER_GEM) ++ res = init_super_gem(); ++ if (res < 0) { ++ goto free_mem; ++ } ++#endif ++ ++ init_proc_fs(); ++ ++ printk(KERN_INFO "MXC SDMA API initialized\n"); ++ ++ clk_disable(mxc_sdma_clk); ++ return res; ++free_mem: ++ kfree(sdma_data[0].cd); ++free_irq: ++ free_irq(MXC_INT_SDMA, NULL); ++sdma_init_fail: ++ clk_disable(mxc_sdma_clk); ++ clk_put(mxc_sdma_clk); ++clk_fail: ++ iounmap(sdma_base_addr); ++ sdma_base_addr = NULL; ++ printk(KERN_ERR "Error %d in sdma_init\n", res); ++ return res; ++} ++arch_initcall(sdma_init); ++ ++MODULE_AUTHOR("Freescale Semiconductor, Inc."); ++MODULE_DESCRIPTION("MXC Linux SDMA API"); ++MODULE_LICENSE("GPL"); +diff -urN linux.35.old/arch/arm/plat-mxc/sdma/sdma.h linux.35.new/arch/arm/plat-mxc/sdma/sdma.h +--- linux.35.old/arch/arm/plat-mxc/sdma/sdma.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux.35.new/arch/arm/plat-mxc/sdma/sdma.h 2010-12-03 09:51:55.416347546 +0100 +@@ -0,0 +1,13 @@ ++#ifndef __SDMA_H ++#define __SDMA_H ++ ++extern struct clk *mxc_sdma_clk; ++extern void __iomem *sdma_base_addr; ++ ++/* ++ * SDMA buffers pool initialization function ++ */ ++extern void init_sdma_pool(void); ++ ++ ++#endif /* __SDMA_H */ +diff -urN linux.35.old/arch/arm/plat-mxc/sdma/sdma_malloc.c linux.35.new/arch/arm/plat-mxc/sdma/sdma_malloc.c +--- linux.35.old/arch/arm/plat-mxc/sdma/sdma_malloc.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux.35.new/arch/arm/plat-mxc/sdma/sdma_malloc.c 2010-12-03 09:51:55.416347546 +0100 +@@ -0,0 +1,404 @@ ++/* ++ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. ++ */ ++ ++/* ++ * The code contained herein is licensed under the GNU General Public ++ * License. You may obtain a copy of the GNU General Public License ++ * Version 2 or later at the following locations: ++ * ++ * http://www.opensource.org/licenses/gpl-license.html ++ * http://www.gnu.org/copyleft/gpl.html ++ */ ++ ++/*! ++ * @file plat-mxc/sdma/sdma_malloc.c ++ * @brief This file contains functions for SDMA non-cacheable buffers allocation ++ * ++ * SDMA (Smart DMA) is used for transferring data between MCU and peripherals ++ * ++ * @ingroup SDMA ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++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 ++ * ++ * 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 ++ * initial code ++ * ++ * TODO: ++ * add RDS support - partialy ++ * add power on/off detection test in fuctions ? ++ */ ++ ++#include ++#include ++#include ++#include /* Initdata */ ++#include /* kernel radio structs */ ++#include /* I2C */ ++#include ++#include ++#include /* for KERNEL_VERSION MACRO */ ++ ++#include ++#include ++#include ++#include ++ ++#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 ++ ++ ++/* driver definitions */ ++#define DRIVER_NAME "radio-si4705" ++ ++#define DRIVER_VERSION "v0.01" ++#define RADIO_VERSION KERNEL_VERSION(0, 0, 1) ++ ++#define DRIVER_AUTHOR "Voipac " ++#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 ++ * ++ * 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 "); ++ * This driver supports Enhanced Secure Digital Host Controller ++ * modules eSDHC of MXC. eSDHC is also referred as enhanced MMC/SD ++ * controller. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#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 ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DRV_NAME "flexcan" ++ ++/* 8 for RX fifo and 2 error handling */ ++#define FLEXCAN_NAPI_WEIGHT (8 + 2) ++ ++/* FLEXCAN module configuration register (CANMCR) bits */ ++#define FLEXCAN_MCR_MDIS BIT(31) ++#define FLEXCAN_MCR_FRZ BIT(30) ++#define FLEXCAN_MCR_FEN BIT(29) ++#define FLEXCAN_MCR_HALT BIT(28) ++#define FLEXCAN_MCR_NOT_RDY BIT(27) ++#define FLEXCAN_MCR_WAK_MSK BIT(26) ++#define FLEXCAN_MCR_SOFTRST BIT(25) ++#define FLEXCAN_MCR_FRZ_ACK BIT(24) ++#define FLEXCAN_MCR_SUPV BIT(23) ++#define FLEXCAN_MCR_SLF_WAK BIT(22) ++#define FLEXCAN_MCR_WRN_EN BIT(21) ++#define FLEXCAN_MCR_LPM_ACK BIT(20) ++#define FLEXCAN_MCR_WAK_SRC BIT(19) ++#define FLEXCAN_MCR_DOZE BIT(18) ++#define FLEXCAN_MCR_SRX_DIS BIT(17) ++#define FLEXCAN_MCR_BCC BIT(16) ++#define FLEXCAN_MCR_LPRIO_EN BIT(13) ++#define FLEXCAN_MCR_AEN BIT(12) ++#define FLEXCAN_MCR_MAXMB(x) ((x) & 0xf) ++#define FLEXCAN_MCR_IDAM_A (0 << 8) ++#define FLEXCAN_MCR_IDAM_B (1 << 8) ++#define FLEXCAN_MCR_IDAM_C (2 << 8) ++#define FLEXCAN_MCR_IDAM_D (3 << 8) ++ ++/* FLEXCAN control register (CANCTRL) bits */ ++#define FLEXCAN_CTRL_PRESDIV(x) (((x) & 0xff) << 24) ++#define FLEXCAN_CTRL_RJW(x) (((x) & 0x03) << 22) ++#define FLEXCAN_CTRL_PSEG1(x) (((x) & 0x07) << 19) ++#define FLEXCAN_CTRL_PSEG2(x) (((x) & 0x07) << 16) ++#define FLEXCAN_CTRL_BOFF_MSK BIT(15) ++#define FLEXCAN_CTRL_ERR_MSK BIT(14) ++#define FLEXCAN_CTRL_CLK_SRC BIT(13) ++#define FLEXCAN_CTRL_LPB BIT(12) ++#define FLEXCAN_CTRL_TWRN_MSK BIT(11) ++#define FLEXCAN_CTRL_RWRN_MSK BIT(10) ++#define FLEXCAN_CTRL_SMP BIT(7) ++#define FLEXCAN_CTRL_BOFF_REC BIT(6) ++#define FLEXCAN_CTRL_TSYN BIT(5) ++#define FLEXCAN_CTRL_LBUF BIT(4) ++#define FLEXCAN_CTRL_LOM BIT(3) ++#define FLEXCAN_CTRL_PROPSEG(x) ((x) & 0x07) ++#define FLEXCAN_CTRL_ERR_BUS (FLEXCAN_CTRL_ERR_MSK) ++#define FLEXCAN_CTRL_ERR_STATE \ ++ (FLEXCAN_CTRL_TWRN_MSK | FLEXCAN_CTRL_RWRN_MSK | \ ++ FLEXCAN_CTRL_BOFF_MSK) ++#define FLEXCAN_CTRL_ERR_ALL \ ++ (FLEXCAN_CTRL_ERR_BUS | FLEXCAN_CTRL_ERR_STATE) ++ ++/* FLEXCAN error and status register (ESR) bits */ ++#define FLEXCAN_ESR_TWRN_INT BIT(17) ++#define FLEXCAN_ESR_RWRN_INT BIT(16) ++#define FLEXCAN_ESR_BIT1_ERR BIT(15) ++#define FLEXCAN_ESR_BIT0_ERR BIT(14) ++#define FLEXCAN_ESR_ACK_ERR BIT(13) ++#define FLEXCAN_ESR_CRC_ERR BIT(12) ++#define FLEXCAN_ESR_FRM_ERR BIT(11) ++#define FLEXCAN_ESR_STF_ERR BIT(10) ++#define FLEXCAN_ESR_TX_WRN BIT(9) ++#define FLEXCAN_ESR_RX_WRN BIT(8) ++#define FLEXCAN_ESR_IDLE BIT(7) ++#define FLEXCAN_ESR_TXRX BIT(6) ++#define FLEXCAN_EST_FLT_CONF_SHIFT (4) ++#define FLEXCAN_ESR_FLT_CONF_MASK (0x3 << FLEXCAN_EST_FLT_CONF_SHIFT) ++#define FLEXCAN_ESR_FLT_CONF_ACTIVE (0x0 << FLEXCAN_EST_FLT_CONF_SHIFT) ++#define FLEXCAN_ESR_FLT_CONF_PASSIVE (0x1 << FLEXCAN_EST_FLT_CONF_SHIFT) ++#define FLEXCAN_ESR_BOFF_INT BIT(2) ++#define FLEXCAN_ESR_ERR_INT BIT(1) ++#define FLEXCAN_ESR_WAK_INT BIT(0) ++#define FLEXCAN_ESR_ERR_BUS \ ++ (FLEXCAN_ESR_BIT1_ERR | FLEXCAN_ESR_BIT0_ERR | \ ++ FLEXCAN_ESR_ACK_ERR | FLEXCAN_ESR_CRC_ERR | \ ++ FLEXCAN_ESR_FRM_ERR | FLEXCAN_ESR_STF_ERR) ++#define FLEXCAN_ESR_ERR_STATE \ ++ (FLEXCAN_ESR_TWRN_INT | FLEXCAN_ESR_RWRN_INT | FLEXCAN_ESR_BOFF_INT) ++#define FLEXCAN_ESR_ERR_ALL \ ++ (FLEXCAN_ESR_ERR_BUS | FLEXCAN_ESR_ERR_STATE) ++ ++/* FLEXCAN interrupt flag register (IFLAG) bits */ ++#define FLEXCAN_TX_BUF_ID 8 ++#define FLEXCAN_IFLAG_BUF(x) BIT(x) ++#define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW BIT(7) ++#define FLEXCAN_IFLAG_RX_FIFO_WARN BIT(6) ++#define FLEXCAN_IFLAG_RX_FIFO_AVAILABLE BIT(5) ++#define FLEXCAN_IFLAG_DEFAULT \ ++ (FLEXCAN_IFLAG_RX_FIFO_OVERFLOW | FLEXCAN_IFLAG_RX_FIFO_AVAILABLE | \ ++ FLEXCAN_IFLAG_BUF(FLEXCAN_TX_BUF_ID)) ++ ++/* FLEXCAN message buffers */ ++#define FLEXCAN_MB_CNT_CODE(x) (((x) & 0xf) << 24) ++#define FLEXCAN_MB_CNT_SRR BIT(22) ++#define FLEXCAN_MB_CNT_IDE BIT(21) ++#define FLEXCAN_MB_CNT_RTR BIT(20) ++#define FLEXCAN_MB_CNT_LENGTH(x) (((x) & 0xf) << 16) ++#define FLEXCAN_MB_CNT_TIMESTAMP(x) ((x) & 0xffff) ++ ++#define FLEXCAN_MB_CODE_MASK (0xf0ffffff) ++ ++/* Structure of the message buffer */ ++struct flexcan_mb { ++ u32 can_ctrl; ++ u32 can_id; ++ u32 data[2]; ++}; ++ ++/* Structure of the hardware registers */ ++struct flexcan_regs { ++ u32 mcr; /* 0x00 */ ++ u32 ctrl; /* 0x04 */ ++ u32 timer; /* 0x08 */ ++ u32 _reserved1; /* 0x0c */ ++ u32 rxgmask; /* 0x10 */ ++ u32 rx14mask; /* 0x14 */ ++ u32 rx15mask; /* 0x18 */ ++ u32 ecr; /* 0x1c */ ++ u32 esr; /* 0x20 */ ++ u32 imask2; /* 0x24 */ ++ u32 imask1; /* 0x28 */ ++ u32 iflag2; /* 0x2c */ ++ u32 iflag1; /* 0x30 */ ++ u32 _reserved2[19]; ++ struct flexcan_mb cantxfg[64]; ++}; ++ ++struct flexcan_priv { ++ struct can_priv can; ++ struct net_device *dev; ++ struct napi_struct napi; ++ ++ void __iomem *base; ++ u32 reg_esr; ++ u32 reg_ctrl_default; ++ ++ struct clk *clk; ++ struct flexcan_platform_data *pdata; ++}; ++ ++static struct can_bittiming_const flexcan_bittiming_const = { ++ .name = DRV_NAME, ++ .tseg1_min = 4, ++ .tseg1_max = 16, ++ .tseg2_min = 2, ++ .tseg2_max = 8, ++ .sjw_max = 4, ++ .brp_min = 1, ++ .brp_max = 256, ++ .brp_inc = 1, ++}; ++ ++/* ++ * Swtich transceiver on or off ++ */ ++static void flexcan_transceiver_switch(const struct flexcan_priv *priv, int on) ++{ ++ if (priv->pdata && priv->pdata->transceiver_switch) ++ priv->pdata->transceiver_switch(on); ++} ++ ++static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, ++ u32 reg_esr) ++{ ++ return (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) && ++ (reg_esr & FLEXCAN_ESR_ERR_BUS); ++} ++ ++static inline void flexcan_chip_enable(struct flexcan_priv *priv) ++{ ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg; ++ ++ reg = readl(®s->mcr); ++ reg &= ~FLEXCAN_MCR_MDIS; ++ writel(reg, ®s->mcr); ++ ++ udelay(10); ++} ++ ++static inline void flexcan_chip_disable(struct flexcan_priv *priv) ++{ ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg; ++ ++ reg = readl(®s->mcr); ++ reg |= FLEXCAN_MCR_MDIS; ++ writel(reg, ®s->mcr); ++} ++ ++static int flexcan_get_berr_counter(const struct net_device *dev, ++ struct can_berr_counter *bec) ++{ ++ const struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg = readl(®s->ecr); ++ ++ bec->txerr = (reg >> 0) & 0xff; ++ bec->rxerr = (reg >> 8) & 0xff; ++ ++ return 0; ++} ++ ++static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ const struct flexcan_priv *priv = netdev_priv(dev); ++ struct net_device_stats *stats = &dev->stats; ++ struct flexcan_regs __iomem *regs = priv->base; ++ struct can_frame *cf = (struct can_frame *)skb->data; ++ u32 can_id; ++ u32 ctrl = FLEXCAN_MB_CNT_CODE(0xc) | (cf->can_dlc << 16); ++ ++ if (can_dropped_invalid_skb(dev, skb)) ++ return NETDEV_TX_OK; ++ ++ netif_stop_queue(dev); ++ ++ if (cf->can_id & CAN_EFF_FLAG) { ++ can_id = cf->can_id & CAN_EFF_MASK; ++ ctrl |= FLEXCAN_MB_CNT_IDE | FLEXCAN_MB_CNT_SRR; ++ } else { ++ can_id = (cf->can_id & CAN_SFF_MASK) << 18; ++ } ++ ++ if (cf->can_id & CAN_RTR_FLAG) ++ ctrl |= FLEXCAN_MB_CNT_RTR; ++ ++ if (cf->can_dlc > 0) { ++ u32 data = be32_to_cpup((__be32 *)&cf->data[0]); ++ writel(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[0]); ++ } ++ if (cf->can_dlc > 3) { ++ u32 data = be32_to_cpup((__be32 *)&cf->data[4]); ++ writel(data, ®s->cantxfg[FLEXCAN_TX_BUF_ID].data[1]); ++ } ++ ++ writel(can_id, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_id); ++ writel(ctrl, ®s->cantxfg[FLEXCAN_TX_BUF_ID].can_ctrl); ++ ++ kfree_skb(skb); ++ ++ /* tx_packets is incremented in flexcan_irq */ ++ stats->tx_bytes += cf->can_dlc; ++ ++ return NETDEV_TX_OK; ++} ++ ++static void do_bus_err(struct net_device *dev, ++ struct can_frame *cf, u32 reg_esr) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ int rx_errors = 0, tx_errors = 0; ++ ++ cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR; ++ ++ if (reg_esr & FLEXCAN_ESR_BIT1_ERR) { ++ dev_dbg(dev->dev.parent, "BIT1_ERR irq\n"); ++ cf->data[2] |= CAN_ERR_PROT_BIT1; ++ tx_errors = 1; ++ } ++ if (reg_esr & FLEXCAN_ESR_BIT0_ERR) { ++ dev_dbg(dev->dev.parent, "BIT0_ERR irq\n"); ++ cf->data[2] |= CAN_ERR_PROT_BIT0; ++ tx_errors = 1; ++ } ++ if (reg_esr & FLEXCAN_ESR_ACK_ERR) { ++ dev_dbg(dev->dev.parent, "ACK_ERR irq\n"); ++ cf->can_id |= CAN_ERR_ACK; ++ cf->data[3] |= CAN_ERR_PROT_LOC_ACK; ++ tx_errors = 1; ++ } ++ if (reg_esr & FLEXCAN_ESR_CRC_ERR) { ++ dev_dbg(dev->dev.parent, "CRC_ERR irq\n"); ++ cf->data[2] |= CAN_ERR_PROT_BIT; ++ cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ; ++ rx_errors = 1; ++ } ++ if (reg_esr & FLEXCAN_ESR_FRM_ERR) { ++ dev_dbg(dev->dev.parent, "FRM_ERR irq\n"); ++ cf->data[2] |= CAN_ERR_PROT_FORM; ++ rx_errors = 1; ++ } ++ if (reg_esr & FLEXCAN_ESR_STF_ERR) { ++ dev_dbg(dev->dev.parent, "STF_ERR irq\n"); ++ cf->data[2] |= CAN_ERR_PROT_STUFF; ++ rx_errors = 1; ++ } ++ ++ priv->can.can_stats.bus_error++; ++ if (rx_errors) ++ dev->stats.rx_errors++; ++ if (tx_errors) ++ dev->stats.tx_errors++; ++} ++ ++static int flexcan_poll_bus_err(struct net_device *dev, u32 reg_esr) ++{ ++ struct sk_buff *skb; ++ struct can_frame *cf; ++ ++ skb = alloc_can_err_skb(dev, &cf); ++ if (unlikely(!skb)) ++ return 0; ++ ++ do_bus_err(dev, cf, reg_esr); ++ netif_receive_skb(skb); ++ ++ dev->stats.rx_packets++; ++ dev->stats.rx_bytes += cf->can_dlc; ++ ++ return 1; ++} ++ ++static void do_state(struct net_device *dev, ++ struct can_frame *cf, enum can_state new_state) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct can_berr_counter bec; ++ ++ flexcan_get_berr_counter(dev, &bec); ++ ++ switch (priv->can.state) { ++ case CAN_STATE_ERROR_ACTIVE: ++ /* ++ * from: ERROR_ACTIVE ++ * to : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF ++ * => : there was a warning int ++ */ ++ if (new_state >= CAN_STATE_ERROR_WARNING && ++ new_state <= CAN_STATE_BUS_OFF) { ++ dev_dbg(dev->dev.parent, "Error Warning IRQ\n"); ++ priv->can.can_stats.error_warning++; ++ ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] = (bec.txerr > bec.rxerr) ? ++ CAN_ERR_CRTL_TX_WARNING : ++ CAN_ERR_CRTL_RX_WARNING; ++ } ++ case CAN_STATE_ERROR_WARNING: /* fallthrough */ ++ /* ++ * from: ERROR_ACTIVE, ERROR_WARNING ++ * to : ERROR_PASSIVE, BUS_OFF ++ * => : error passive int ++ */ ++ if (new_state >= CAN_STATE_ERROR_PASSIVE && ++ new_state <= CAN_STATE_BUS_OFF) { ++ dev_dbg(dev->dev.parent, "Error Passive IRQ\n"); ++ priv->can.can_stats.error_passive++; ++ ++ cf->can_id |= CAN_ERR_CRTL; ++ cf->data[1] = (bec.txerr > bec.rxerr) ? ++ CAN_ERR_CRTL_TX_PASSIVE : ++ CAN_ERR_CRTL_RX_PASSIVE; ++ } ++ break; ++ case CAN_STATE_BUS_OFF: ++ dev_err(dev->dev.parent, ++ "BUG! hardware recovered automatically from BUS_OFF\n"); ++ break; ++ default: ++ break; ++ } ++ ++ /* process state changes depending on the new state */ ++ switch (new_state) { ++ case CAN_STATE_ERROR_ACTIVE: ++ dev_dbg(dev->dev.parent, "Error Active\n"); ++ cf->can_id |= CAN_ERR_PROT; ++ cf->data[2] = CAN_ERR_PROT_ACTIVE; ++ break; ++ case CAN_STATE_BUS_OFF: ++ cf->can_id |= CAN_ERR_BUSOFF; ++ can_bus_off(dev); ++ break; ++ default: ++ break; ++ } ++} ++ ++static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct sk_buff *skb; ++ struct can_frame *cf; ++ enum can_state new_state; ++ int flt; ++ ++ flt = reg_esr & FLEXCAN_ESR_FLT_CONF_MASK; ++ if (likely(flt == FLEXCAN_ESR_FLT_CONF_ACTIVE)) { ++ if (likely(!(reg_esr & (FLEXCAN_ESR_TX_WRN | ++ FLEXCAN_ESR_RX_WRN)))) ++ new_state = CAN_STATE_ERROR_ACTIVE; ++ else ++ new_state = CAN_STATE_ERROR_WARNING; ++ } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) ++ new_state = CAN_STATE_ERROR_PASSIVE; ++ else ++ new_state = CAN_STATE_BUS_OFF; ++ ++ /* state hasn't changed */ ++ if (likely(new_state == priv->can.state)) ++ return 0; ++ ++ skb = alloc_can_err_skb(dev, &cf); ++ if (unlikely(!skb)) ++ return 0; ++ ++ do_state(dev, cf, new_state); ++ priv->can.state = new_state; ++ netif_receive_skb(skb); ++ ++ dev->stats.rx_packets++; ++ dev->stats.rx_bytes += cf->can_dlc; ++ ++ return 1; ++} ++ ++static void flexcan_read_fifo(const struct net_device *dev, ++ struct can_frame *cf) ++{ ++ const struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ struct flexcan_mb __iomem *mb = ®s->cantxfg[0]; ++ u32 reg_ctrl, reg_id; ++ ++ reg_ctrl = readl(&mb->can_ctrl); ++ reg_id = readl(&mb->can_id); ++ if (reg_ctrl & FLEXCAN_MB_CNT_IDE) ++ cf->can_id = ((reg_id >> 0) & CAN_EFF_MASK) | CAN_EFF_FLAG; ++ else ++ cf->can_id = (reg_id >> 18) & CAN_SFF_MASK; ++ ++ if (reg_ctrl & FLEXCAN_MB_CNT_RTR) ++ cf->can_id |= CAN_RTR_FLAG; ++ cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf); ++ ++ *(__be32 *)(cf->data + 0) = cpu_to_be32(readl(&mb->data[0])); ++ *(__be32 *)(cf->data + 4) = cpu_to_be32(readl(&mb->data[1])); ++ ++ /* mark as read */ ++ writel(FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ®s->iflag1); ++ readl(®s->timer); ++} ++ ++static int flexcan_read_frame(struct net_device *dev) ++{ ++ struct net_device_stats *stats = &dev->stats; ++ struct can_frame *cf; ++ struct sk_buff *skb; ++ ++ skb = alloc_can_skb(dev, &cf); ++ if (unlikely(!skb)) { ++ stats->rx_dropped++; ++ return 0; ++ } ++ ++ flexcan_read_fifo(dev, cf); ++ netif_receive_skb(skb); ++ ++ stats->rx_packets++; ++ stats->rx_bytes += cf->can_dlc; ++ ++ return 1; ++} ++ ++static int flexcan_poll(struct napi_struct *napi, int quota) ++{ ++ struct net_device *dev = napi->dev; ++ const struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg_iflag1, reg_esr; ++ int work_done = 0; ++ ++ /* ++ * The error bits are cleared on read, ++ * use saved value from irq handler. ++ */ ++ reg_esr = readl(®s->esr) | priv->reg_esr; ++ ++ /* handle state changes */ ++ work_done += flexcan_poll_state(dev, reg_esr); ++ ++ /* handle RX-FIFO */ ++ reg_iflag1 = readl(®s->iflag1); ++ while (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE && ++ work_done < quota) { ++ work_done += flexcan_read_frame(dev); ++ reg_iflag1 = readl(®s->iflag1); ++ } ++ ++ /* report bus errors */ ++ if (flexcan_has_and_handle_berr(priv, reg_esr) && work_done < quota) ++ work_done += flexcan_poll_bus_err(dev, reg_esr); ++ ++ if (work_done < quota) { ++ napi_complete(napi); ++ /* enable IRQs */ ++ writel(FLEXCAN_IFLAG_DEFAULT, ®s->imask1); ++ writel(priv->reg_ctrl_default, ®s->ctrl); ++ } ++ ++ return work_done; ++} ++ ++static irqreturn_t flexcan_irq(int irq, void *dev_id) ++{ ++ struct net_device *dev = dev_id; ++ struct net_device_stats *stats = &dev->stats; ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg_iflag1, reg_esr; ++ ++ reg_iflag1 = readl(®s->iflag1); ++ reg_esr = readl(®s->esr); ++ writel(FLEXCAN_ESR_ERR_INT, ®s->esr); /* ACK err IRQ */ ++ ++ /* ++ * schedule NAPI in case of: ++ * - rx IRQ ++ * - state change IRQ ++ * - bus error IRQ and bus error reporting is activated ++ */ ++ if ((reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_AVAILABLE) || ++ (reg_esr & FLEXCAN_ESR_ERR_STATE) || ++ flexcan_has_and_handle_berr(priv, reg_esr)) { ++ /* ++ * The error bits are cleared on read, ++ * save them for later use. ++ */ ++ priv->reg_esr = reg_esr & FLEXCAN_ESR_ERR_BUS; ++ writel(FLEXCAN_IFLAG_DEFAULT & ~FLEXCAN_IFLAG_RX_FIFO_AVAILABLE, ++ ®s->imask1); ++ writel(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, ++ ®s->ctrl); ++ napi_schedule(&priv->napi); ++ } ++ ++ /* FIFO overflow */ ++ if (reg_iflag1 & FLEXCAN_IFLAG_RX_FIFO_OVERFLOW) { ++ writel(FLEXCAN_IFLAG_RX_FIFO_OVERFLOW, ®s->iflag1); ++ dev->stats.rx_over_errors++; ++ dev->stats.rx_errors++; ++ } ++ ++ /* transmission complete interrupt */ ++ if (reg_iflag1 & (1 << FLEXCAN_TX_BUF_ID)) { ++ /* tx_bytes is incremented in flexcan_start_xmit */ ++ stats->tx_packets++; ++ writel((1 << FLEXCAN_TX_BUF_ID), ®s->iflag1); ++ netif_wake_queue(dev); ++ } ++ ++ return IRQ_HANDLED; ++} ++ ++static void flexcan_set_bittiming(struct net_device *dev) ++{ ++ const struct flexcan_priv *priv = netdev_priv(dev); ++ const struct can_bittiming *bt = &priv->can.bittiming; ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg; ++ ++ reg = readl(®s->ctrl); ++ reg &= ~(FLEXCAN_CTRL_PRESDIV(0xff) | ++ FLEXCAN_CTRL_RJW(0x3) | ++ FLEXCAN_CTRL_PSEG1(0x7) | ++ FLEXCAN_CTRL_PSEG2(0x7) | ++ FLEXCAN_CTRL_PROPSEG(0x7) | ++ FLEXCAN_CTRL_LPB | ++ FLEXCAN_CTRL_SMP | ++ FLEXCAN_CTRL_LOM); ++ ++ reg |= FLEXCAN_CTRL_PRESDIV(bt->brp - 1) | ++ FLEXCAN_CTRL_PSEG1(bt->phase_seg1 - 1) | ++ FLEXCAN_CTRL_PSEG2(bt->phase_seg2 - 1) | ++ FLEXCAN_CTRL_RJW(bt->sjw - 1) | ++ FLEXCAN_CTRL_PROPSEG(bt->prop_seg - 1); ++ ++ if (priv->can.ctrlmode & CAN_CTRLMODE_LOOPBACK) ++ reg |= FLEXCAN_CTRL_LPB; ++ if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ++ reg |= FLEXCAN_CTRL_LOM; ++ if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES) ++ reg |= FLEXCAN_CTRL_SMP; ++ ++ dev_info(dev->dev.parent, "writing ctrl=0x%08x\n", reg); ++ writel(reg, ®s->ctrl); ++ ++ /* print chip status */ ++ dev_dbg(dev->dev.parent, "%s: mcr=0x%08x ctrl=0x%08x\n", __func__, ++ readl(®s->mcr), readl(®s->ctrl)); ++} ++ ++/* ++ * flexcan_chip_start ++ * ++ * this functions is entered with clocks enabled ++ * ++ */ ++static int flexcan_chip_start(struct net_device *dev) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ unsigned int i; ++ int err; ++ u32 reg_mcr, reg_ctrl; ++ ++ /* enable module */ ++ flexcan_chip_enable(priv); ++ ++ /* soft reset */ ++ writel(FLEXCAN_MCR_SOFTRST, ®s->mcr); ++ udelay(10); ++ ++ reg_mcr = readl(®s->mcr); ++ if (reg_mcr & FLEXCAN_MCR_SOFTRST) { ++ dev_err(dev->dev.parent, ++ "Failed to softreset can module (mcr=0x%08x)\n", ++ reg_mcr); ++ err = -ENODEV; ++ goto out; ++ } ++ ++ flexcan_set_bittiming(dev); ++ ++ /* ++ * MCR ++ * ++ * enable freeze ++ * enable fifo ++ * halt now ++ * only supervisor access ++ * enable warning int ++ * choose format C ++ * ++ */ ++ reg_mcr = readl(®s->mcr); ++ reg_mcr |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_FEN | FLEXCAN_MCR_HALT | ++ FLEXCAN_MCR_SUPV | FLEXCAN_MCR_WRN_EN | ++ FLEXCAN_MCR_IDAM_C; ++ dev_dbg(dev->dev.parent, "%s: writing mcr=0x%08x", __func__, reg_mcr); ++ writel(reg_mcr, ®s->mcr); ++ ++ /* ++ * CTRL ++ * ++ * disable timer sync feature ++ * ++ * disable auto busoff recovery ++ * transmit lowest buffer first ++ * ++ * enable tx and rx warning interrupt ++ * enable bus off interrupt ++ * (== FLEXCAN_CTRL_ERR_STATE) ++ * ++ * _note_: we enable the "error interrupt" ++ * (FLEXCAN_CTRL_ERR_MSK), too. Otherwise we don't get any ++ * warning or bus passive interrupts. ++ */ ++ reg_ctrl = readl(®s->ctrl); ++ reg_ctrl &= ~FLEXCAN_CTRL_TSYN; ++ reg_ctrl |= FLEXCAN_CTRL_BOFF_REC | FLEXCAN_CTRL_LBUF | ++ FLEXCAN_CTRL_ERR_STATE | FLEXCAN_CTRL_ERR_MSK; ++ ++ /* save for later use */ ++ priv->reg_ctrl_default = reg_ctrl; ++ dev_dbg(dev->dev.parent, "%s: writing ctrl=0x%08x", __func__, reg_ctrl); ++ writel(reg_ctrl, ®s->ctrl); ++ ++ for (i = 0; i < ARRAY_SIZE(regs->cantxfg); i++) { ++ writel(0, ®s->cantxfg[i].can_ctrl); ++ writel(0, ®s->cantxfg[i].can_id); ++ writel(0, ®s->cantxfg[i].data[0]); ++ writel(0, ®s->cantxfg[i].data[1]); ++ ++ /* put MB into rx queue */ ++ writel(FLEXCAN_MB_CNT_CODE(0x4), ®s->cantxfg[i].can_ctrl); ++ } ++ ++ /* acceptance mask/acceptance code (accept everything) */ ++ writel(0x0, ®s->rxgmask); ++ writel(0x0, ®s->rx14mask); ++ writel(0x0, ®s->rx15mask); ++ ++ flexcan_transceiver_switch(priv, 1); ++ ++ /* synchronize with the can bus */ ++ reg_mcr = readl(®s->mcr); ++ reg_mcr &= ~FLEXCAN_MCR_HALT; ++ writel(reg_mcr, ®s->mcr); ++ ++ priv->can.state = CAN_STATE_ERROR_ACTIVE; ++ ++ /* enable FIFO interrupts */ ++ writel(FLEXCAN_IFLAG_DEFAULT, ®s->imask1); ++ ++ /* print chip status */ ++ dev_dbg(dev->dev.parent, "%s: reading mcr=0x%08x ctrl=0x%08x\n", ++ __func__, readl(®s->mcr), readl(®s->ctrl)); ++ ++ return 0; ++ ++ out: ++ flexcan_chip_disable(priv); ++ return err; ++} ++ ++/* ++ * flexcan_chip_stop ++ * ++ * this functions is entered with clocks enabled ++ * ++ */ ++static void flexcan_chip_stop(struct net_device *dev) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg; ++ ++ /* Disable all interrupts */ ++ writel(0, ®s->imask1); ++ ++ /* Disable + halt module */ ++ reg = readl(®s->mcr); ++ reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; ++ writel(reg, ®s->mcr); ++ ++ flexcan_transceiver_switch(priv, 0); ++ priv->can.state = CAN_STATE_STOPPED; ++ ++ return; ++} ++ ++static int flexcan_open(struct net_device *dev) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ int err; ++ ++ clk_enable(priv->clk); ++ ++ err = open_candev(dev); ++ if (err) ++ goto out; ++ ++ err = request_irq(dev->irq, flexcan_irq, IRQF_SHARED, dev->name, dev); ++ if (err) ++ goto out_close; ++ ++ /* start chip and queuing */ ++ err = flexcan_chip_start(dev); ++ if (err) ++ goto out_close; ++ napi_enable(&priv->napi); ++ netif_start_queue(dev); ++ ++ return 0; ++ ++ out_close: ++ close_candev(dev); ++ out: ++ clk_disable(priv->clk); ++ ++ return err; ++} ++ ++static int flexcan_close(struct net_device *dev) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ ++ netif_stop_queue(dev); ++ napi_disable(&priv->napi); ++ flexcan_chip_stop(dev); ++ ++ free_irq(dev->irq, dev); ++ clk_disable(priv->clk); ++ ++ close_candev(dev); ++ ++ return 0; ++} ++ ++static int flexcan_set_mode(struct net_device *dev, enum can_mode mode) ++{ ++ int err; ++ ++ switch (mode) { ++ case CAN_MODE_START: ++ err = flexcan_chip_start(dev); ++ if (err) ++ return err; ++ ++ netif_wake_queue(dev); ++ break; ++ ++ default: ++ return -EOPNOTSUPP; ++ } ++ ++ return 0; ++} ++ ++static const struct net_device_ops flexcan_netdev_ops = { ++ .ndo_open = flexcan_open, ++ .ndo_stop = flexcan_close, ++ .ndo_start_xmit = flexcan_start_xmit, ++}; ++ ++static int __devinit register_flexcandev(struct net_device *dev) ++{ ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct flexcan_regs __iomem *regs = priv->base; ++ u32 reg, err; ++ ++ clk_enable(priv->clk); ++ ++ /* select "bus clock", chip must be disabled */ ++ flexcan_chip_disable(priv); ++ reg = readl(®s->ctrl); ++ reg |= FLEXCAN_CTRL_CLK_SRC; ++ writel(reg, ®s->ctrl); ++ ++ flexcan_chip_enable(priv); ++ ++ /* set freeze, halt and activate FIFO, restrict register access */ ++ reg = readl(®s->mcr); ++ reg |= FLEXCAN_MCR_FRZ | FLEXCAN_MCR_HALT | ++ FLEXCAN_MCR_FEN | FLEXCAN_MCR_SUPV; ++ writel(reg, ®s->mcr); ++ ++ /* ++ * Currently we only support newer versions of this core ++ * featuring a RX FIFO. Older cores found on some Coldfire ++ * derivates are not yet supported. ++ */ ++ reg = readl(®s->mcr); ++ if (!(reg & FLEXCAN_MCR_FEN)) { ++ dev_err(dev->dev.parent, ++ "Could not enable RX FIFO, unsupported core\n"); ++ err = -ENODEV; ++ goto out; ++ } ++ ++ err = register_candev(dev); ++ ++ out: ++ /* disable core and turn off clocks */ ++ flexcan_chip_disable(priv); ++ clk_disable(priv->clk); ++ ++ return err; ++} ++ ++static void __devexit unregister_flexcandev(struct net_device *dev) ++{ ++ unregister_candev(dev); ++} ++ ++static int __devinit flexcan_probe(struct platform_device *pdev) ++{ ++ struct net_device *dev; ++ struct flexcan_priv *priv; ++ struct resource *mem; ++ struct clk *clk; ++ void __iomem *base; ++ resource_size_t mem_size; ++ int err, irq; ++ ++ clk = clk_get(&pdev->dev, NULL); ++ if (IS_ERR(clk)) { ++ dev_err(&pdev->dev, "no clock defined\n"); ++ err = PTR_ERR(clk); ++ goto failed_clock; ++ } ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ irq = platform_get_irq(pdev, 0); ++ if (!mem || irq <= 0) { ++ err = -ENODEV; ++ goto failed_get; ++ } ++ ++ mem_size = resource_size(mem); ++ if (!request_mem_region(mem->start, mem_size, pdev->name)) { ++ err = -EBUSY; ++ goto failed_req; ++ } ++ ++ base = ioremap(mem->start, mem_size); ++ if (!base) { ++ err = -ENOMEM; ++ goto failed_map; ++ } ++ ++ dev = alloc_candev(sizeof(struct flexcan_priv), 0); ++ if (!dev) { ++ err = -ENOMEM; ++ goto failed_alloc; ++ } ++ ++ dev->netdev_ops = &flexcan_netdev_ops; ++ dev->irq = irq; ++ dev->flags |= IFF_ECHO; /* we support local echo in hardware */ ++ ++ priv = netdev_priv(dev); ++ priv->can.clock.freq = clk_get_rate(clk); ++ priv->can.bittiming_const = &flexcan_bittiming_const; ++ priv->can.do_set_mode = flexcan_set_mode; ++ priv->can.do_get_berr_counter = flexcan_get_berr_counter; ++ priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | ++ CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES | ++ CAN_CTRLMODE_BERR_REPORTING; ++ priv->base = base; ++ priv->dev = dev; ++ priv->clk = clk; ++ priv->pdata = pdev->dev.platform_data; ++ ++ netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); ++ ++ dev_set_drvdata(&pdev->dev, dev); ++ SET_NETDEV_DEV(dev, &pdev->dev); ++ ++ err = register_flexcandev(dev); ++ if (err) { ++ dev_err(&pdev->dev, "registering netdev failed\n"); ++ goto failed_register; ++ } ++ ++ dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%d)\n", ++ priv->base, dev->irq); ++ ++ return 0; ++ ++ failed_register: ++ free_candev(dev); ++ failed_alloc: ++ iounmap(base); ++ failed_map: ++ release_mem_region(mem->start, mem_size); ++ failed_req: ++ clk_put(clk); ++ failed_get: ++ failed_clock: ++ return err; ++} ++ ++static int __devexit flexcan_remove(struct platform_device *pdev) ++{ ++ struct net_device *dev = platform_get_drvdata(pdev); ++ struct flexcan_priv *priv = netdev_priv(dev); ++ struct resource *mem; ++ ++ unregister_flexcandev(dev); ++ platform_set_drvdata(pdev, NULL); ++ free_candev(dev); ++ iounmap(priv->base); ++ ++ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ release_mem_region(mem->start, resource_size(mem)); ++ ++ clk_put(priv->clk); ++ ++ return 0; ++} ++ ++static struct platform_driver flexcan_driver = { ++ .driver.name = DRV_NAME, ++ .probe = flexcan_probe, ++ .remove = __devexit_p(flexcan_remove), ++}; ++ ++static int __init flexcan_init(void) ++{ ++ pr_info("%s netdevice driver\n", DRV_NAME); ++ return platform_driver_register(&flexcan_driver); ++} ++ ++static void __exit flexcan_exit(void) ++{ ++ platform_driver_unregister(&flexcan_driver); ++ pr_info("%s: driver removed\n", DRV_NAME); ++} ++ ++module_init(flexcan_init); ++module_exit(flexcan_exit); ++ ++MODULE_AUTHOR("Sascha Hauer , " ++ "Marc Kleine-Budde "); ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* 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 ++#include + + #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 ++ * ++ * 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 ++ ++/*! ++ * @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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "sgtl5000.h" ++ ++#include ++/* 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 ++ ++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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "../codecs/sgtl5000.h" ++#include "imx-ssi.h" ++//#include "imx-pcm.h" ++ ++#if defined(CONFIG_MXC_ASRC) || defined(CONFIG_MXC_ASRC_MODULE) ++#include ++ ++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 diff --git a/recipes/linux/linux_2.6.35.bb b/recipes/linux/linux_2.6.35.bb index 98edfaa35d..5060c02d42 100644 --- a/recipes/linux/linux_2.6.35.bb +++ b/recipes/linux/linux_2.6.35.bb @@ -15,6 +15,7 @@ DEFAULT_PREFERENCE_qemumips64 = "1" DEFAULT_PREFERENCE_qemuppc = "1" DEFAULT_PREFERENCE_qemux86 = "1" DEFAULT_PREFERENCE_nokia900 = "1" +DEFAULT_PREFERENCE_vmx25 = "1" SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/${P}.tar.bz2;name=kernel \ ${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/patch-${PV}.${STABLEV}.bz2;apply=yes;name=stablepatch \ @@ -116,6 +117,8 @@ SRC_URI_nokia900 = "\ file://inconsistent-mmc-fix-2.6.35.patch \ file://defconfig " +SRC_URI_append_vmx25 = "file://linux-2.6.35-vmx25-20110112.patch" + CMDLINE_nokia900_shr = "snd-soc-rx51.hp_lim=42 snd-soc-tlv320aic3x.hp_dac_lim=6 console=tty1 root=/dev/mmcblk1p1 rootwait panic=20 debug" SRC_URI[kernel.md5sum] = "091abeb4684ce03d1d936851618687b6" -- cgit 1.2.3-korg