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