aboutsummaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux
diff options
context:
space:
mode:
authorPaul Eggleton <paul.eggleton@linux.intel.com>2014-01-28 13:40:53 +0000
committerPaul Eggleton <paul.eggleton@linux.intel.com>2014-05-09 12:16:23 +0100
commit6dae9e2b3031dd196c7a695e75b0746c1bf8e593 (patch)
tree9d4c15d91a58ca542e00fe90d797e5bd1feddeca /recipes-kernel/linux
downloadmeta-intel-quark-6dae9e2b3031dd196c7a695e75b0746c1bf8e593.tar.gz
meta-intel-quark-6dae9e2b3031dd196c7a695e75b0746c1bf8e593.tar.bz2
meta-intel-quark-6dae9e2b3031dd196c7a695e75b0746c1bf8e593.zip
Initial commit adding combo repositories
Signed-off-by: Paul Eggleton <paul.eggleton@linux.intel.com>
Diffstat (limited to 'recipes-kernel/linux')
-rw-r--r--recipes-kernel/linux/files/clanton-standard.scc6
-rw-r--r--recipes-kernel/linux/files/clanton.cfg2938
-rw-r--r--recipes-kernel/linux/files/clanton.patch30644
-rw-r--r--recipes-kernel/linux/linux-yocto-clanton_3.8.bb70
4 files changed, 33658 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/clanton-standard.scc b/recipes-kernel/linux/files/clanton-standard.scc
new file mode 100644
index 0000000..07e0758
--- /dev/null
+++ b/recipes-kernel/linux/files/clanton-standard.scc
@@ -0,0 +1,6 @@
+define KMACHINE clanton
+define KTYPE standard
+define KARCH i386
+
+kconf hardware clanton.cfg
+
diff --git a/recipes-kernel/linux/files/clanton.cfg b/recipes-kernel/linux/files/clanton.cfg
new file mode 100644
index 0000000..1356dc9
--- /dev/null
+++ b/recipes-kernel/linux/files/clanton.cfg
@@ -0,0 +1,2938 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Linux/i386 3.8.7 Kernel Configuration
+#
+# CONFIG_64BIT is not set
+CONFIG_X86_32=y
+CONFIG_X86=y
+CONFIG_INSTRUCTION_DECODER=y
+CONFIG_OUTPUT_FORMAT="elf32-i386"
+CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_MMU=y
+CONFIG_NEED_SG_DMA_LENGTH=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_HAS_CPU_RELAX=y
+CONFIG_ARCH_HAS_DEFAULT_IDLE=y
+CONFIG_ARCH_HAS_CACHE_LINE_SIZE=y
+CONFIG_ARCH_HAS_CPU_AUTOPROBE=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_ZONE_DMA32 is not set
+# CONFIG_AUDIT_ARCH is not set
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_X86_32_LAZY_GS=y
+CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx"
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_HAVE_IRQ_WORK=y
+CONFIG_IRQ_WORK=y
+CONFIG_BUILDTIME_EXTABLE_SORT=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=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_BZIP2=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_KERNEL_LZO=y
+# CONFIG_KERNEL_GZIP is not set
+# CONFIG_KERNEL_BZIP2 is not set
+CONFIG_KERNEL_LZMA=y
+# CONFIG_KERNEL_XZ is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_DEFAULT_HOSTNAME="(none)"
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_FHANDLE is not set
+# CONFIG_AUDIT is not set
+CONFIG_HAVE_GENERIC_HARDIRQS=y
+
+#
+# IRQ subsystem
+#
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_IRQ_DOMAIN=y
+# CONFIG_IRQ_DOMAIN_DEBUG is not set
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+
+#
+# Timers subsystem
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+
+#
+# CPU/Task time and stats accounting
+#
+CONFIG_TICK_CPU_ACCOUNTING=y
+# CONFIG_IRQ_TIME_ACCOUNTING is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TINY_RCU=y
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=18
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
+CONFIG_ARCH_WANTS_PROT_NUMA_PROT_NONE=y
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+CONFIG_CGROUP_FREEZER=y
+# CONFIG_CGROUP_DEVICE is not set
+CONFIG_CPUSETS=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_MEMCG is not set
+# CONFIG_CGROUP_HUGETLB is not set
+# CONFIG_CGROUP_PERF is not set
+CONFIG_CGROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_CFS_BANDWIDTH is not set
+# CONFIG_RT_GROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
+# CONFIG_CHECKPOINT_RESTORE is not set
+CONFIG_NAMESPACES=y
+CONFIG_UTS_NS=y
+CONFIG_IPC_NS=y
+# CONFIG_USER_NS is not set
+CONFIG_PID_NS=y
+CONFIG_NET_NS=y
+CONFIG_UIDGID_CONVERTED=y
+# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set
+# CONFIG_SCHED_AUTOGROUP is not set
+# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EXPERT=y
+CONFIG_HAVE_UID16=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_HAVE_PCSPKR_PLATFORM=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=y
+CONFIG_EMBEDDED=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_PERF_EVENTS=y
+# CONFIG_DEBUG_PERF_USE_VMALLOC is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_OPROFILE_NMI_TIMER=y
+# CONFIG_KPROBES is not set
+CONFIG_JUMP_LABEL=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_MIXED_BREAKPOINTS_REGS=y
+CONFIG_HAVE_USER_RETURN_NOTIFIER=y
+CONFIG_HAVE_PERF_EVENTS_NMI=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG=y
+CONFIG_HAVE_ALIGNED_STRUCT_PAGE=y
+CONFIG_HAVE_CMPXCHG_LOCAL=y
+CONFIG_HAVE_CMPXCHG_DOUBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_SECCOMP_FILTER=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_GENERIC_SIGALTSTACK=y
+CONFIG_CLONE_BACKWARDS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_GCOV_KERNEL is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_MODULE_SIG is not set
+CONFIG_BLOCK=y
+# CONFIG_LBDAF is not set
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_BSGLIB is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_BSD_DISKLABEL=y
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_FREEZER=y
+
+#
+# Processor type and features
+#
+# CONFIG_ZONE_DMA is not set
+# CONFIG_SMP is not set
+CONFIG_X86_MPPARSE=y
+CONFIG_X86_EXTENDED_PLATFORM=y
+CONFIG_INTEL_QUARK_X1000_SOC=y
+# CONFIG_X86_WANT_INTEL_MID is not set
+# CONFIG_X86_RDC321X is not set
+CONFIG_X86_SUPPORTS_MEMORY_FAILURE=y
+
+#
+# Intel Media SOC Gen3 support
+#
+CONFIG_ARCH_GEN3=y
+# CONFIG_X86_32_IRIS is not set
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+# CONFIG_PARAVIRT_GUEST is not set
+CONFIG_NO_BOOTMEM=y
+# CONFIG_MEMTEST is not set
+# CONFIG_M486 is not set
+# CONFIG_M586 is not set
+CONFIG_M586TSC=y
+# CONFIG_M586MMX is not set
+# CONFIG_M686 is not set
+# CONFIG_MPENTIUMII is not set
+# CONFIG_MPENTIUMIII is not set
+# CONFIG_MPENTIUMM is not set
+# CONFIG_MPENTIUM4 is not set
+# CONFIG_MK6 is not set
+# CONFIG_MK7 is not set
+# CONFIG_MK8 is not set
+# CONFIG_MCRUSOE is not set
+# CONFIG_MEFFICEON is not set
+# CONFIG_MWINCHIPC6 is not set
+# CONFIG_MWINCHIP3D is not set
+# CONFIG_MELAN is not set
+# CONFIG_MGEODEGX1 is not set
+# CONFIG_MGEODE_LX is not set
+# CONFIG_MCYRIXIII is not set
+# CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
+# CONFIG_MCORE2 is not set
+# CONFIG_MATOM is not set
+CONFIG_X86_GENERIC=y
+CONFIG_X86_INTERNODE_CACHE_SHIFT=6
+CONFIG_X86_L1_CACHE_SHIFT=6
+# CONFIG_X86_PPRO_FENCE is not set
+CONFIG_X86_F00F_BUG=y
+CONFIG_X86_ALIGNMENT_16=y
+CONFIG_X86_INTEL_USERCOPY=y
+CONFIG_X86_TSC=y
+CONFIG_X86_CMPXCHG64=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=5
+# CONFIG_PROCESSOR_SELECT is not set
+CONFIG_CPU_SUP_INTEL=y
+CONFIG_CPU_SUP_CYRIX_32=y
+CONFIG_CPU_SUP_AMD=y
+CONFIG_CPU_SUP_CENTAUR=y
+CONFIG_CPU_SUP_TRANSMETA_32=y
+CONFIG_CPU_SUP_UMC_32=y
+CONFIG_HPET_TIMER=y
+CONFIG_HPET_EMULATE_RTC=y
+# CONFIG_DMI is not set
+CONFIG_NR_CPUS=1
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+CONFIG_X86_UP_APIC=y
+CONFIG_X86_UP_IOAPIC=y
+CONFIG_X86_LOCAL_APIC=y
+CONFIG_X86_IO_APIC=y
+# CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set
+CONFIG_X86_MCE=y
+CONFIG_X86_MCE_INTEL=y
+# CONFIG_X86_MCE_AMD is not set
+# CONFIG_X86_ANCIENT_MCE is not set
+CONFIG_X86_MCE_THRESHOLD=y
+# CONFIG_X86_MCE_INJECT is not set
+CONFIG_X86_THERMAL_VECTOR=y
+CONFIG_VM86=y
+# CONFIG_TOSHIBA is not set
+# CONFIG_I8K is not set
+CONFIG_X86_REBOOTFIXUPS=y
+CONFIG_MICROCODE=y
+CONFIG_MICROCODE_INTEL=y
+# CONFIG_MICROCODE_AMD is not set
+CONFIG_MICROCODE_OLD_INTERFACE=y
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
+# CONFIG_NOHIGHMEM is not set
+# CONFIG_HIGHMEM4G is not set
+CONFIG_HIGHMEM64G=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_HIGHMEM=y
+CONFIG_X86_PAE=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_ARCH_DMA_ADDR_T_64BIT=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ILLEGAL_POINTER_VALUE=0
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_STATIC=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_COMPACTION is not set
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ARCH_SUPPORTS_MEMORY_FAILURE=y
+# CONFIG_MEMORY_FAILURE is not set
+# CONFIG_TRANSPARENT_HUGEPAGE is not set
+CONFIG_CROSS_MEMORY_ATTACH=y
+CONFIG_NEED_PER_CPU_KM=y
+# CONFIG_CLEANCACHE is not set
+# CONFIG_HIGHPTE is not set
+# CONFIG_X86_CHECK_BIOS_CORRUPTION is not set
+CONFIG_X86_RESERVE_LOW=64
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_MTRR is not set
+# CONFIG_ARCH_RANDOM is not set
+CONFIG_X86_SMAP=y
+CONFIG_EFI=y
+CONFIG_EFI_STUB=y
+CONFIG_EFI_CAPSULE=y
+CONFIG_SECCOMP=y
+# CONFIG_CC_STACKPROTECTOR is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+CONFIG_PHYSICAL_START=0x400000
+# CONFIG_RELOCATABLE is not set
+CONFIG_PHYSICAL_ALIGN=0x1000000
+# CONFIG_COMPAT_VDSO is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+
+#
+# Power management and ACPI options
+#
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_PM_SLEEP=y
+# CONFIG_PM_AUTOSLEEP is not set
+# CONFIG_PM_WAKELOCKS is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_ADVANCED_DEBUG is not set
+CONFIG_PM_SLEEP_DEBUG=y
+CONFIG_PM_TRACE=y
+CONFIG_PM_TRACE_RTC=y
+CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_EC_DEBUGFS=y
+# CONFIG_ACPI_PROC_EVENT is not set
+CONFIG_ACPI_AC=y
+# CONFIG_ACPI_BATTERY is not set
+CONFIG_ACPI_BUTTON=y
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_I2C=m
+CONFIG_ACPI_PROCESSOR=y
+# CONFIG_ACPI_PROCESSOR_AGGREGATOR is not set
+CONFIG_ACPI_THERMAL=y
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+# CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
+CONFIG_ACPI_DEBUG=y
+# CONFIG_ACPI_DEBUG_FUNC_TRACE is not set
+CONFIG_ACPI_PCI_SLOT=y
+CONFIG_X86_PM_TIMER=y
+# CONFIG_ACPI_CONTAINER is not set
+# CONFIG_ACPI_SBS is not set
+# CONFIG_ACPI_HED is not set
+# CONFIG_ACPI_CUSTOM_METHOD is not set
+# CONFIG_ACPI_BGRT is not set
+# CONFIG_ACPI_APEI is not set
+# CONFIG_SFI is not set
+# CONFIG_APM is not set
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_IDLE=y
+# CONFIG_CPU_IDLE_MULTIPLE_DRIVERS is not set
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+# CONFIG_INTEL_IDLE is not set
+
+#
+# Bus options (PCI etc.)
+#
+CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GOMMCONFIG is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
+CONFIG_PCI_BIOS=y
+CONFIG_PCI_DIRECT=y
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_CNB20LE_QUIRK is not set
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
+CONFIG_PCIEASPM=y
+# CONFIG_PCIEASPM_DEBUG is not set
+CONFIG_PCIEASPM_DEFAULT=y
+# CONFIG_PCIEASPM_POWERSAVE is not set
+# CONFIG_PCIEASPM_PERFORMANCE is not set
+CONFIG_PCIE_PME=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_REALLOC_ENABLE_AUTO is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_HT_IRQ=y
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCI_PRI is not set
+# CONFIG_PCI_PASID is not set
+CONFIG_PCI_IOAPIC=y
+CONFIG_PCI_LABEL=y
+CONFIG_ISA_DMA_API=y
+# CONFIG_ISA is not set
+# CONFIG_SCx200 is not set
+# CONFIG_ALIX is not set
+# CONFIG_NET5501 is not set
+CONFIG_AMD_NB=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_RAPIDIO is not set
+
+#
+# Executable file formats / Emulations
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_COREDUMP=y
+CONFIG_HAVE_ATOMIC_IOMAP=y
+CONFIG_HAVE_TEXT_POKE_SMP=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_DIAG is not set
+CONFIG_UNIX=y
+# CONFIG_UNIX_DIAG is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE_DEMUX is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_NET_IPVTI 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=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_INET_UDP_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=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+# CONFIG_IPV6_SIT is not set
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_GRE is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETWORK_PHY_TIMESTAMPING 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_STP=m
+CONFIG_GARP=m
+# CONFIG_BRIDGE is not set
+CONFIG_HAVE_NET_DSA=y
+CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q_GVRP=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_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
+# CONFIG_DNS_RESOLVER is not set
+# CONFIG_BATMAN_ADV is not set
+# CONFIG_OPENVSWITCH is not set
+# CONFIG_NETPRIO_CGROUP is not set
+CONFIG_BQL=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+CONFIG_BT=m
+CONFIG_BT_RFCOMM=m
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=m
+CONFIG_BT_BNEP_MC_FILTER=y
+CONFIG_BT_BNEP_PROTO_FILTER=y
+CONFIG_BT_HIDP=m
+
+#
+# Bluetooth device drivers
+#
+CONFIG_BT_HCIBTUSB=m
+# CONFIG_BT_HCIBTSDIO is not set
+# CONFIG_BT_HCIUART is not set
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+CONFIG_BT_HCIVHCI=m
+# CONFIG_BT_MRVL is not set
+# CONFIG_BT_ATH3K is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+CONFIG_WEXT_CORE=y
+CONFIG_WEXT_PROC=y
+CONFIG_CFG80211=m
+# CONFIG_NL80211_TESTMODE is not set
+# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set
+# CONFIG_CFG80211_REG_DEBUG is not set
+# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
+CONFIG_CFG80211_DEFAULT_PS=y
+# CONFIG_CFG80211_DEBUGFS is not set
+# CONFIG_CFG80211_INTERNAL_REGDB is not set
+CONFIG_CFG80211_WEXT=y
+# CONFIG_LIB80211 is not set
+CONFIG_MAC80211=m
+CONFIG_MAC80211_HAS_RC=y
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+CONFIG_MAC80211_RC_MINSTREL_HT=y
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel_ht"
+# CONFIG_MAC80211_MESH is not set
+CONFIG_MAC80211_LEDS=y
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_MESSAGE_TRACING is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+# CONFIG_WIMAX is not set
+CONFIG_RFKILL=m
+CONFIG_RFKILL_LEDS=y
+CONFIG_RFKILL_INPUT=y
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+# CONFIG_CEPH_LIB is not set
+# CONFIG_NFC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_GENERIC_CPU_DEVICES is not set
+CONFIG_DMA_SHARED_BUFFER=y
+# CONFIG_CMA is not set
+
+#
+# Bus devices
+#
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLKDEVS=m
+CONFIG_MTD_BLOCK=m
+# 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_TS5500 is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_DATAFLASH is not set
+CONFIG_MTD_M25P80=m
+CONFIG_M25PXX_USE_FAST_READ=y
+# 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_MTD_CLN_ROM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOCG3 is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+
+#
+# Protocols
+#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_PCIESSD_MTIP32XX is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=2
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_NVME is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=81920
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_BLK_DEV_RBD is not set
+
+#
+# Misc devices
+#
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_IBM_ASM is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_INTEL_MID_PTI is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_APDS9802ALS is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_ISL29020 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_SENSORS_BH1780 is not set
+# CONFIG_SENSORS_BH1770 is not set
+# CONFIG_SENSORS_APDS990X is not set
+# CONFIG_HMC6352 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_VMWARE_BALLOON is not set
+# CONFIG_BMP085_I2C is not set
+# CONFIG_BMP085_SPI is not set
+# CONFIG_PCH_PHUB is not set
+# CONFIG_USB_SWITCH_FSA9480 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=m
+# 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_EEPROM_93XX46 is not set
+# CONFIG_CB710_CORE is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+# CONFIG_TI_ST is not set
+# CONFIG_SENSORS_LIS3_I2C is not set
+
+#
+# Altera FPGA firmware download module
+#
+# CONFIG_ALTERA_STAPL 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 is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_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_TARGET_CORE is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_FIREWIRE_NOSY is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_NET_CORE=y
+# CONFIG_BONDING is not set
+# CONFIG_DUMMY is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_NET_FC is not set
+CONFIG_MII=y
+# CONFIG_NET_TEAM is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_VXLAN is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+
+#
+# CAIF transport drivers
+#
+
+#
+# Distributed Switch Architecture drivers
+#
+# CONFIG_NET_DSA_MV88E6XXX is not set
+# CONFIG_NET_DSA_MV88E6060 is not set
+# CONFIG_NET_DSA_MV88E6XXX_NEED_PPU is not set
+# CONFIG_NET_DSA_MV88E6131 is not set
+# CONFIG_NET_DSA_MV88E6123_61_65 is not set
+CONFIG_ETHERNET=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+CONFIG_NET_CADENCE=y
+# CONFIG_ARM_AT91_ETHER is not set
+# CONFIG_MACB is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_CALXEDA_XGMAC is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_VENDOR_DEC is not set
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+# CONFIG_NET_VENDOR_EXAR is not set
+# CONFIG_NET_VENDOR_HP is not set
+CONFIG_NET_VENDOR_INTEL=y
+# CONFIG_E100 is not set
+CONFIG_E1000=m
+# CONFIG_E1000E is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_IXGB is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGBEVF is not set
+# CONFIG_NET_VENDOR_I825XX is not set
+# CONFIG_IP1000 is not set
+# CONFIG_JME is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_ETHOC is not set
+# CONFIG_NET_PACKET_ENGINE is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_SFC is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+CONFIG_NET_VENDOR_STMICRO=y
+CONFIG_STMMAC_ETH=m
+# CONFIG_STMMAC_PLATFORM is not set
+CONFIG_STMMAC_PCI=y
+# CONFIG_STMMAC_DEBUG_FS is not set
+CONFIG_STMMAC_DA=y
+# CONFIG_STMMAC_PTP is not set
+CONFIG_STMMAC_RING=y
+# CONFIG_STMMAC_CHAINED is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_NET_SB1000 is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_AT803X_PHY is not set
+# CONFIG_AMD_PHY is not set
+# 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 is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_BCM87XX_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_MICREL_KS8995MA is not set
+CONFIG_PPP=m
+# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPP_DEFLATE=m
+# CONFIG_PPP_FILTER is not set
+# CONFIG_PPP_MPPE is not set
+# CONFIG_PPP_MULTILINK is not set
+# CONFIG_PPPOE is not set
+CONFIG_PPP_ASYNC=m
+# CONFIG_PPP_SYNC_TTY is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+
+#
+# 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_HSO is not set
+# CONFIG_USB_IPHETH is not set
+CONFIG_WLAN=y
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AIRO is not set
+# CONFIG_ATMEL is not set
+# CONFIG_AT76C50X_USB is not set
+# CONFIG_PRISM54 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8180 is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_ADM8211 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_MWL8K is not set
+# CONFIG_ATH_CARDS is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_BRCMFMAC is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+CONFIG_IWLWIFI=m
+CONFIG_IWLDVM=m
+
+#
+# Debugging Options
+#
+# CONFIG_IWLWIFI_DEBUG is not set
+CONFIG_IWLWIFI_P2P=y
+# CONFIG_IWL4965 is not set
+# CONFIG_IWL3945 is not set
+# CONFIG_LIBERTAS is not set
+# CONFIG_HERMES is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_RT2X00 is not set
+# CONFIG_RTL8192CE is not set
+# CONFIG_RTL8192SE is not set
+# CONFIG_RTL8192DE is not set
+# CONFIG_RTL8723AE is not set
+# CONFIG_RTL8192CU is not set
+# CONFIG_WL_TI is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_MWIFIEX is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN 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
+# CONFIG_INPUT_MATRIXKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=m
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_CONSOLE_SLEEP=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=32
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_SYNCLINK is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_NOZOMI is not set
+# CONFIG_ISI is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_N_GSM is not set
+# CONFIG_TRACE_SINK is not set
+CONFIG_DEVKMEM=y
+# CONFIG_STALDRV is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_PNP is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+# CONFIG_SERIAL_MAX310X is not set
+# CONFIG_SERIAL_MFD_HSU is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_SCCNXP is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+# CONFIG_SERIAL_IFX6X60 is not set
+# CONFIG_SERIAL_CLN_UART is not set
+# CONFIG_SERIAL_PCH_UART is not set
+# CONFIG_SERIAL_ARC is not set
+# CONFIG_TTY_PRINTK is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+CONFIG_RTC=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_SONYPI is not set
+# CONFIG_MWAVE is not set
+# CONFIG_PC8736x_GPIO is not set
+# CONFIG_NSC_GPIO is not set
+# CONFIG_RAW_DRIVER is not set
+CONFIG_HPET=y
+# CONFIG_HPET_MMAP is not set
+# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=m
+# CONFIG_I2C_MUX is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# ACPI drivers
+#
+# CONFIG_I2C_SCMI is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_CBUS_GPIO is not set
+# CONFIG_I2C_EG20T is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_INTEL_MID is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_PXA_PCI is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_DIOLAN_U2C is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_SCx200_ACB is not set
+# CONFIG_I2C_STUB is not set
+# 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_DEBUG=y
+CONFIG_GEN3_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_ALTERA is not set
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+# CONFIG_SPI_OC_TINY is not set
+CONFIG_SPI_PXA2XX=m
+CONFIG_SPI_PXA2XX_PCI=m
+# CONFIG_SPI_CE5XX_SPI_SLAVE is not set
+# CONFIG_SPI_SC18IS602 is not set
+# CONFIG_SPI_TOPCLIFF_PCH is not set
+# CONFIG_SPI_XCOMM is not set
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+# CONFIG_SPI_LPC_SCH is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+# CONFIG_HSI is not set
+
+#
+# PPS support
+#
+CONFIG_PPS=m
+# CONFIG_PPS_DEBUG is not set
+
+#
+# PPS clients support
+#
+# CONFIG_PPS_CLIENT_KTIMER is not set
+# CONFIG_PPS_CLIENT_LDISC is not set
+# CONFIG_PPS_CLIENT_GPIO is not set
+
+#
+# PPS generators support
+#
+
+#
+# PTP clock support
+#
+CONFIG_PTP_1588_CLOCK=m
+
+#
+# Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks.
+#
+CONFIG_PTP_1588_CLOCK_PCH=m
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_ACPI=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO drivers:
+#
+# CONFIG_GPIO_GENERIC_PLATFORM is not set
+# CONFIG_GPIO_IT8761E is not set
+# CONFIG_GPIO_TS5500 is not set
+CONFIG_GPIO_SCH=m
+# CONFIG_GPIO_ICH is not set
+# CONFIG_GPIO_VX855 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:
+#
+# CONFIG_GPIO_BT8XX is not set
+# CONFIG_GPIO_AMD8111 is not set
+# CONFIG_GPIO_LANGWELL is not set
+# CONFIG_GPIO_PCH is not set
+# CONFIG_GPIO_ML_IOH is not set
+# CONFIG_GPIO_RDC321X is not set
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+# CONFIG_GPIO_74X164 is not set
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
+
+#
+# USB GPIO expanders:
+#
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_GENERIC_ADC_BATTERY is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2780 is not set
+# CONFIG_BATTERY_DS2781 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_SBS is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_BATTERY_MAX17042 is not set
+# CONFIG_CHARGER_MAX8903 is not set
+# CONFIG_CHARGER_LP8727 is not set
+# CONFIG_CHARGER_GPIO is not set
+# CONFIG_CHARGER_BQ2415X is not set
+# CONFIG_CHARGER_SMB347 is not set
+# CONFIG_POWER_RESET is not set
+# CONFIG_POWER_AVS is not set
+# CONFIG_HWMON is not set
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
+# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
+# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
+# CONFIG_FAIR_SHARE is not set
+CONFIG_STEP_WISE=y
+# CONFIG_USER_SPACE is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+CONFIG_BCMA_POSSIBLE=y
+
+#
+# Broadcom specific AMBA
+#
+# CONFIG_BCMA is not set
+
+#
+# Multifunction device drivers
+#
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_RTSX_PCI is not set
+# CONFIG_MFD_TI_AM335X_TSCADC is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_LM3533 is not set
+# CONFIG_TPS6105X is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_MFD_TPS65217 is not set
+# CONFIG_MFD_TPS65912_SPI is not set
+# CONFIG_MFD_STMPE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_DA9052_SPI is not set
+# CONFIG_MFD_ARIZONA_I2C is not set
+# CONFIG_MFD_ARIZONA_SPI is not set
+# CONFIG_MFD_WM831X_SPI is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13XXX_SPI is not set
+# CONFIG_MFD_MC13XXX_I2C is not set
+# CONFIG_ABX500_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_CS5535 is not set
+# CONFIG_MFD_TIMBERDALE is not set
+CONFIG_CY8C9540A=m
+CONFIG_INTEL_CLN_GIP=m
+CONFIG_LPC_SCH=y
+# CONFIG_LPC_ICH is not set
+# CONFIG_MFD_RDC321X is not set
+# CONFIG_MFD_JANZ_CMODIO is not set
+# CONFIG_MFD_VX855 is not set
+# CONFIG_MFD_WL1273_CORE is not set
+# CONFIG_MFD_VIPERBOARD is not set
+# CONFIG_MFD_RETU is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=m
+
+#
+# Multimedia core support
+#
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
+# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
+# CONFIG_MEDIA_RADIO_SUPPORT is not set
+# CONFIG_MEDIA_RC_SUPPORT is not set
+# CONFIG_MEDIA_CONTROLLER is not set
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2=m
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEOBUF2_CORE=m
+CONFIG_VIDEOBUF2_MEMOPS=m
+CONFIG_VIDEOBUF2_VMALLOC=m
+
+#
+# Media drivers
+#
+CONFIG_MEDIA_USB_SUPPORT=y
+
+#
+# Webcam devices
+#
+CONFIG_USB_VIDEO_CLASS=m
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+# CONFIG_USB_GSPCA is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_USB_SN9C102 is not set
+
+#
+# Webcam, TV (analog/digital) USB devices
+#
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_MEDIA_PCI_SUPPORT is not set
+# CONFIG_V4L_PLATFORM_DRIVERS is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_V4L_TEST_DRIVERS is not set
+
+#
+# Supported MMC/SDIO adapters
+#
+# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
+
+#
+# Media ancillary drivers (tuners, sensors, i2c, frontends)
+#
+
+#
+# Encoders, decoders, sensors and other helper chips
+#
+
+#
+# Audio decoders, processors and mixers
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_ADV7183 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_TVP7002 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+# CONFIG_VIDEO_ADV7393 is not set
+# CONFIG_VIDEO_AK881X is not set
+
+#
+# Camera sensor devices
+#
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_VS6624 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SR030PC30 is not set
+
+#
+# Flash devices
+#
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+
+#
+# Miscelaneous helper chips
+#
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_M52790 is not set
+
+#
+# Sensors used on soc_camera driver
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_AU8522_V4L is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+
+#
+# Tools to develop new frontends
+#
+# CONFIG_DVB_DUMMY_FE is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_VGA_ARB is not set
+# CONFIG_VGA_SWITCHEROO is not set
+# CONFIG_DRM is not set
+# CONFIG_STUB_POULSBO is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_EXYNOS_VIDEO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=m
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_HWDEP=m
+CONFIG_SND_RAWMIDI=m
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_RTCTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DMA_SGBUF=y
+# 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=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_ALOOP is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+# CONFIG_SND_ALS4000 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ASIHPI is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_CS5535AUDIO is not set
+# CONFIG_SND_CTXFI is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_INDIGOIOX is not set
+# CONFIG_SND_INDIGODJX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_LOLA is not set
+# CONFIG_SND_LX6464ES is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SIS7019 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+CONFIG_SND_USB_AUDIO=m
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_USB_US122L is not set
+# CONFIG_SND_USB_6FIRE is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+
+#
+# HID support
+#
+CONFIG_HID=y
+# CONFIG_HID_BATTERY_STRENGTH is not set
+# CONFIG_HIDRAW is not set
+# CONFIG_UHID is not set
+CONFIG_HID_GENERIC=y
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_ACRUX is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_AUREAL is not set
+# CONFIG_HID_BELKIN 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_EMS_FF is not set
+# CONFIG_HID_ELECOM is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_HOLTEK is not set
+# CONFIG_HID_KEYTOUCH is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_UCLOGIC is not set
+# CONFIG_HID_WALTOP is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_ICADE is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LCPOWER is not set
+# CONFIG_HID_LENOVO_TPKBD is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MAGICMOUSE is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_MULTITOUCH 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_PRIMAX is not set
+# CONFIG_HID_PS3REMOTE is not set
+# CONFIG_HID_ROCCAT is not set
+# CONFIG_HID_SAITEK is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SPEEDLINK is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TIVO is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_WACOM is not set
+# CONFIG_HID_WIIMOTE is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+# CONFIG_HID_SENSOR_HUB is not set
+
+#
+# USB HID support
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+
+#
+# I2C HID support
+#
+# CONFIG_I2C_HID is not set
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB_ARCH_HAS_XHCI=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_COMMON=m
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_DWC3 is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_XHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+CONFIG_USB_EHCI_PCI=m
+# 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_OHCI_HCD=m
+# CONFIG_USB_OHCI_HCD_PLATFORM is not set
+# CONFIG_USB_EHCI_HCD_PLATFORM is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_CHIPIDEA is not set
+# CONFIG_USB_RENESAS_USBHS is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+# 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=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_REALTEK 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_STORAGE_ENE_UB6250 is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP210X is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_F81232 is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_METRO is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_QCAUX is not set
+# CONFIG_USB_SERIAL_QUALCOMM is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_SYMBOL is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set
+# CONFIG_USB_SERIAL_ZIO is not set
+# CONFIG_USB_SERIAL_ZTE is not set
+# CONFIG_USB_SERIAL_SSU100 is not set
+# CONFIG_USB_SERIAL_QT2 is not set
+# CONFIG_USB_SERIAL_DEBUG 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_YUREX is not set
+# CONFIG_USB_EZUSB_FX2 is not set
+
+#
+# USB Physical Layer drivers
+#
+# CONFIG_USB_ISP1301 is not set
+# CONFIG_USB_RCAR_PHY is not set
+CONFIG_USB_GADGET=m
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=2
+CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2
+
+#
+# USB Peripheral Controller
+#
+# CONFIG_USB_R8A66597 is not set
+# CONFIG_USB_MV_UDC is not set
+# CONFIG_USB_M66592 is not set
+# CONFIG_USB_AMD5536UDC is not set
+# CONFIG_USB_NET2272 is not set
+# CONFIG_USB_NET2280 is not set
+# CONFIG_USB_GOKU is not set
+CONFIG_USB_EG20T=m
+# CONFIG_USB_DUMMY_HCD is not set
+CONFIG_USB_LIBCOMPOSITE=m
+CONFIG_USB_ZERO=m
+# CONFIG_USB_AUDIO is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_ETH_EEM is not set
+# CONFIG_USB_G_NCM is not set
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FUNCTIONFS is not set
+CONFIG_USB_MASS_STORAGE=m
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_CDC_COMPOSITE is not set
+# CONFIG_USB_G_ACM_MS is not set
+# CONFIG_USB_G_MULTI is not set
+# CONFIG_USB_G_HID is not set
+# CONFIG_USB_G_DBGP is not set
+# CONFIG_USB_G_WEBCAM is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_UWB is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_CLKGATE is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_MINORS=8
+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_PCI=y
+# CONFIG_MMC_RICOH_MMC is not set
+# CONFIG_MMC_SDHCI_ACPI is not set
+CONFIG_MMC_SDHCI_PLTFM=y
+# CONFIG_MMC_WBSD is not set
+# CONFIG_MMC_TIFM_SD is not set
+# CONFIG_MMC_CB710 is not set
+# CONFIG_MMC_VIA_SDMMC is not set
+# CONFIG_MMC_VUB300 is not set
+# CONFIG_MMC_USHC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=m
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_LM3530 is not set
+# CONFIG_LEDS_LM3642 is not set
+# CONFIG_LEDS_PCA9532 is not set
+# CONFIG_LEDS_GPIO is not set
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_LP5521 is not set
+# CONFIG_LEDS_LP5523 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_PCA9633 is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+# CONFIG_LEDS_TCA6507 is not set
+# CONFIG_LEDS_LM355x is not set
+# CONFIG_LEDS_OT200 is not set
+# CONFIG_LEDS_BLINKM is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_ONESHOT is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_CPU is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_LEDS_TRIGGER_TRANSIENT is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_INTEL_MID_DMAC=m
+CONFIG_INTEL_MID_PCI=m
+CONFIG_INTEL_CLN_DMAC=m
+# CONFIG_INTEL_IOATDMA is not set
+# CONFIG_TIMB_DMA is not set
+# CONFIG_PCH_DMA is not set
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+CONFIG_UIO=m
+# CONFIG_UIO_CIF is not set
+# CONFIG_UIO_PDRV is not set
+# CONFIG_UIO_PDRV_GENIRQ is not set
+# CONFIG_UIO_DMEM_GENIRQ is not set
+# CONFIG_UIO_AEC is not set
+# CONFIG_UIO_SERCOS3 is not set
+# CONFIG_UIO_PCI_GENERIC is not set
+# CONFIG_UIO_NETX is not set
+
+#
+# Virtio drivers
+#
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_MMIO is not set
+
+#
+# Microsoft Hyper-V guest support
+#
+# CONFIG_HYPERV is not set
+CONFIG_STAGING=y
+# CONFIG_ET131X is not set
+# CONFIG_SLICOSS is not set
+# CONFIG_USBIP_CORE is not set
+# CONFIG_W35UND is not set
+# CONFIG_PRISM2_USB is not set
+# CONFIG_ECHO is not set
+# CONFIG_COMEDI is not set
+# CONFIG_ASUS_OLED is not set
+# CONFIG_R8187SE is not set
+# CONFIG_RTL8192U is not set
+# CONFIG_RTLLIB is not set
+# CONFIG_R8712U is not set
+# CONFIG_RTS5139 is not set
+# CONFIG_TRANZPORT is not set
+# CONFIG_LINE6_USB is not set
+# CONFIG_USB_SERIAL_QUATECH2 is not set
+# CONFIG_VT6655 is not set
+# CONFIG_VT6656 is not set
+# CONFIG_DX_SEP is not set
+
+#
+# IIO staging drivers
+#
+# CONFIG_IIO_SW_RING is not set
+
+#
+# Accelerometers
+#
+# CONFIG_ADIS16201 is not set
+# CONFIG_ADIS16203 is not set
+# CONFIG_ADIS16204 is not set
+# CONFIG_ADIS16209 is not set
+# CONFIG_ADIS16220 is not set
+# CONFIG_ADIS16240 is not set
+# CONFIG_KXSD9 is not set
+# CONFIG_LIS3L02DQ is not set
+# CONFIG_SCA3000 is not set
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7291 is not set
+# CONFIG_AD7606 is not set
+# CONFIG_AD799X is not set
+# CONFIG_AD7780 is not set
+# CONFIG_AD7816 is not set
+# CONFIG_AD7192 is not set
+# CONFIG_ADT7410 is not set
+# CONFIG_AD7280 is not set
+CONFIG_MAX78M6610_LMU=m
+
+#
+# Analog digital bi-direction converters
+#
+# CONFIG_ADT7316 is not set
+
+#
+# Capacitance to digital converters
+#
+# CONFIG_AD7150 is not set
+# CONFIG_AD7152 is not set
+# CONFIG_AD7746 is not set
+
+#
+# Direct Digital Synthesis
+#
+# CONFIG_AD5930 is not set
+# CONFIG_AD9832 is not set
+# CONFIG_AD9834 is not set
+# CONFIG_AD9850 is not set
+# CONFIG_AD9852 is not set
+# CONFIG_AD9910 is not set
+# CONFIG_AD9951 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16060 is not set
+# CONFIG_ADIS16080 is not set
+# CONFIG_ADIS16130 is not set
+# CONFIG_ADIS16260 is not set
+# CONFIG_ADXRS450 is not set
+
+#
+# Network Analyzer, Impedance Converters
+#
+# CONFIG_AD5933 is not set
+
+#
+# Inertial measurement units
+#
+# CONFIG_ADIS16400 is not set
+
+#
+# Light sensors
+#
+# CONFIG_SENSORS_ISL29018 is not set
+# CONFIG_SENSORS_ISL29028 is not set
+# CONFIG_SENSORS_TSL2563 is not set
+# CONFIG_TSL2583 is not set
+# CONFIG_TSL2x7x is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_SENSORS_AK8975 is not set
+# CONFIG_SENSORS_HMC5843 is not set
+
+#
+# Active energy metering IC
+#
+# CONFIG_ADE7753 is not set
+# CONFIG_ADE7754 is not set
+# CONFIG_ADE7758 is not set
+# CONFIG_ADE7759 is not set
+# CONFIG_ADE7854 is not set
+
+#
+# Resolver to digital converters
+#
+# CONFIG_AD2S90 is not set
+# CONFIG_AD2S1200 is not set
+# CONFIG_AD2S1210 is not set
+
+#
+# Triggers - standalone
+#
+# CONFIG_IIO_GPIO_TRIGGER is not set
+CONFIG_IIO_SYSFS_TRIGGER=m
+# CONFIG_IIO_SIMPLE_DUMMY is not set
+# CONFIG_ZSMALLOC is not set
+# CONFIG_CRYSTALHD is not set
+# CONFIG_ACPI_QUICKSTART is not set
+# CONFIG_USB_ENESTORAGE is not set
+# CONFIG_BCM_WIMAX is not set
+# CONFIG_FT1000 is not set
+
+#
+# Speakup console speech
+#
+# CONFIG_SPEAKUP is not set
+# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set
+# CONFIG_STAGING_MEDIA is not set
+
+#
+# Android
+#
+# CONFIG_ANDROID is not set
+# CONFIG_USB_WPAN_HCD is not set
+# CONFIG_WIMAX_GDM72XX is not set
+# CONFIG_CSR_WIFI is not set
+# CONFIG_NET_VENDOR_SILICOM is not set
+# CONFIG_CED1401 is not set
+# CONFIG_DGRP is not set
+# CONFIG_SB105X is not set
+CONFIG_X86_PLATFORM_DEVICES=y
+# CONFIG_ACERHDF is not set
+# CONFIG_ASUS_LAPTOP is not set
+# CONFIG_FUJITSU_TABLET is not set
+# CONFIG_AMILO_RFKILL is not set
+# CONFIG_HP_ACCEL is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_THINKPAD_ACPI is not set
+# CONFIG_SENSORS_HDAPS is not set
+# CONFIG_INTEL_MENLOW is not set
+# CONFIG_ACPI_WMI is not set
+# CONFIG_TOPSTAR_LAPTOP is not set
+# CONFIG_TOSHIBA_BT_RFKILL is not set
+# CONFIG_ACPI_CMPC is not set
+CONFIG_INTEL_CLN_ESRAM=y
+CONFIG_INTEL_CLN_ECC_REFRESH_PERIOD=24
+CONFIG_INTEL_CLN_ECC_SCRUB=y
+# CONFIG_INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG is not set
+# CONFIG_INTEL_CLN_ECC_SCRUB_S3_CONFIG is not set
+CONFIG_INTEL_CLN_THERMAL=y
+CONFIG_INTEL_CLN_AUDIO_CTRL=m
+# CONFIG_INTEL_IPS is not set
+# CONFIG_IBM_RTL is not set
+# CONFIG_XO15_EBOOK is not set
+
+#
+# Hardware Spinlock drivers
+#
+CONFIG_CLKSRC_I8253=y
+CONFIG_CLKEVT_I8253=y
+CONFIG_CLKBLD_I8253=y
+# CONFIG_IOMMU_SUPPORT is not set
+
+#
+# Remoteproc drivers (EXPERIMENTAL)
+#
+# CONFIG_STE_MODEM_RPROC is not set
+
+#
+# Rpmsg drivers (EXPERIMENTAL)
+#
+# CONFIG_VIRT_DRIVERS is not set
+# CONFIG_PM_DEVFREQ is not set
+# CONFIG_EXTCON is not set
+# CONFIG_MEMORY is not set
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER=y
+CONFIG_IIO_BUFFER_CB=y
+CONFIG_IIO_KFIFO_BUF=m
+CONFIG_IIO_TRIGGERED_BUFFER=m
+CONFIG_IIO_TRIGGER=y
+CONFIG_IIO_CONSUMERS_PER_TRIGGER=2
+
+#
+# Accelerometers
+#
+CONFIG_IIO_LIS331DLH_INTEL_CLN=m
+
+#
+# Analog to digital converters
+#
+# CONFIG_AD7266 is not set
+CONFIG_AD7298=m
+# CONFIG_AD7791 is not set
+# CONFIG_AD7793 is not set
+# CONFIG_AD7476 is not set
+# CONFIG_AD7887 is not set
+# CONFIG_MAX1363 is not set
+# CONFIG_TI_ADC081C is not set
+
+#
+# Amplifiers
+#
+# CONFIG_AD8366 is not set
+
+#
+# STMicro sensors
+#
+CONFIG_IIO_ST_SENSORS_I2C=m
+CONFIG_IIO_ST_SENSORS_SPI=m
+CONFIG_IIO_ST_SENSORS_CORE=m
+
+#
+# Digital to analog converters
+#
+# CONFIG_AD5064 is not set
+# CONFIG_AD5360 is not set
+# CONFIG_AD5380 is not set
+# CONFIG_AD5421 is not set
+# CONFIG_AD5624R_SPI is not set
+# CONFIG_AD5446 is not set
+# CONFIG_AD5449 is not set
+# CONFIG_AD5504 is not set
+# CONFIG_AD5755 is not set
+# CONFIG_AD5764 is not set
+# CONFIG_AD5791 is not set
+# CONFIG_AD5686 is not set
+# CONFIG_MAX517 is not set
+# CONFIG_MCP4725 is not set
+
+#
+# Frequency Synthesizers DDS/PLL
+#
+
+#
+# Clock Generator/Distribution
+#
+# CONFIG_AD9523 is not set
+
+#
+# Phase-Locked Loop (PLL) frequency synthesizers
+#
+# CONFIG_ADF4350 is not set
+
+#
+# Digital gyroscope sensors
+#
+# CONFIG_ADIS16136 is not set
+
+#
+# Inertial measurement units
+#
+# CONFIG_ADIS16480 is not set
+
+#
+# Light sensors
+#
+# CONFIG_ADJD_S311 is not set
+# CONFIG_VCNL4000 is not set
+
+#
+# Magnetometer sensors
+#
+# CONFIG_VME_BUS is not set
+CONFIG_PWM=y
+CONFIG_PWM_SYSFS=y
+# CONFIG_IPACK_BUS is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_EDD is not set
+CONFIG_FIRMWARE_MEMMAP=y
+CONFIG_EFI_VARS=m
+# CONFIG_DELL_RBU is not set
+# CONFIG_DCDBAS is not set
+# CONFIG_ISCSI_IBFT_FIND is not set
+# CONFIG_GOOGLE_FIRMWARE is not set
+
+#
+# File systems
+#
+CONFIG_DCACHE_WORD_ACCESS=y
+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=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_FANOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_QUOTACTL is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
+
+#
+# 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 is not set
+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_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD 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
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="utf8"
+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 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# 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_MAC_ROMAN is not set
+# CONFIG_NLS_MAC_CELTIC is not set
+# CONFIG_NLS_MAC_CENTEURO is not set
+# CONFIG_NLS_MAC_CROATIAN is not set
+# CONFIG_NLS_MAC_CYRILLIC is not set
+# CONFIG_NLS_MAC_GAELIC is not set
+# CONFIG_NLS_MAC_GREEK is not set
+# CONFIG_NLS_MAC_ICELAND is not set
+# CONFIG_NLS_MAC_INUIT is not set
+# CONFIG_NLS_MAC_ROMANIAN is not set
+# CONFIG_NLS_MAC_TURKISH is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_READABLE_ASM is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+CONFIG_HEADERS_CHECK=y
+# CONFIG_DEBUG_SECTION_MISMATCH is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_LOCKUP_DETECTOR is not set
+# CONFIG_PANIC_ON_OOPS is not set
+CONFIG_PANIC_ON_OOPS_VALUE=0
+# CONFIG_DETECT_HUNG_TASK is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_LOCK_ALLOC=y
+CONFIG_PROVE_LOCKING=y
+# CONFIG_PROVE_RCU is not set
+# CONFIG_SPARSE_RCU_POINTER is not set
+CONFIG_LOCKDEP=y
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_LOCKDEP is not set
+CONFIG_TRACE_IRQFLAGS=y
+# CONFIG_DEBUG_ATOMIC_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_VIRTUAL is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_TEST_LIST_SORT is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_ARCH_WANT_FRAME_POINTERS=y
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_TRACE is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_LKDTM is not set
+# CONFIG_NOTIFIER_ERROR_INJECTION is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_USER_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST=y
+CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_RBTREE_TEST is not set
+# CONFIG_INTERVAL_TREE_TEST is not set
+# CONFIG_PROVIDE_OHCI1394_DMA_INIT is not set
+# CONFIG_BUILD_DOCSRC is not set
+# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_HAVE_ARCH_KMEMCHECK=y
+# CONFIG_KMEMCHECK is not set
+# CONFIG_TEST_KSTRTOX is not set
+# CONFIG_STRICT_DEVMEM is not set
+CONFIG_X86_VERBOSE_BOOTUP=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_EARLY_PRINTK_DBGP is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_X86_PTDUMP=y
+CONFIG_DEBUG_RODATA=y
+# CONFIG_DEBUG_RODATA_TEST is not set
+CONFIG_DEBUG_SET_MODULE_RONX=y
+# CONFIG_DEBUG_NX_TEST is not set
+# CONFIG_DOUBLEFAULT is not set
+# CONFIG_IOMMU_STRESS is not set
+CONFIG_HAVE_MMIOTRACE_SUPPORT=y
+CONFIG_IO_DELAY_TYPE_0X80=0
+CONFIG_IO_DELAY_TYPE_0XED=1
+CONFIG_IO_DELAY_TYPE_UDELAY=2
+CONFIG_IO_DELAY_TYPE_NONE=3
+CONFIG_IO_DELAY_0X80=y
+# CONFIG_IO_DELAY_0XED is not set
+# CONFIG_IO_DELAY_UDELAY is not set
+# CONFIG_IO_DELAY_NONE is not set
+CONFIG_DEFAULT_IO_DELAY_TYPE=0
+CONFIG_DEBUG_BOOT_PARAMS=y
+# CONFIG_CPA_DEBUG is not set
+CONFIG_OPTIMIZE_INLINING=y
+# CONFIG_DEBUG_STRICT_USER_COPY_CHECKS is not set
+# CONFIG_DEBUG_NMI_SELFTEST is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_ENCRYPTED_KEYS is not set
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY_DMESG_RESTRICT is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_SMACK is not set
+# CONFIG_SECURITY_TOMOYO is not set
+# CONFIG_SECURITY_APPARMOR is not set
+# CONFIG_SECURITY_YAMA is not set
+# CONFIG_IMA is not set
+# CONFIG_EVM 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_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP2=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_USER is not set
+CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST 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=m
+# 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=y
+# CONFIG_CRYPTO_CRC32C_INTEL 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=m
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_AES_586 is not set
+# CONFIG_CRYPTO_AES_NI_INTEL is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# 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_SALSA20_586 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_SERPENT_SSE2_586 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_TWOFISH_586 is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+# CONFIG_CRYPTO_USER_API_HASH is not set
+# CONFIG_CRYPTO_USER_API_SKCIPHER is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_PADLOCK is not set
+# CONFIG_CRYPTO_DEV_GEODE is not set
+# CONFIG_ASYMMETRIC_KEY_TYPE is not set
+CONFIG_HAVE_KVM=y
+# CONFIG_VIRTUALIZATION is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_IO=y
+CONFIG_PERCPU_RWSEM=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC32_SELFTEST is not set
+CONFIG_CRC32_SLICEBY8=y
+# CONFIG_CRC32_SLICEBY4 is not set
+# CONFIG_CRC32_SARWATE is not set
+# CONFIG_CRC32_BIT is not set
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+# CONFIG_CRC8 is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=m
+# CONFIG_XZ_DEC is not set
+# CONFIG_XZ_DEC_BCJ is not set
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_DQL=y
+CONFIG_NLATTR=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_AVERAGE=y
+# CONFIG_CORDIC is not set
+# CONFIG_DDR is not set
diff --git a/recipes-kernel/linux/files/clanton.patch b/recipes-kernel/linux/files/clanton.patch
new file mode 100644
index 0000000..437b591
--- /dev/null
+++ b/recipes-kernel/linux/files/clanton.patch
@@ -0,0 +1,30644 @@
+diff --git a/.gitignore b/.gitignore
+index 3b8b9b3..3557999 100644
+--- a/.gitignore
++++ b/.gitignore
+@@ -64,11 +64,11 @@ include/generated
+ arch/*/include/generated
+
+ # stgit generated dirs
+-patches-*
++#patches-*
+
+ # quilt's files
+-patches
+-series
++#patches
++#series
+
+ # cscope files
+ cscope.*
+diff --git a/Documentation/ABI/testing/sysfs-class-pwm b/Documentation/ABI/testing/sysfs-class-pwm
+new file mode 100644
+index 0000000..c479d77
+--- /dev/null
++++ b/Documentation/ABI/testing/sysfs-class-pwm
+@@ -0,0 +1,79 @@
++What: /sys/class/pwm/
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ The pwm/ class sub-directory belongs to the Generic PWM
++ Framework and provides a sysfs interface for using PWM
++ channels.
++
++What: /sys/class/pwm/pwmchipN/
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ A /sys/class/pwm/pwmchipN directory is created for each
++ probed PWM controller/chip where N is the base of the
++ PWM chip.
++
++What: /sys/class/pwm/pwmchipN/npwm
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ The number of PWM channels supported by the PWM chip.
++
++What: /sys/class/pwm/pwmchipN/export
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Exports a PWM channel from the PWM chip for sysfs control.
++ Value is between 0 and /sys/class/pwm/pwmchipN/npwm - 1.
++
++What: /sys/class/pwm/pwmchipN/unexport
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Unexports a PWM channel.
++
++What: /sys/class/pwm/pwmchipN/pwmX
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ A /sys/class/pwm/pwmchipN/pwmX directory is created for
++ each exported PWM channel where X is the exported PWM
++ channel number.
++
++What: /sys/class/pwm/pwmchipN/pwmX/period
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the PWM signal period in nanoseconds.
++
++What: /sys/class/pwm/pwmchipN/pwmX/duty_cycle
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the PWM signal duty cycle in nanoseconds.
++
++What: /sys/class/pwm/pwmchipN/pwmX/polarity
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Sets the output polarity of the PWM signal to "normal" or
++ "inversed".
++
++What: /sys/class/pwm/pwmchipN/pwmX/enable
++Date: May 2013
++KernelVersion: 3.11
++Contact: H Hartley Sweeten <hsweeten@visionengravers.com>
++Description:
++ Enable/disable the PWM signal.
++ 0 is disabled
++ 1 is enabled
+diff --git a/Documentation/pwm.txt b/Documentation/pwm.txt
+index 7d2b4c9..1039b68 100644
+--- a/Documentation/pwm.txt
++++ b/Documentation/pwm.txt
+@@ -45,6 +45,43 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
+
+ To start/stop toggling the PWM output use pwm_enable()/pwm_disable().
+
++Using PWMs with the sysfs interface
++-----------------------------------
++
++If CONFIG_SYSFS is enabled in your kernel configuration a simple sysfs
++interface is provided to use the PWMs from userspace. It is exposed at
++/sys/class/pwm/. Each probed PWM controller/chip will be exported as
++pwmchipN, where N is the base of the PWM chip. Inside the directory you
++will find:
++
++npwm - The number of PWM channels this chip supports (read-only).
++
++export - Exports a PWM channel for use with sysfs (write-only).
++
++unexport - Unexports a PWM channel from sysfs (write-only).
++
++The PWM channels are numbered using a per-chip index from 0 to npwm-1.
++
++When a PWM channel is exported a pwmX directory will be created in the
++pwmchipN directory it is associated with, where X is the number of the
++channel that was exported. The following properties will then be available:
++
++period - The total period of the PWM signal (read/write).
++ Value is in nanoseconds and is the sum of the active and inactive
++ time of the PWM.
++
++duty_cycle - The active time of the PWM signal (read/write).
++ Value is in nanoseconds and must be less than the period.
++
++polarity - Changes the polarity of the PWM signal (read/write).
++ Writes to this property only work if the PWM chip supports changing
++ the polarity. The polarity can only be changed if the PWM is not
++ enabled. Value is the string "normal" or "inversed".
++
++enable - Enable/disable the PWM signal (read/write).
++ 0 - disabled
++ 1 - enabled
++
+ Implementing a PWM driver
+ -------------------------
+
+diff --git a/Documentation/usb/linux-cdc-acm.inf b/Documentation/usb/linux-cdc-acm.inf
+index f0ffc27..e56f074 100644
+--- a/Documentation/usb/linux-cdc-acm.inf
++++ b/Documentation/usb/linux-cdc-acm.inf
+@@ -90,10 +90,10 @@ ServiceBinary=%12%\USBSER.sys
+ [SourceDisksFiles]
+ [SourceDisksNames]
+ [DeviceList]
+-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
+
+ [DeviceList.NTamd64]
+-%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00
++%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_1D6B&PID_0104&MI_02, USB\VID_1D6B&PID_0106&MI_00, USB\VID_8086&PID_BABE
+
+
+ ;------------------------------------------------------------------------------
+diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
+index 0694d09..7509992 100644
+--- a/arch/x86/Kconfig
++++ b/arch/x86/Kconfig
+@@ -417,6 +417,14 @@ config X86_INTEL_CE
+ This option compiles in support for the CE4100 SOC for settop
+ boxes and media devices.
+
++config INTEL_QUARK_X1000_SOC
++ bool "Intel Quark X1000 SOC support"
++ depends on M586TSC
++ select ARCH_REQUIRE_GPIOLIB
++ ---help---
++ Quark X1000 SOC support . This option enables probing for various
++ PCI-IDs of several on-chip devices provided by the X1000
++
+ config X86_WANT_INTEL_MID
+ bool "Intel MID platform support"
+ depends on X86_32
+@@ -500,6 +508,13 @@ config X86_SUPPORTS_MEMORY_FAILURE
+ depends on X86_64 || !SPARSEMEM
+ select ARCH_SUPPORTS_MEMORY_FAILURE
+
++menu "Intel Media SOC Gen3 support"
++
++config ARCH_GEN3
++ bool "Enable Intel Media SOC Gen3 support"
++ default y
++
++endmenu
+ config X86_VISWS
+ bool "SGI 320/540 (Visual Workstation)"
+ depends on X86_32 && PCI && X86_MPPARSE && PCI_GODIRECT
+@@ -1524,6 +1539,13 @@ config EFI_STUB
+
+ See Documentation/x86/efi-stub.txt for more information.
+
++config EFI_CAPSULE
++ bool "EFI capsule update support"
++ depends on EFI
++ ---help---
++ This kernel feature allows for loading of EFI capsule code
++ with callbacks into the EDK firmware to execute update
++
+ config SECCOMP
+ def_bool y
+ prompt "Enable seccomp to safely compute untrusted bytecode"
+diff --git a/arch/x86/include/asm/cln.h b/arch/x86/include/asm/cln.h
+new file mode 100644
+index 0000000..4a5b0e3
+--- /dev/null
++++ b/arch/x86/include/asm/cln.h
+@@ -0,0 +1,85 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++#ifndef _ASM_X86_CLN_H
++#define _ASM_X86_CLN_H
++
++#include <linux/pci.h>
++#include <linux/msi.h>
++
++/**
++ * cln_pci_pvm_mask
++ *
++ * Mask PVM bit on a per function basis. Clanton SC components have but one
++ * vector each - so we mask for what we need
++ */
++static inline void cln_pci_pvm_mask(struct pci_dev * dev)
++{
++ struct msi_desc *entry;
++ int mask_bits = 1;
++
++ if(unlikely(dev->msi_enabled == 0))
++ return;
++
++ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
++
++ if(unlikely(entry == NULL))
++ return;
++
++ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
++}
++
++/**
++ * cln_pci_pvm_mask
++ *
++ * UnMask PVM bit on a per function basis. Clanton SC components have but one
++ * vector each - so we unmask for what we need
++ */
++static inline void cln_pci_pvm_unmask(struct pci_dev * dev)
++{
++ struct msi_desc *entry;
++ int mask_bits = 0;
++
++ if(unlikely(dev->msi_enabled == 0))
++ return;
++
++ entry = list_first_entry(&dev->msi_list, struct msi_desc, list);
++
++ if(unlikely(entry == NULL))
++ return;
++
++ pci_write_config_dword(dev, entry->mask_pos, mask_bits);
++}
++
++/* Convienence macros */
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define mask_pvm(x) cln_pci_pvm_mask(x)
++ #define unmask_pvm(x) cln_pci_pvm_unmask(x)
++#else
++ #define mask_pvm(x)
++ #define unmask_pvm(x)
++#endif
++
++/* Serial */
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define SERIAL_PORT_DFNS
++ #define BASE_BAUD 2764800
++#endif
++
++#endif /* _ASM_X86_CLN_H */
+diff --git a/arch/x86/include/asm/imr.h b/arch/x86/include/asm/imr.h
+new file mode 100644
+index 0000000..2c17eec
+--- /dev/null
++++ b/arch/x86/include/asm/imr.h
+@@ -0,0 +1,22 @@
++/*
++ * imr.h: Intel Clanton platform imr setup code
++ *
++ * (C) Copyright 2012 Intel Corporation
++ *
++ * 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
++ * of the License.
++ */
++#ifndef _ASM_X86_IMR_H
++#define _ASM_X86_IMR_H
++
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ extern int intel_cln_imr_runt_setparams(void);
++ extern int intel_cln_imr_lockall(void);
++#else
++ static void intel_cln_imr_runt_setparams(void){}
++ static void intel_cln_imr_lockall(void){}
++#endif
++
++#endif /* _ASM_X86_IMR_H */
+diff --git a/arch/x86/include/asm/serial.h b/arch/x86/include/asm/serial.h
+index 628c801..3965f86 100644
+--- a/arch/x86/include/asm/serial.h
++++ b/arch/x86/include/asm/serial.h
+@@ -1,6 +1,8 @@
+ #ifndef _ASM_X86_SERIAL_H
+ #define _ASM_X86_SERIAL_H
+
++#include <asm/cln.h>
++
+ /*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ *
+@@ -8,7 +10,9 @@
+ * clock, since the 16550A is capable of handling a top speed of 1.5
+ * megabits/second; but this requires the faster clock.
+ */
++#ifndef BASE_BAUD
+ #define BASE_BAUD ( 1843200 / 16 )
++#endif
+
+ /* Standard COM flags (except for COM4, because of the 8514 problem) */
+ #ifdef CONFIG_SERIAL_DETECT_IRQ
+@@ -19,11 +23,13 @@
+ #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
+ #endif
+
++#ifndef SERIAL_PORT_DFNS
+ #define SERIAL_PORT_DFNS \
+ /* UART CLK PORT IRQ FLAGS */ \
+ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
+ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
+ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
+ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
++#endif
+
+ #endif /* _ASM_X86_SERIAL_H */
+diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
+index fcaabd0..ea7624c 100644
+--- a/arch/x86/kernel/cpu/intel.c
++++ b/arch/x86/kernel/cpu/intel.c
+@@ -143,6 +143,17 @@ static void __cpuinit early_init_intel(struct cpuinfo_x86 *c)
+ setup_clear_cpu_cap(X86_FEATURE_ERMS);
+ }
+ }
++
++ /*
++ * Quark X1000 PGE is advertised but not implemented. This matters since
++ * cpu_has_pge is used to determine the type of TLB flushing to do. With
++ * PGE not actually doing what it says on the tin writes to CR4.PGE do
++ * nothing when we should be re-writing CR3 like a 486
++ */
++ if (c->x86 == 5 && c->x86_model == 9){
++ printk(KERN_INFO "Disabling PGE capability bit\n");
++ setup_clear_cpu_cap(X86_FEATURE_PGE);
++ }
+ }
+
+ #ifdef CONFIG_X86_32
+diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
+index 8b24289..c963186 100644
+--- a/arch/x86/kernel/setup.c
++++ b/arch/x86/kernel/setup.c
+@@ -761,7 +761,10 @@ void __init setup_arch(char **cmdline_p)
+ KERNEL_PGD_PTRS);
+
+ load_cr3(swapper_pg_dir);
+- __flush_tlb_all();
++ if (boot_cpu_data.x86 == 5 && boot_cpu_data.x86_model == 9)
++ __flush_tlb();
++ else
++ __flush_tlb_all();
+ #else
+ printk(KERN_INFO "Command line: %s\n", boot_command_line);
+ #endif
+diff --git a/arch/x86/platform/efi/Makefile b/arch/x86/platform/efi/Makefile
+index 6db1cc4..41ac17c 100644
+--- a/arch/x86/platform/efi/Makefile
++++ b/arch/x86/platform/efi/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_EFI) += efi.o efi_$(BITS).o efi_stub_$(BITS).o
+-obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
++obj-$(CONFIG_ACPI_BGRT) += efi-bgrt.o
++obj-$(CONFIG_EFI_CAPSULE) += efi_capsule.o
+diff --git a/arch/x86/platform/efi/efi-bgrt.c b/arch/x86/platform/efi/efi-bgrt.c
+index d9c1b95..9fd5168 100644
+--- a/arch/x86/platform/efi/efi-bgrt.c
++++ b/arch/x86/platform/efi/efi-bgrt.c
+@@ -24,19 +24,29 @@ struct bmp_header {
+ u32 size;
+ } __packed;
+
+-void efi_bgrt_init(void)
++bool __init efi_bgrt_probe(void)
+ {
+ acpi_status status;
+- void __iomem *image;
+- bool ioremapped = false;
+- struct bmp_header bmp_header;
+
+ if (acpi_disabled)
+- return;
++ return false;
+
++ bgrt_tab = NULL;
+ status = acpi_get_table("BGRT", 0,
+ (struct acpi_table_header **)&bgrt_tab);
+ if (ACPI_FAILURE(status))
++ return false;
++
++ return true;
++}
++
++void __init efi_bgrt_init(void)
++{
++ void __iomem *image;
++ bool ioremapped = false;
++ struct bmp_header bmp_header;
++
++ if (acpi_disabled || bgrt_tab == NULL)
+ return;
+
+ if (bgrt_tab->header.length < sizeof(*bgrt_tab))
+diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
+index e2cd38f..0e22b5f4 100644
+--- a/arch/x86/platform/efi/efi.c
++++ b/arch/x86/platform/efi/efi.c
+@@ -847,6 +847,7 @@ void __init efi_enter_virtual_mode(void)
+ u64 end, systab, end_pfn;
+ void *p, *va, *new_memmap = NULL;
+ int count = 0;
++ bool bgrt_map;
+
+ efi.systab = NULL;
+
+@@ -860,6 +861,11 @@ void __init efi_enter_virtual_mode(void)
+ return;
+ }
+
++ /*
++ * Determine if mapping EFI boot code/data is required for BGRT mapping
++ */
++ bgrt_map = efi_bgrt_probe();
++
+ /* Merge contiguous regions of the same type and attribute */
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ u64 prev_size;
+@@ -889,9 +895,9 @@ void __init efi_enter_virtual_mode(void)
+
+ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) {
+ md = p;
+- if (!(md->attribute & EFI_MEMORY_RUNTIME) &&
+- md->type != EFI_BOOT_SERVICES_CODE &&
+- md->type != EFI_BOOT_SERVICES_DATA)
++ if (!((md->attribute & EFI_MEMORY_RUNTIME) || (bgrt_map &&
++ (md->type == EFI_BOOT_SERVICES_CODE ||
++ md->type == EFI_BOOT_SERVICES_DATA))))
+ continue;
+
+ size = md->num_pages << EFI_PAGE_SHIFT;
+diff --git a/arch/x86/platform/efi/efi_capsule.c b/arch/x86/platform/efi/efi_capsule.c
+new file mode 100644
+index 0000000..d329d6d
+--- /dev/null
++++ b/arch/x86/platform/efi/efi_capsule.c
+@@ -0,0 +1,320 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++#include <asm/cln.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/efi.h>
++
++#define DRIVER_NAME "efi_capsule_update"
++#define PFX "efi-capsupdate: "
++#define MAX_PATH 256
++#define MAX_CHUNK PAGE_SIZE
++#define CSH_HDR_SIZE 0x400
++
++typedef struct {
++ u64 length;
++ union {
++ u64 data_block;
++ u64 continuation_pointer;
++ };
++} efi_blk_desc_t;
++
++static struct kobject * efi_capsule_kobj;
++static struct list_head sg_list;
++static char fpath[MAX_PATH];
++static int csh_jump = CSH_HDR_SIZE; /* Clanton EDK wants CSH jump */
++
++/**
++ * efi_capsule_trigger_update
++ *
++ * Trigger the EFI capsule update
++ */
++static int efi_capsule_trigger_update(void)
++{
++ struct file *fp = NULL;
++ mm_segment_t old_fs = get_fs();
++ int ret = 0;
++ u32 nblocks = 0, i = 0, total_size = 0, data_len = 0, offset = 0;
++ efi_capsule_header_t *chdr = NULL;
++ efi_blk_desc_t * desc_block = NULL;
++ u8 ** data = NULL;
++
++ set_fs (KERNEL_DS);
++ fp = filp_open(fpath, O_RDONLY, 0);
++
++ /* Sanity check input */
++ if (IS_ERR(fp)|| fp->f_op == NULL ||fp->f_op->read == NULL ||
++ fp->f_dentry->d_inode->i_size == 0){
++ pr_err(PFX"file open [%s] error!\n", fpath);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ /* Determine necessary sizes */
++ nblocks = (fp->f_dentry->d_inode->i_size/MAX_CHUNK) + 2;
++ total_size = fp->f_dentry->d_inode->i_size;
++
++ pr_info(PFX "nblocks %d total_size %d\n", nblocks, total_size);
++
++ /* Allocate array of descriptor blocks + 1 for terminator */
++ desc_block = (efi_blk_desc_t*)kzalloc(nblocks * sizeof(efi_blk_desc_t), GFP_KERNEL);
++ if (desc_block == NULL){
++ pr_info(PFX"%s failed to allocate %d blocks\n", __func__, nblocks);
++ ret = -ENOMEM;
++ goto done_close;
++ }
++
++ pr_info(PFX"File %s size %u descriptor blocks %u\n",
++ fpath, total_size, nblocks);
++
++ data = kmalloc(nblocks, GFP_KERNEL);
++ if (data == NULL){
++ ret = -ENOMEM;
++ pr_info("Failed to allocate %d bytes\n", nblocks);
++ goto done;
++ }
++
++ for (i = 0; i < nblocks; i++){
++ data[i] = kmalloc(MAX_CHUNK, GFP_KERNEL);
++ if (data[i] == NULL){
++ ret = -ENOMEM;
++ pr_info("Alloc fail %d bytes entry %d\n",
++ nblocks, i);
++ goto done;
++ }
++
++ }
++
++ /* Read in data */
++ for (i = 0; i < nblocks && offset < total_size; i++){
++ /* Determine read len */
++ data_len = offset < total_size - MAX_CHUNK ?
++ MAX_CHUNK : total_size - offset;
++ ret = fp->f_op->read(fp, data[i], data_len, &fp->f_pos);
++ if (ret < 0){
++ pr_err(PFX"Error reading @ data %u\n", offset);
++ ret = -EIO;
++ goto done;
++ }
++ offset += data_len;
++
++ /* Sanity check */
++ if (i >= nblocks){
++ pr_err(PFX"%s Driver bug line %d\n", __func__, __LINE__);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ /* Validate header as appropriate */
++ if (chdr == NULL){
++ chdr = (efi_capsule_header_t*)&data[i][csh_jump];
++ desc_block[i].data_block = __pa(&data[i][csh_jump]);
++ desc_block[i].length = data_len - csh_jump;
++ pr_info(PFX"hdr offset in file %d bytes\n", csh_jump);
++ pr_info(PFX"hdr size %u flags 0x%08x imagesize 0x%08x\n",
++ chdr->headersize, chdr->flags, chdr->imagesize);
++
++ }else{
++ desc_block[i].data_block = __pa(&data[i][0]);
++ desc_block[i].length = data_len;
++ }
++
++ pr_info(PFX "block %d length %u data @ phys 0x%08x\n",
++ i, (int)desc_block[i].length,
++ (unsigned int)desc_block[i].data_block);
++ }
++
++ if (i > nblocks-1){
++ pr_err(PFX"%s Used block %d expected %d !\n", __func__, i, nblocks-1);
++ ret = -EINVAL;
++ goto done;
++ }
++
++ pr_info(PFX"submitting capsule to EDKII firmware\n");
++
++ ret = efi.update_capsule(&chdr, 1, __pa(desc_block));
++ if(ret != EFI_SUCCESS) {
++ pr_err(PFX"submission fail err=0x%08x\n", ret);
++ }else{
++ pr_info(PFX"submission success\n");
++ ret = 0;
++ }
++
++ if (chdr != NULL && chdr->flags & 0x10000){
++ pr_info(PFX"capsule persist across S3 skipping capsule free\n");
++ goto done_close;
++ }
++done:
++ for (i = 0; i < nblocks; i++){
++ if (data && data[i])
++ kfree(data[i]);
++ }
++ if (data)
++ kfree(data);
++
++ if (desc_block != NULL)
++ kfree(desc_block);
++done_close:
++ if (!IS_ERR(fp))
++ filp_close(fp, NULL);
++
++ set_fs (old_fs);
++ return ret;
++}
++
++/**
++ * efi_capsule_csh_jump
++ *
++ * sysfs callback used to show current path
++ */
++static ssize_t efi_capsule_csh_jump_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, sizeof(fpath), "%d\n", csh_jump > 0);
++}
++
++/**
++ * efi_capsule_path_store
++ *
++ * sysfs callback used to set a new capsule path
++ */
++static ssize_t efi_capsule_csh_jump_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (buf != NULL && buf[0] == '0')
++ csh_jump = 0;
++ else
++ csh_jump = CSH_HDR_SIZE;
++ return count;
++}
++
++static struct kobj_attribute efi_capsule_csh_jump_attr =
++ __ATTR(csh_jump, 0644, efi_capsule_csh_jump_show, efi_capsule_csh_jump_store);
++
++/**
++ * efi_capsule_path_show
++ *
++ * sysfs callback used to show current path
++ */
++static ssize_t efi_capsule_path_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, sizeof(fpath), fpath);
++}
++
++/**
++ * efi_capsule_path_store
++ *
++ * sysfs callback used to set a new capsule path
++ */
++static ssize_t efi_capsule_path_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{
++ if (count > MAX_PATH-1)
++ return -EINVAL;
++
++ memset(fpath, 0x00, sizeof(fpath));
++ memcpy(fpath, buf, count);
++
++ return count;
++}
++
++static struct kobj_attribute efi_capsule_path_attr =
++ __ATTR(capsule_path, 0644, efi_capsule_path_show, efi_capsule_path_store);
++
++/**
++ * efi_capsule_update_store
++ *
++ * sysfs callback used to initiate update
++ */
++static ssize_t efi_capsule_update_store(struct kobject *kobj, struct kobj_attribute *attr,
++ const char *buf, size_t count)
++{ int ret = 0;
++
++ ret = efi_capsule_trigger_update();
++ return ret == 0 ? count : ret;
++}
++
++static struct kobj_attribute efi_capsule_update_attr =
++ __ATTR(capsule_update, 0644, NULL, efi_capsule_update_store);
++
++#define SYSFS_ERRTXT "Error adding sysfs entry!\n"
++/**
++ * intel_cln_capsule_update_init
++ *
++ * @return 0 success < 0 failure
++ *
++ * Module entry point
++ */
++static int __init efi_capsule_update_init(void)
++{
++ int retval = 0;
++ extern struct kobject * firmware_kobj;
++
++ INIT_LIST_HEAD(&sg_list);
++
++ /* efi_capsule_kobj subordinate of firmware @ /sys/firmware/efi */
++ efi_capsule_kobj = kobject_create_and_add("efi", firmware_kobj);
++ if (!efi_capsule_kobj) {
++ pr_err(PFX"kset create error\n");
++ retval = -ENODEV;
++ goto err;
++ }
++
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_path_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err;
++ }
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_update_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err;
++
++ }
++ if(sysfs_create_file(efi_capsule_kobj, &efi_capsule_csh_jump_attr.attr)) {
++ pr_err(PFX SYSFS_ERRTXT);
++ retval = -ENODEV;
++ goto err;
++
++ }
++
++err:
++ return retval;
++}
++
++/**
++ * intel_cln_esram_exit
++ *
++ * Module exit
++ */
++static void __exit efi_capsule_update_exit(void)
++{
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("EFI Capsule Update driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++module_init(efi_capsule_update_init);
++module_exit(efi_capsule_update_exit);
+diff --git a/drivers/base/class.c b/drivers/base/class.c
+index 03243d4..3ce8454 100644
+--- a/drivers/base/class.c
++++ b/drivers/base/class.c
+@@ -420,8 +420,8 @@ EXPORT_SYMBOL_GPL(class_for_each_device);
+ * code. There's no locking restriction.
+ */
+ struct device *class_find_device(struct class *class, struct device *start,
+- void *data,
+- int (*match)(struct device *, void *))
++ const void *data,
++ int (*match)(struct device *, const void *))
+ {
+ struct class_dev_iter iter;
+ struct device *dev;
+diff --git a/drivers/base/core.c b/drivers/base/core.c
+index a235085..dda0c7f 100644
+--- a/drivers/base/core.c
++++ b/drivers/base/core.c
+@@ -1617,9 +1617,9 @@ struct device *device_create(struct class *class, struct device *parent,
+ }
+ EXPORT_SYMBOL_GPL(device_create);
+
+-static int __match_devt(struct device *dev, void *data)
++static int __match_devt(struct device *dev, const void *data)
+ {
+- dev_t *devt = data;
++ const dev_t *devt = data;
+
+ return dev->devt == *devt;
+ }
+diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
+index d4c1218..955d8fe 100644
+--- a/drivers/dma/Kconfig
++++ b/drivers/dma/Kconfig
+@@ -34,18 +34,46 @@ if DMADEVICES
+ comment "DMA Devices"
+
+ config INTEL_MID_DMAC
++ tristate "Intel DMAC Moorsetown/Medfield/Clanton DMA controllers"
++ depends on X86
++ default n
++ help
++ Enable support for the Intel(R) MID/Clanton DMA engine present
++ in Intel MID chipsets and Clanton SOC devices
++
++ Say Y here if you have such a chipset.
++
++ If unsure, say N.
++
++if INTEL_MID_DMAC
++
++config INTEL_MID_PCI
+ tristate "Intel MID DMA support for Peripheral DMA controllers"
+- depends on PCI && X86
++ depends on X86 && PCI
+ select DMA_ENGINE
+ default n
+ help
+ Enable support for the Intel(R) MID DMA engine present
+- in Intel MID chipsets.
++ in Intel MID chipsets
+
+ Say Y here if you have such a chipset.
+
+ If unsure, say N.
+
++config INTEL_CLN_DMAC
++ tristate "Intel CLN DMA support for Peripheral DMA controllers"
++ depends on PCI && X86 && INTEL_QUARK_X1000_SOC
++ default n
++ help
++ Enable support for the Intel(R) Clanton DMA engine present
++ in Intel Clanton DMA enabled UART. This is not a generic DMA
++ driver, instead this enables DMAC regs for Clanton's UART alone
++
++ Say Y here if you have a Clanton processor.
++
++ If unsure, say N.
++endif
++
+ config ASYNC_TX_ENABLE_CHANNEL_SWITCH
+ bool
+
+diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
+index a0de82e..91883c2 100644
+--- a/drivers/dma/intel_mid_dma.c
++++ b/drivers/dma/intel_mid_dma.c
+@@ -30,9 +30,9 @@
+ #include <linux/module.h>
+
+ #include "dmaengine.h"
++#include "intel_mid_dma_regs.h"
+
+ #define MAX_CHAN 4 /*max ch across controllers*/
+-#include "intel_mid_dma_regs.h"
+
+ #define INTEL_MID_DMAC1_ID 0x0814
+ #define INTEL_MID_DMAC2_ID 0x0813
+@@ -43,6 +43,14 @@
+ #define LNW_PERIPHRAL_STATUS 0x0
+ #define LNW_PERIPHRAL_MASK 0x8
+
++/**
++ * struct intel_mid_dma_probe_info
++ *
++ * @max_chan: maximum channels to probe
++ * @ch_base: offset from register base
++ * @block_size: TBD
++ * @pimr_mask: indicates if mask registers to be mapped
++ */
+ struct intel_mid_dma_probe_info {
+ u8 max_chan;
+ u8 ch_base;
+@@ -1015,7 +1023,7 @@ static void dma_tasklet2(unsigned long data)
+ * See if this is our interrupt if so then schedule the tasklet
+ * otherwise ignore
+ */
+-static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
++irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
+ {
+ struct middma_device *mid = data;
+ u32 tfr_status, err_status;
+@@ -1048,6 +1056,7 @@ static irqreturn_t intel_mid_dma_interrupt(int irq, void *data)
+
+ return IRQ_HANDLED;
+ }
++EXPORT_SYMBOL(intel_mid_dma_interrupt);
+
+ static irqreturn_t intel_mid_dma_interrupt1(int irq, void *data)
+ {
+diff --git a/drivers/dma/intel_mid_dma/Makefile b/drivers/dma/intel_mid_dma/Makefile
+new file mode 100644
+index 0000000..567eca5
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma/Makefile
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
++intel_mid_dma-objs:= intel_mid_dma_core.o intel_cln_dma_pci.o intel_mid_dma_pci.o
++
+diff --git a/drivers/dma/intel_mid_dma/intel_cln_dma_pci.c b/drivers/dma/intel_mid_dma/intel_cln_dma_pci.c
+new file mode 100644
+index 0000000..442c2f2
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma/intel_cln_dma_pci.c
+@@ -0,0 +1,153 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++/*
++ * intel_mid_dma.c - Intel Langwell DMA Drivers
++ *
++ * Author: Vinod Koul <bryan.odonoghue@linux.intel.com>
++ * This is an entry point for Intel Clanton based DMAC on Clanton's UART
++ * specifically we don't have a dedicated PCI function, instead we have DMAC
++ * regs hung off of a PCI BAR. This entry/exit allows re-use of the core
++ * DMA API for MID devices manipulated to suit our BAR setup
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/module.h>
++
++#include "intel_mid_dma_core.h"
++#include "intel_mid_dma_regs.h"
++
++/**
++ * intel_mid_dma_probe - PCI Probe
++ * @pdev: Controller PCI device structure
++ * @id: pci device id structure
++ *
++ * Initialize the PCI device, map BARs, query driver data.
++ * Call intel_setup_dma to complete contoller and chan initilzation
++ */
++int __devinit intel_cln_dma_probe(struct pci_dev *pdev,
++ struct middma_device *device)
++{
++ u32 base_addr, bar_size;
++ int err;
++
++ pr_debug("MDMA: probe for %x\n", pdev->device);
++ pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
++ device->max_chan, device->chan_base,
++ device->block_size, device->pimr_mask);
++
++ device->pdev = pci_dev_get(pdev);
++ device->ispci_fn = true;
++
++ base_addr = pci_resource_start(pdev, 1);
++ bar_size = pci_resource_len(pdev, 1);
++ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
++ if (!device->dma_base) {
++ pr_err("ERR_MDMA:ioremap failed\n");
++ err = -ENOMEM;
++ goto err_ioremap;
++ }
++
++ err = intel_mid_dma_setup(pdev, device, false);
++ if (err)
++ goto err_dma;
++
++ return 0;
++
++err_dma:
++ iounmap(device->dma_base);
++err_ioremap:
++ pr_err("ERR_MDMA:Probe failed %d\n", err);
++ return err;
++}
++EXPORT_SYMBOL(intel_cln_dma_probe);
++
++/**
++ * intel_mid_dma_remove - PCI remove
++ * @pdev: Controller PCI device structure
++ *
++ * Free up all resources and data
++ * Call shutdown_dma to complete contoller and chan cleanup
++ */
++void __devexit intel_cln_dma_remove(struct pci_dev *pdev, struct middma_device *device)
++{
++ intel_mid_dma_shutdown(pdev, device);
++}
++EXPORT_SYMBOL(intel_cln_dma_remove);
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_cln_dma_suspend(struct middma_device *device)
++{
++ int i = 0;
++ pr_debug("MDMA: dma_suspend called\n");
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++ dmac1_mask_periphral_intr(device);
++ device->state = SUSPENDED;
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_dma_suspend);
++
++/**
++* dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int intel_cln_dma_resume(struct middma_device *device)
++{
++ pr_debug("MDMA: dma_resume called\n");
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_dma_resume);
++
++static int intel_cln_dma_runtime_suspend(struct middma_device *device)
++{
++ device->state = SUSPENDED;
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_dma_runtime_suspend);
++
++static int intel_cln_dma_runtime_resume(struct middma_device *device)
++{
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_dma_runtime_resume);
++
++
+diff --git a/drivers/dma/intel_mid_dma/intel_mid_dma_pci.c b/drivers/dma/intel_mid_dma/intel_mid_dma_pci.c
+new file mode 100644
+index 0000000..be7705b
+--- /dev/null
++++ b/drivers/dma/intel_mid_dma/intel_mid_dma_pci.c
+@@ -0,0 +1,287 @@
++/*
++ * intel_mid_dma.c - Intel Langwell DMA Drivers
++ *
++ * Copyright (C) 2008-12 Intel Corp
++ * Author: Vinod Koul <vinod.koul@intel.com>
++ * The driver design is based on dw_dmac driver
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++ *
++ * 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.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *
++ */
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <linux/pm_runtime.h>
++#include <linux/intel_mid_dma.h>
++#include <linux/module.h>
++
++#include "intel_mid_dma_regs.h"
++#include "intel_mid_dma_core.h"
++
++#define INTEL_MID_DMAC1_ID 0x0814
++#define INTEL_MID_DMAC2_ID 0x0813
++#define INTEL_MID_GP_DMAC2_ID 0x0827
++#define INTEL_MFLD_DMAC1_ID 0x0830
++
++#define INFO(_max_chan, _ch_base, _block_size, _pimr_mask) \
++ ((kernel_ulong_t)&(struct intel_mid_dma_probe_info) { \
++ .max_chan = (_max_chan), \
++ .ch_base = (_ch_base), \
++ .block_size = (_block_size), \
++ .pimr_mask = (_pimr_mask), \
++ })
++
++/**
++ * intel_mid_dma_probe - PCI Probe
++ * @pdev: Controller PCI device structure
++ * @id: pci device id structure
++ *
++ * Initialize the PCI device, map BARs, query driver data.
++ * Call setup_dma to complete contoller and chan initilzation
++ */
++static int intel_mid_dma_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ struct middma_device *device;
++ u32 base_addr, bar_size;
++ struct intel_mid_dma_probe_info *info;
++ int err;
++
++ pr_debug("MDMA: probe for %x\n", pdev->device);
++ info = (void *)id->driver_data;
++ pr_debug("MDMA: CH %d, base %d, block len %d, Periphral mask %x\n",
++ info->max_chan, info->ch_base,
++ info->block_size, info->pimr_mask);
++
++ err = pci_enable_device(pdev);
++ if (err)
++ goto err_enable_device;
++
++ err = pci_request_regions(pdev, "intel_mid_dmac");
++ if (err)
++ goto err_request_regions;
++
++ err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
++ if (err)
++ goto err_set_dma_mask;
++
++ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
++ if (err)
++ goto err_set_dma_mask;
++
++ device = kzalloc(sizeof(*device), GFP_KERNEL);
++ if (!device) {
++ pr_err("ERR_MDMA:kzalloc failed probe\n");
++ err = -ENOMEM;
++ goto err_kzalloc;
++ }
++ device->pdev = pci_dev_get(pdev);
++
++ base_addr = pci_resource_start(pdev, 0);
++ bar_size = pci_resource_len(pdev, 0);
++ device->dma_base = ioremap_nocache(base_addr, DMA_REG_SIZE);
++ if (!device->dma_base) {
++ pr_err("ERR_MDMA:ioremap failed\n");
++ err = -ENOMEM;
++ goto err_ioremap;
++ }
++ pci_set_drvdata(pdev, device);
++ pci_set_master(pdev);
++ device->max_chan = info->max_chan;
++ device->chan_base = info->ch_base;
++ device->block_size = info->block_size;
++ device->pimr_mask = info->pimr_mask;
++
++ err = mid_setup_dma(pdev);
++ if (err)
++ goto err_dma;
++
++ pm_runtime_put_noidle(&pdev->dev);
++ pm_runtime_allow(&pdev->dev);
++ return 0;
++
++err_dma:
++ iounmap(device->dma_base);
++err_ioremap:
++ pci_dev_put(pdev);
++ kfree(device);
++err_kzalloc:
++err_set_dma_mask:
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++err_request_regions:
++err_enable_device:
++ pr_err("ERR_MDMA:Probe failed %d\n", err);
++ return err;
++}
++
++/**
++ * intel_mid_dma_remove - PCI remove
++ * @pdev: Controller PCI device structure
++ *
++ * Free up all resources and data
++ * Call shutdown_dma to complete contoller and chan cleanup
++ */
++static void intel_mid_dma_remove(struct pci_dev *pdev)
++{
++ struct middma_device *device = pci_get_drvdata(pdev);
++
++ pm_runtime_get_noresume(&pdev->dev);
++ pm_runtime_forbid(&pdev->dev);
++ middma_shutdown(pdev);
++ pci_dev_put(pdev);
++ kfree(device);
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++}
++
++/* Power Management */
++/*
++* dma_suspend - PCI suspend function
++*
++* @pci: PCI device structure
++* @state: PM message
++*
++* This function is called by OS when a power event occurs
++*/
++static int dma_suspend(struct device *dev)
++{
++ struct pci_dev *pci = to_pci_dev(dev);
++ int i;
++ struct middma_device *device = pci_get_drvdata(pci);
++ pr_debug("MDMA: dma_suspend called\n");
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++ dmac1_mask_periphral_intr(device);
++ device->state = SUSPENDED;
++ pci_save_state(pci);
++ pci_disable_device(pci);
++ pci_set_power_state(pci, PCI_D3hot);
++ return 0;
++}
++
++/**
++* dma_resume - PCI resume function
++*
++* @pci: PCI device structure
++*
++* This function is called by OS when a power event occurs
++*/
++int dma_resume(struct device *dev)
++{
++ struct pci_dev *pci = to_pci_dev(dev);
++ int ret;
++ struct middma_device *device = pci_get_drvdata(pci);
++
++ pr_debug("MDMA: dma_resume called\n");
++ pci_set_power_state(pci, PCI_D0);
++ pci_restore_state(pci);
++ ret = pci_enable_device(pci);
++ if (ret) {
++ pr_err("MDMA: device can't be enabled for %x\n", pci->device);
++ return ret;
++ }
++ intel_mid_dma_resume(device);
++ return 0;
++}
++
++static int dma_runtime_suspend(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = SUSPENDED;
++ return 0;
++}
++
++static int dma_runtime_resume(struct device *dev)
++{
++ struct pci_dev *pci_dev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pci_dev);
++
++ device->state = RUNNING;
++ iowrite32(REG_BIT0, device->dma_base + DMA_CFG);
++ return 0;
++}
++
++static int dma_runtime_idle(struct device *dev)
++{
++ struct pci_dev *pdev = to_pci_dev(dev);
++ struct middma_device *device = pci_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < device->max_chan; i++) {
++ if (device->ch[i].in_use)
++ return -EAGAIN;
++ }
++
++ return pm_schedule_suspend(dev, 0);
++}
++
++/******************************************************************************
++* PCI stuff
++*/
++static struct pci_device_id intel_mid_dma_ids[] = {
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC1_ID), INFO(2, 6, 4095, 0x200020)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_DMAC2_ID), INFO(2, 0, 2047, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MID_GP_DMAC2_ID), INFO(2, 0, 2047, 0)},
++ { PCI_VDEVICE(INTEL, INTEL_MFLD_DMAC1_ID), INFO(4, 0, 4095, 0x400040)},
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_mid_dma_ids);
++
++static const struct dev_pm_ops intel_mid_dma_pm = {
++ .runtime_suspend = dma_runtime_suspend,
++ .runtime_resume = dma_runtime_resume,
++ .runtime_idle = dma_runtime_idle,
++ .suspend = dma_suspend,
++ .resume = dma_resume,
++};
++
++static struct pci_driver intel_mid_dma_pci_driver = {
++ .name = "Intel MID DMA",
++ .id_table = intel_mid_dma_ids,
++ .probe = intel_mid_dma_probe,
++ .remove = __devexit_p(intel_mid_dma_remove),
++#ifdef CONFIG_PM
++ .driver = {
++ .pm = &intel_mid_dma_pm,
++ },
++#endif
++};
++
++static int __init intel_mid_dma_init(void)
++{
++ pr_debug("INFO_MDMA: LNW DMA Driver Version %s\n",
++ INTEL_MID_DMA_DRIVER_VERSION);
++ return pci_register_driver(&intel_mid_dma_pci_driver);
++}
++fs_initcall(intel_mid_dma_init);
++
++static void __exit intel_mid_dma_exit(void)
++{
++ pci_unregister_driver(&intel_mid_dma_pci_driver);
++}
++module_exit(intel_mid_dma_exit);
++
++MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
++MODULE_DESCRIPTION("Intel (R) MID DMAC Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_VERSION(INTEL_MID_DMA_DRIVER_VERSION);
+diff --git a/drivers/dma/intel_mid_dma_regs.h b/drivers/dma/intel_mid_dma_regs.h
+index 17b4219..4be7a01 100644
+--- a/drivers/dma/intel_mid_dma_regs.h
++++ b/drivers/dma/intel_mid_dma_regs.h
+@@ -27,6 +27,7 @@
+
+ #include <linux/dmaengine.h>
+ #include <linux/dmapool.h>
++#include <linux/intel_mid_dma.h>
+ #include <linux/pci_ids.h>
+
+ #define INTEL_MID_DMA_DRIVER_VERSION "1.1.0"
+@@ -158,115 +159,17 @@ union intel_mid_dma_cfg_hi {
+ };
+
+
+-/**
+- * struct intel_mid_dma_chan - internal mid representation of a DMA channel
+- * @chan: dma_chan strcture represetation for mid chan
+- * @ch_regs: MMIO register space pointer to channel register
+- * @dma_base: MMIO register space DMA engine base pointer
+- * @ch_id: DMA channel id
+- * @lock: channel spinlock
+- * @active_list: current active descriptors
+- * @queue: current queued up descriptors
+- * @free_list: current free descriptors
+- * @slave: dma slave structure
+- * @descs_allocated: total number of descriptors allocated
+- * @dma: dma device structure pointer
+- * @busy: bool representing if ch is busy (active txn) or not
+- * @in_use: bool representing if ch is in use or not
+- * @raw_tfr: raw trf interrupt received
+- * @raw_block: raw block interrupt received
+- */
+-struct intel_mid_dma_chan {
+- struct dma_chan chan;
+- void __iomem *ch_regs;
+- void __iomem *dma_base;
+- int ch_id;
+- spinlock_t lock;
+- struct list_head active_list;
+- struct list_head queue;
+- struct list_head free_list;
+- unsigned int descs_allocated;
+- struct middma_device *dma;
+- bool busy;
+- bool in_use;
+- u32 raw_tfr;
+- u32 raw_block;
+- struct intel_mid_dma_slave *mid_slave;
+-};
+-
+ static inline struct intel_mid_dma_chan *to_intel_mid_dma_chan(
+ struct dma_chan *chan)
+ {
+ return container_of(chan, struct intel_mid_dma_chan, chan);
+ }
+
+-enum intel_mid_dma_state {
+- RUNNING = 0,
+- SUSPENDED,
+-};
+-/**
+- * struct middma_device - internal representation of a DMA device
+- * @pdev: PCI device
+- * @dma_base: MMIO register space pointer of DMA
+- * @dma_pool: for allocating DMA descriptors
+- * @common: embedded struct dma_device
+- * @tasklet: dma tasklet for processing interrupts
+- * @ch: per channel data
+- * @pci_id: DMA device PCI ID
+- * @intr_mask: Interrupt mask to be used
+- * @mask_reg: MMIO register for periphral mask
+- * @chan_base: Base ch index (read from driver data)
+- * @max_chan: max number of chs supported (from drv_data)
+- * @block_size: Block size of DMA transfer supported (from drv_data)
+- * @pimr_mask: MMIO register addr for periphral interrupt (from drv_data)
+- * @state: dma PM device state
+- */
+-struct middma_device {
+- struct pci_dev *pdev;
+- void __iomem *dma_base;
+- struct pci_pool *dma_pool;
+- struct dma_device common;
+- struct tasklet_struct tasklet;
+- struct intel_mid_dma_chan ch[MAX_CHAN];
+- unsigned int pci_id;
+- unsigned int intr_mask;
+- void __iomem *mask_reg;
+- int chan_base;
+- int max_chan;
+- int block_size;
+- unsigned int pimr_mask;
+- enum intel_mid_dma_state state;
+-};
+-
+ static inline struct middma_device *to_middma_device(struct dma_device *common)
+ {
+ return container_of(common, struct middma_device, common);
+ }
+
+-struct intel_mid_dma_desc {
+- void __iomem *block; /*ch ptr*/
+- struct list_head desc_node;
+- struct dma_async_tx_descriptor txd;
+- size_t len;
+- dma_addr_t sar;
+- dma_addr_t dar;
+- u32 cfg_hi;
+- u32 cfg_lo;
+- u32 ctl_lo;
+- u32 ctl_hi;
+- struct pci_pool *lli_pool;
+- struct intel_mid_dma_lli *lli;
+- dma_addr_t lli_phys;
+- unsigned int lli_length;
+- unsigned int current_lli;
+- dma_addr_t next;
+- enum dma_transfer_direction dirn;
+- enum dma_status status;
+- enum dma_slave_buswidth width; /*width of DMA txn*/
+- enum intel_mid_dma_mode cfg_mode; /*mode configuration*/
+-
+-};
+-
+ struct intel_mid_dma_lli {
+ dma_addr_t sar;
+ dma_addr_t dar;
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+index 682de75..97e951b 100644
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -243,13 +243,14 @@ config GPIO_VR41XX
+ Say yes here to support the NEC VR4100 series General-purpose I/O Uint
+
+ config GPIO_SCH
+- tristate "Intel SCH/TunnelCreek/Centerton GPIO"
++ tristate "Intel SCH/TunnelCreek/Centerton/Clanton GPIO"
+ depends on PCI && X86
+ select MFD_CORE
+ select LPC_SCH
+ help
+ Say yes here to support GPIO interface on Intel Poulsbo SCH,
+- Intel Tunnel Creek processor or Intel Centerton processor.
++ Intel Tunnel Creek processor, Intel Centerton processor or Intel
++ Clanton.
+ The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
+ powered by the core power rail and are turned off during sleep
+ modes (S3 and higher). The remaining four GPIOs are powered by
+@@ -261,6 +262,8 @@ config GPIO_SCH
+ The Intel Centerton processor has a total of 30 GPIO pins.
+ Twenty-one are powered by the core power rail and 9 from the
+ suspend power supply.
++ The Intel Clanton has 2 GPIOs powered by the core power well and 6
++ form the suspend power well.
+
+ config GPIO_ICH
+ tristate "Intel ICH GPIO"
+diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
+index edae963..73591be 100644
+--- a/drivers/gpio/gpio-sch.c
++++ b/drivers/gpio/gpio-sch.c
+@@ -41,6 +41,13 @@ static DEFINE_SPINLOCK(gpio_lock);
+
+ static unsigned short gpio_ba;
+
++static void cln_gpio_restrict_release(struct device *dev) {}
++static struct platform_device cln_gpio_restrict_pdev =
++{
++ .name = "cln-gpio-restrict-nc",
++ .dev.release = cln_gpio_restrict_release,
++};
++
+ static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+ {
+ u8 curr_dirs;
+@@ -240,6 +247,14 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ sch_gpio_resume.ngpio = 9;
+ break;
+
++ case PCI_DEVICE_ID_INTEL_CLANTON_ILB:
++ sch_gpio_core.base = 0;
++ sch_gpio_core.ngpio = 2;
++
++ sch_gpio_resume.base = 2;
++ sch_gpio_resume.ngpio = 6;
++ break;
++
+ default:
+ err = -ENODEV;
+ goto err_sch_gpio_core;
+@@ -256,6 +271,10 @@ static int sch_gpio_probe(struct platform_device *pdev)
+ if (err < 0)
+ goto err_sch_gpio_resume;
+
++ err = platform_device_register(&cln_gpio_restrict_pdev);
++ if (err < 0)
++ goto err_sch_gpio_resume;
++
+ return 0;
+
+ err_sch_gpio_resume:
+@@ -277,6 +296,8 @@ static int sch_gpio_remove(struct platform_device *pdev)
+ if (gpio_ba) {
+ int err;
+
++ platform_device_unregister(&cln_gpio_restrict_pdev);
++
+ err = gpiochip_remove(&sch_gpio_core);
+ if (err)
+ dev_err(&pdev->dev, "%s failed, %d\n",
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+index 199fca1..5e897ff 100644
+--- a/drivers/gpio/gpiolib.c
++++ b/drivers/gpio/gpiolib.c
+@@ -60,11 +60,17 @@ struct gpio_desc {
+ #define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */
+ #define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */
+ #define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */
++#define FLAG_PULLUP 10 /* Gpio drive is resistive pullup */
++#define FLAG_PULLDOWN 11 /* Gpio drive is resistive pulldown */
++#define FLAG_STRONG 12 /* Gpio drive is strong (fast output) */
++#define FLAG_HIZ 13 /* Gpio drive is Hi-Z (input) */
+
+ #define ID_SHIFT 16 /* add new flags before this one */
+
+ #define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)
+ #define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))
++#define GPIO_DRIVE_MASK (BIT(FLAG_PULLUP) | BIT(FLAG_PULLDOWN) \
++ | BIT(FLAG_STRONG) | BIT(FLAG_HIZ))
+
+ #ifdef CONFIG_DEBUG_FS
+ const char *label;
+@@ -243,6 +249,10 @@ static DEFINE_MUTEX(sysfs_lock);
+ * * is read/write as zero/nonzero
+ * * also affects existing and subsequent "falling" and "rising"
+ * /edge configuration
++ * /drive
++ * * sets signal drive mode
++ * * is read/write as "pullup", "pulldown", "strong" or "hiz"
++ *
+ */
+
+ static ssize_t gpio_direction_show(struct device *dev,
+@@ -573,9 +583,85 @@ static ssize_t gpio_active_low_store(struct device *dev,
+ static const DEVICE_ATTR(active_low, 0644,
+ gpio_active_low_show, gpio_active_low_store);
+
++static ssize_t gpio_drive_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ const struct gpio_desc *desc = dev_get_drvdata(dev);
++ ssize_t status;
++
++ mutex_lock(&sysfs_lock);
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags)) {
++ status = -EIO;
++ } else {
++ if (test_bit(FLAG_PULLUP, &desc->flags))
++ status = sprintf(buf, "pullup\n");
++ else if (test_bit(FLAG_PULLDOWN, &desc->flags))
++ status = sprintf(buf, "pulldown\n");
++ else if (test_bit(FLAG_STRONG, &desc->flags))
++ status = sprintf(buf, "strong\n");
++ else if (test_bit(FLAG_HIZ, &desc->flags))
++ status = sprintf(buf, "hiz\n");
++ else
++ status = -EINVAL;
++ }
++
++ mutex_unlock(&sysfs_lock);
++ return status;
++}
++
++static ssize_t gpio_drive_store(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ struct gpio_desc *desc = dev_get_drvdata(dev);
++ unsigned gpio = desc - gpio_desc;
++ ssize_t status;
++
++ mutex_lock(&sysfs_lock);
++
++ if (!test_bit(FLAG_EXPORT, &desc->flags))
++ status = -EIO;
++ else {
++ if (sysfs_streq(buf, "pullup")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLUP);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_PULLUP, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "pulldown")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_PULLDOWN);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_PULLDOWN, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "strong")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_STRONG);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_STRONG, &desc->flags);
++ }
++ } else if (sysfs_streq(buf, "hiz")) {
++ status = gpio_set_drive(gpio, GPIOF_DRIVE_HIZ);
++ if (!status) {
++ desc->flags &= ~GPIO_DRIVE_MASK;
++ set_bit(FLAG_HIZ, &desc->flags);
++ }
++ } else {
++ status = -EINVAL;
++ }
++ }
++
++ mutex_unlock(&sysfs_lock);
++ return status ? : size;
++}
++
++static const DEVICE_ATTR(drive, 0644,
++ gpio_drive_show, gpio_drive_store);
++
+ static const struct attribute *gpio_attrs[] = {
+ &dev_attr_value.attr,
+ &dev_attr_active_low.attr,
++ &dev_attr_drive.attr,
+ NULL,
+ };
+
+@@ -806,7 +892,7 @@ fail_unlock:
+ }
+ EXPORT_SYMBOL_GPL(gpio_export);
+
+-static int match_export(struct device *dev, void *data)
++static int match_export(struct device *dev, const void *data)
+ {
+ return dev_get_drvdata(dev) == data;
+ }
+@@ -1677,6 +1763,50 @@ fail:
+ }
+ EXPORT_SYMBOL_GPL(gpio_set_debounce);
+
++/**
++ * gpio_set_drive - sets drive @mode for a @gpio
++ * @gpio: the gpio to set the drive mode
++ * @mode: the drive mode
++ */
++int gpio_set_drive(unsigned gpio, unsigned mode)
++{
++ unsigned long flags;
++ struct gpio_chip *chip;
++ struct gpio_desc *desc = &gpio_desc[gpio];
++ int status = -EINVAL;
++
++ spin_lock_irqsave(&gpio_lock, flags);
++
++ if (!gpio_is_valid(gpio))
++ goto fail;
++ chip = desc->chip;
++ if (!chip || !chip->set || !chip->set_drive)
++ goto fail;
++ gpio -= chip->base;
++ if (gpio >= chip->ngpio)
++ goto fail;
++ status = gpio_ensure_requested(desc, gpio);
++ if (status < 0)
++ goto fail;
++
++ /* now we know the gpio is valid and chip won't vanish */
++
++ spin_unlock_irqrestore(&gpio_lock, flags);
++
++ might_sleep_if(chip->can_sleep);
++
++ return chip->set_drive(chip, gpio, mode);
++
++fail:
++ spin_unlock_irqrestore(&gpio_lock, flags);
++ if (status)
++ pr_debug("%s: gpio-%d status %d\n",
++ __func__, gpio, status);
++
++ return status;
++}
++EXPORT_SYMBOL_GPL(gpio_set_drive);
++
+ /* I/O calls are only valid after configuration completed; the relevant
+ * "is this a valid GPIO" error checks should already have been done.
+ *
+diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
+index bdca511..010e4fd 100644
+--- a/drivers/i2c/busses/Kconfig
++++ b/drivers/i2c/busses/Kconfig
+@@ -22,7 +22,7 @@ config I2C_ALI1535
+
+ config I2C_ALI1563
+ tristate "ALI 1563"
+- depends on PCI && EXPERIMENTAL
++ depends on PCI
+ help
+ If you say yes to this option, support will be included for the SMB
+ Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB
+@@ -56,7 +56,7 @@ config I2C_AMD756
+
+ config I2C_AMD756_S4882
+ tristate "SMBus multiplexing on the Tyan S4882"
+- depends on I2C_AMD756 && X86 && EXPERIMENTAL
++ depends on I2C_AMD756 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
+@@ -164,7 +164,7 @@ config I2C_NFORCE2
+
+ config I2C_NFORCE2_S4985
+ tristate "SMBus multiplexing on the Tyan S4985"
+- depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
++ depends on I2C_NFORCE2 && X86
+ help
+ Enabling this option will add specific SMBus support for the Tyan
+ S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
+@@ -215,7 +215,7 @@ config I2C_SIS96X
+
+ config I2C_VIA
+ tristate "VIA VT82C586B"
+- depends on PCI && EXPERIMENTAL
++ depends on PCI
+ select I2C_ALGOBIT
+ help
+ If you say yes to this option, support will be included for the VIA
+@@ -267,7 +267,7 @@ comment "Mac SMBus host controller drivers"
+
+ config I2C_HYDRA
+ tristate "CHRP Apple Hydra Mac I/O I2C interface"
+- depends on PCI && PPC_CHRP && EXPERIMENTAL
++ depends on PCI && PPC_CHRP
+ select I2C_ALGOBIT
+ help
+ This supports the use of the I2C interface in the Apple Hydra Mac
+@@ -293,7 +293,7 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"
+
+ config I2C_AT91
+ tristate "Atmel AT91 I2C Two-Wire interface (TWI)"
+- depends on ARCH_AT91 && EXPERIMENTAL
++ depends on ARCH_AT91
+ help
+ This supports the use of the I2C interface on Atmel AT91
+ processors.
+@@ -386,7 +386,7 @@ config I2C_DESIGNWARE_PLATFORM
+
+ config I2C_DESIGNWARE_PCI
+ tristate "Synopsys DesignWare PCI"
+- depends on PCI
++ depends on PCI && !INTEL_QUARK_X1000_SOC
+ select I2C_DESIGNWARE_CORE
+ help
+ If you say yes to this option, support will be included for the
+@@ -519,7 +519,6 @@ config I2C_NUC900
+
+ config I2C_OCORES
+ tristate "OpenCores I2C Controller"
+- depends on EXPERIMENTAL
+ help
+ If you say yes to this option, support will be included for the
+ OpenCores I2C controller. For details see
+@@ -712,7 +711,7 @@ config I2C_OCTEON
+
+ config I2C_XILINX
+ tristate "Xilinx I2C Controller"
+- depends on EXPERIMENTAL && HAS_IOMEM
++ depends on HAS_IOMEM
+ help
+ If you say yes to this option, support will be included for the
+ Xilinx I2C controller.
+@@ -803,7 +802,7 @@ config I2C_PARPORT_LIGHT
+
+ config I2C_TAOS_EVM
+ tristate "TAOS evaluation module"
+- depends on EXPERIMENTAL
++ depends on TTY
+ select SERIO
+ select SERIO_SERPORT
+ default n
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index f5258c2..2a2d1c9 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -164,6 +164,29 @@ static char *abort_sources[] = {
+ "lost arbitration",
+ };
+
++/*
++ * Bitmask for struct i2c_dw_data_cmd's `cmd' field.
++ * - DW_IC_CMD_READ: read/~write operation
++ * - DW_IC_CMD_STOP: stop condition generation (only for devices requiring
++ * explicit transaction termination)
++ * - DW_IC_CMD_RESTART: (re)start condition generation (only for devices
++ * requiring explicit transaction termination)
++ */
++#define DW_IC_CMD_READ 0x01
++#define DW_IC_CMD_STOP 0x02
++#define DW_IC_CMD_RESTART 0x04
++
++/*
++ * Define the IC_DATA_CMD format.
++ */
++static union i2c_dw_data_cmd {
++ struct fields {
++ u8 data;
++ u8 cmd;
++ } fields;
++ u16 value;
++} data_cmd;
++
+ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+ {
+ u32 value;
+@@ -344,6 +367,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
+ struct i2c_msg *msgs = dev->msgs;
+ u32 ic_con;
+
++ /* Disable interrupts */
++ i2c_dw_disable_int(dev);
++
+ /* Disable the adapter */
+ dw_writel(dev, 0, DW_IC_ENABLE);
+
+@@ -380,6 +406,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ u32 addr = msgs[dev->msg_write_idx].addr;
+ u32 buf_len = dev->tx_buf_len;
+ u8 *buf = dev->tx_buf;
++ int segment_start = 0;
+
+ intr_mask = DW_IC_INTR_DEFAULT_MASK;
+
+@@ -403,21 +430,65 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ break;
+ }
+
++ segment_start = 0;
+ if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) {
+ /* new i2c_msg */
+ buf = msgs[dev->msg_write_idx].buf;
+ buf_len = msgs[dev->msg_write_idx].len;
++ segment_start = 1;
+ }
+
+ tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR);
+ rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR);
+
++ /*
++ * The maximum number of read requests that can be put into TX
++ * FIFO depends on the number read operations already pending
++ * in RX FIFO + the number of outstanding read operations still
++ * queued in the TX FIFO.
++ * This prevents RX FIFO overrun.
++ */
++ rx_limit -= dev->rx_outstanding;
++
+ while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) {
++ data_cmd.fields.data = 0x00;
++ data_cmd.fields.cmd = 0x00;
++
+ if (msgs[dev->msg_write_idx].flags & I2C_M_RD) {
+- dw_writel(dev, 0x100, DW_IC_DATA_CMD);
++ /* Master-receiver */
++ data_cmd.fields.cmd = DW_IC_CMD_READ;
+ rx_limit--;
+- } else
+- dw_writel(dev, *buf++, DW_IC_DATA_CMD);
++ dev->rx_outstanding++;
++ } else {
++ /* Master-transmitter */
++ data_cmd.fields.data = *buf;
++ buf++;
++ }
++
++ if (1 == dev->explicit_stop
++ && 1 == segment_start) {
++ /*
++ * First byte of a transaction segment for a
++ * device requiring explicit transaction
++ * termination: generate (re)start symbol.
++ */
++ segment_start = 0;
++ data_cmd.fields.cmd |= DW_IC_CMD_RESTART;
++ }
++
++ if (1 == dev->explicit_stop
++ && dev->msg_write_idx == dev->msgs_num - 1
++ && 1 == buf_len) {
++ /*
++ * Last byte of last transction segment for a
++ * device requiring explicit transaction
++ * termination: generate stop symbol.
++ */
++ data_cmd.fields.cmd |= DW_IC_CMD_STOP;
++ }
++
++ dw_writel(dev, data_cmd.value, DW_IC_DATA_CMD);
++
+ tx_limit--; buf_len--;
+ }
+
+@@ -468,8 +539,10 @@ i2c_dw_read(struct dw_i2c_dev *dev)
+
+ rx_valid = dw_readl(dev, DW_IC_RXFLR);
+
+- for (; len > 0 && rx_valid > 0; len--, rx_valid--)
++ for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
+ *buf++ = dw_readl(dev, DW_IC_DATA_CMD);
++ dev->rx_outstanding--;
++ }
+
+ if (len > 0) {
+ dev->status |= STATUS_READ_IN_PROGRESS;
+@@ -527,6 +600,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+ dev->msg_err = 0;
+ dev->status = STATUS_IDLE;
+ dev->abort_source = 0;
++ dev->rx_outstanding = 0;
+
+ ret = i2c_dw_wait_bus_not_busy(dev);
+ if (ret < 0)
+@@ -625,8 +699,6 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
+ dw_readl(dev, DW_IC_CLR_RX_DONE);
+ if (stat & DW_IC_INTR_ACTIVITY)
+ dw_readl(dev, DW_IC_CLR_ACTIVITY);
+- if (stat & DW_IC_INTR_STOP_DET)
+- dw_readl(dev, DW_IC_CLR_STOP_DET);
+ if (stat & DW_IC_INTR_START_DET)
+ dw_readl(dev, DW_IC_CLR_START_DET);
+ if (stat & DW_IC_INTR_GEN_CALL)
+@@ -677,8 +749,21 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+ * the current transmit status.
+ */
+
++ /*
++ * Process stop condition after the last transaction segment is
++ * transmitted (and received if appropriate).
++ */
++ if (dev->msgs_num == dev->msg_write_idx
++ && (DW_IC_INTR_STOP_DET & dw_readl(dev, DW_IC_INTR_STAT))
++ && 0 == dw_readl(dev, DW_IC_TXFLR)
++ && 0 == dw_readl(dev, DW_IC_RXFLR)
++ && 0 == dev->rx_outstanding) {
++ dw_readl(dev, DW_IC_CLR_STOP_DET);
++ complete(&dev->cmd_complete);
++ }
++
+ tx_aborted:
+- if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
++ if ((stat & (DW_IC_INTR_TX_ABRT)) || dev->msg_err)
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
+index 9c1840e..691aff8 100644
+--- a/drivers/i2c/busses/i2c-designware-core.h
++++ b/drivers/i2c/busses/i2c-designware-core.h
+@@ -34,6 +34,14 @@
+ #define DW_IC_CON_RESTART_EN 0x20
+ #define DW_IC_CON_SLAVE_DISABLE 0x40
+
++struct dw_pci_controller {
++ u32 bus_num;
++ u32 bus_cfg;
++ u32 tx_fifo_depth;
++ u32 rx_fifo_depth;
++ u32 clk_khz;
++ u8 explicit_stop;
++};
+
+ /**
+ * struct dw_i2c_dev - private i2c-designware data
+@@ -60,6 +68,8 @@
+ * @adapter: i2c subsystem adapter node
+ * @tx_fifo_depth: depth of the hardware tx fifo
+ * @rx_fifo_depth: depth of the hardware rx fifo
++ * @rx_outstanding: current outstanding master-receiver bytes in TX FIFO
++ * @explicit_stop: set to 1 if hardware requires explicit stop bit transmission
+ */
+ struct dw_i2c_dev {
+ struct device *dev;
+@@ -88,6 +98,8 @@ struct dw_i2c_dev {
+ u32 master_cfg;
+ unsigned int tx_fifo_depth;
+ unsigned int rx_fifo_depth;
++ int rx_outstanding;
++ u8 explicit_stop;
+ };
+
+ #define ACCESS_SWAP 0x00000001
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 6add851..62ad7dc 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -56,14 +56,6 @@ enum dw_pci_ctl_id_t {
+ medfield_5,
+ };
+
+-struct dw_pci_controller {
+- u32 bus_num;
+- u32 bus_cfg;
+- u32 tx_fifo_depth;
+- u32 rx_fifo_depth;
+- u32 clk_khz;
+-};
+-
+ #define INTEL_MID_STD_CFG (DW_IC_CON_MASTER | \
+ DW_IC_CON_SLAVE_DISABLE | \
+ DW_IC_CON_RESTART_EN)
+@@ -75,6 +67,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [moorestown_1] = {
+ .bus_num = 1,
+@@ -82,6 +75,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [moorestown_2] = {
+ .bus_num = 2,
+@@ -89,6 +83,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_0] = {
+ .bus_num = 0,
+@@ -96,6 +91,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_1] = {
+ .bus_num = 1,
+@@ -103,6 +99,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_2] = {
+ .bus_num = 2,
+@@ -110,6 +107,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_3] = {
+ .bus_num = 3,
+@@ -117,6 +115,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_4] = {
+ .bus_num = 4,
+@@ -124,6 +123,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ [medfield_5] = {
+ .bus_num = 5,
+@@ -131,6 +131,7 @@ static struct dw_pci_controller dw_pci_controllers[] = {
+ .tx_fifo_depth = 32,
+ .rx_fifo_depth = 32,
+ .clk_khz = 25000,
++ .explicit_stop = 0,
+ },
+ };
+ static struct i2c_algorithm i2c_dw_algo = {
+@@ -282,6 +283,7 @@ const struct pci_device_id *id)
+
+ dev->tx_fifo_depth = controller->tx_fifo_depth;
+ dev->rx_fifo_depth = controller->rx_fifo_depth;
++ dev->explicit_stop = controller->explicit_stop;
+ r = i2c_dw_init(dev);
+ if (r)
+ goto err_iounmap;
+diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
+index 05e996f..168989b 100644
+--- a/drivers/iio/accel/Kconfig
++++ b/drivers/iio/accel/Kconfig
+@@ -3,15 +3,12 @@
+ #
+ menu "Accelerometers"
+
+-config HID_SENSOR_ACCEL_3D
+- depends on HID_SENSOR_HUB
+- select IIO_BUFFER
+- select IIO_TRIGGERED_BUFFER
+- select HID_SENSOR_IIO_COMMON
+- select HID_SENSOR_IIO_TRIGGER
+- tristate "HID Accelerometers 3D"
+- help
+- Say yes here to build support for the HID SENSOR
+- accelerometers 3D.
++config IIO_LIS331DLH_INTEL_CLN
++ tristate "STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Clanton platform"
++ depends on INTEL_QUARK_X1000_SOC
++ depends on I2C && SYSFS
++ select IIO_ST_SENSORS_CORE
++ help
++ Selects the LIS331DLH accelerometer driver for the Intel Clanton Hill platform
+
+ endmenu
+diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
+index 5bc6855..c82ce57 100644
+--- a/drivers/iio/accel/Makefile
++++ b/drivers/iio/accel/Makefile
+@@ -1,5 +1,4 @@
+ #
+ # Makefile for industrial I/O accelerometer drivers
+ #
+-
+-obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o
++obj-$(CONFIG_IIO_LIS331DLH_INTEL_CLN) += lis331dlh_intel_cln.o
+diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
+index 0b0c3c6..563a2fe 100644
+--- a/drivers/iio/accel/hid-sensor-accel-3d.c
++++ b/drivers/iio/accel/hid-sensor-accel-3d.c
+@@ -45,6 +45,7 @@ enum accel_3d_channel {
+ struct accel_3d_state {
+ struct hid_sensor_hub_callbacks callbacks;
+ struct hid_sensor_iio_common common_attributes;
++ struct hid_sensor_common common_attributes;
+ struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
+ u32 accel_val[ACCEL_3D_CHANNEL_MAX];
+ };
+diff --git a/drivers/iio/accel/lis331dlh_intel_cln.c b/drivers/iio/accel/lis331dlh_intel_cln.c
+new file mode 100644
+index 0000000..57998d0
+--- /dev/null
++++ b/drivers/iio/accel/lis331dlh_intel_cln.c
+@@ -0,0 +1,675 @@
++/*
++ * Intel Clanton Hill platform accelerometer driver
++ *
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * Derived from STMicroelectronics accelerometers driver by Denis Ciocca
++ *
++ * The Intel Clanton Hill platform hardware design includes an
++ * STMicroelectronics LIS331DLH accelerometer, intended to be used mainly for
++ * sensing orientation, movement and sudden impacts (e.g. vehicle collision)
++ *
++ * This driver plugs into the Linux Industrial-IO framework to provide a
++ * standardised user-space application interface for retreiving data and events
++ * from the accelerometer.
++ *
++ * The LIS331DLH is connected via I2C to the host CPU on the Clanton Hill
++ * platform and so this driver registers to the kernel as an I2C device driver
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/errno.h>
++#include <linux/types.h>
++#include <linux/mutex.h>
++#include <linux/interrupt.h>
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/sysfs.h>
++#include <linux/iio/trigger.h>
++#include <linux/iio/buffer.h>
++
++#include <linux/iio/common/st_sensors.h>
++#include <linux/iio/common/st_sensors_i2c.h>
++
++#include <linux/platform_data/lis331dlh_intel_cln.h>
++
++/* DEFAULT VALUE FOR SENSORS */
++#define ST_ACCEL_DEFAULT_OUT_X_L_ADDR 0x28
++#define ST_ACCEL_DEFAULT_OUT_Y_L_ADDR 0x2a
++#define ST_ACCEL_DEFAULT_OUT_Z_L_ADDR 0x2c
++
++/* FULLSCALE */
++#define ST_ACCEL_FS_AVL_2G 2
++#define ST_ACCEL_FS_AVL_4G 4
++#define ST_ACCEL_FS_AVL_6G 6
++#define ST_ACCEL_FS_AVL_8G 8
++#define ST_ACCEL_FS_AVL_16G 16
++
++/* CUSTOM VALUES FOR SENSOR 2 */
++#define ST_ACCEL_2_WAI_EXP 0x32
++#define ST_ACCEL_2_ODR_ADDR 0x20
++#define ST_ACCEL_2_ODR_MASK 0x18
++#define ST_ACCEL_2_ODR_AVL_50HZ_VAL 0x00
++#define ST_ACCEL_2_ODR_AVL_100HZ_VAL 0x01
++#define ST_ACCEL_2_ODR_AVL_400HZ_VAL 0x02
++#define ST_ACCEL_2_ODR_AVL_1000HZ_VAL 0x03
++#define ST_ACCEL_2_PW_ADDR 0x20
++#define ST_ACCEL_2_PW_MASK 0xe0
++#define ST_ACCEL_2_PW_DOWN 0x00
++#define ST_ACCEL_2_PW_NORMAL 0x20
++#define ST_ACCEL_2_CTRL_REG1_XEN 0x01
++#define ST_ACCEL_2_CTRL_REG1_YEN 0x02
++#define ST_ACCEL_2_CTRL_REG1_ZEN 0x04
++#define ST_ACCEL_2_FS_ADDR 0x23
++#define ST_ACCEL_2_FS_MASK 0x30
++#define ST_ACCEL_2_FS_AVL_2_VAL 0X00
++#define ST_ACCEL_2_FS_AVL_4_VAL 0X01
++#define ST_ACCEL_2_FS_AVL_8_VAL 0x03
++#define ST_ACCEL_2_FS_AVL_2_GAIN IIO_G_TO_M_S_2(1000)
++#define ST_ACCEL_2_FS_AVL_4_GAIN IIO_G_TO_M_S_2(2000)
++#define ST_ACCEL_2_FS_AVL_8_GAIN IIO_G_TO_M_S_2(3900)
++#define ST_ACCEL_2_BDU_ADDR 0x23
++#define ST_ACCEL_2_BDU_MASK 0x80
++#define ST_ACCEL_2_DRDY_IRQ_ADDR 0x22
++#define ST_ACCEL_2_DRDY_IRQ_MASK 0x02
++#define ST_ACCEL_2_THRESH_IRQ_ADDR 0x30
++#define ST_ACCEL_2_THRESH_IRQ_MASK 0x7f
++#define ST_ACCEL_2_INT1_CFG_ADDR 0x30
++#define ST_ACCEL_2_INT1_SRC_ADDR 0x31
++#define ST_ACCEL_2_INT1_THRESH_ADDR 0x32
++#define ST_ACCEL_2_INT1_DURATION_ADDR 0x33
++#define ST_ACCEL_2_INT2_CFG_ADDR 0x34
++#define ST_ACCEL_2_INT2_SRC_ADDR 0x35
++#define ST_ACCEL_2_INT2_THRESH_ADDR 0x36
++#define ST_ACCEL_2_INT2_DURATION_ADDR 0x37
++#define ST_ACCEL_2_INT_IA_MASK 0x40
++#define ST_ACCEL_2_INT_LIR_MASK 0x05
++#define ST_ACCEL_2_INT_SRC_HIGH_MASK 0x20
++#define ST_ACCEL_2_INT_CFG_XLIE_EN 0x01
++#define ST_ACCEL_2_INT_CFG_XHIE_EN 0x02
++#define ST_ACCEL_2_INT_CFG_YLIE_EN 0x04
++#define ST_ACCEL_2_INT_CFG_YHIE_EN 0x08
++#define ST_ACCEL_2_INT_CFG_ZLIE_EN 0x10
++#define ST_ACCEL_2_INT_CFG_ZHIE_EN 0x20
++
++#define ST_ACCEL_2_MULTIREAD_BIT true
++#define CLN_ACCEL_INT2_WAKEUP_THRESH_VAL 0x7f
++
++static const u8 iio_modifier_map[] = {
++ IIO_NO_MOD,
++ IIO_MOD_X,
++ IIO_MOD_Y,
++ IIO_MOD_X_AND_Y,
++ IIO_MOD_Z,
++ IIO_MOD_X_AND_Z,
++ IIO_MOD_Y_AND_Z,
++ IIO_MOD_X_AND_Y_AND_Z,
++};
++
++/* Threshold event ISR bottom half. This function reads interrupt status
++ * registers for INT1 to reset any active interrupt conditions
++ * and pushes an IIO event if a threshold interrupt was active.
++ */
++static irqreturn_t lis331dlh_intel_cln_threshold_event_handler(
++ int irq,
++ void *private)
++{
++ int err;
++ u8 data;
++ u8 mask;
++ int i;
++ u64 iio_modifier;
++
++ struct st_sensor_data *sdata = iio_priv(private);
++ s64 timestamp = iio_get_time_ns();
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_SRC_ADDR,
++ &data);
++
++ if (err < 0)
++ goto st_sensors_read_err;
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ &mask);
++
++ if (err < 0)
++ goto st_sensors_read_err;
++
++ if (data & ST_ACCEL_2_INT_IA_MASK) {
++ data &= mask;
++
++ iio_modifier = 0;
++ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
++ iio_modifier <<= 1;
++ iio_modifier += !!(data & ST_ACCEL_2_INT_SRC_HIGH_MASK);
++ data <<= 2;
++ }
++
++ iio_modifier = iio_modifier_map[iio_modifier];
++
++ iio_push_event(private,
++ IIO_EVENT_CODE(IIO_ACCEL,
++ 0, /* non differential */
++ iio_modifier,
++ IIO_EV_TYPE_THRESH,
++ IIO_EV_DIR_RISING, 0, 0, 0),
++ timestamp);
++ }
++
++st_sensors_read_err:
++ return IRQ_HANDLED;
++}
++
++static int lis331dlh_intel_cln_read_raw(
++ struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch,
++ int *val, int *val2, long mask)
++{
++ int err;
++ struct st_sensor_data *adata = iio_priv(indio_dev);
++
++ switch (mask) {
++ case IIO_CHAN_INFO_RAW:
++ err = st_sensors_read_info_raw(indio_dev, ch, val);
++ if (err < 0)
++ goto read_error;
++
++ return IIO_VAL_INT;
++ case IIO_CHAN_INFO_SCALE:
++ *val = 0;
++ *val2 = adata->current_fullscale->gain;
++ return IIO_VAL_INT_PLUS_MICRO;
++ default:
++ return -EINVAL;
++ }
++
++read_error:
++ return err;
++}
++
++static int lis331dlh_intel_cln_write_raw(
++ struct iio_dev *indio_dev,
++ struct iio_chan_spec const *chan,
++ int val, int val2, long mask)
++{
++ int err;
++
++ switch (mask) {
++ case IIO_CHAN_INFO_SCALE:
++ err = st_sensors_set_fullscale_by_gain(indio_dev, val2);
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ return err;
++}
++
++
++static ST_SENSOR_DEV_ATTR_SAMP_FREQ();
++static ST_SENSORS_DEV_ATTR_SAMP_FREQ_AVAIL();
++static ST_SENSORS_DEV_ATTR_SCALE_AVAIL(in_accel_scale_available);
++
++static struct attribute *lis331dlh_intel_cln_attributes[] = {
++ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
++ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
++ &iio_dev_attr_sampling_frequency.dev_attr.attr,
++ NULL,
++};
++
++static const struct attribute_group lis331dlh_intel_cln_attribute_group = {
++ .attrs = lis331dlh_intel_cln_attributes,
++};
++
++static int lis331dlh_intel_cln_read_event_value(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int *val)
++{
++ int err;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_THRESH_ADDR, &data);
++
++ *val = (int) data;
++ return err;
++}
++
++static int lis331dlh_intel_cln_write_event_value(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int val)
++{
++ int err;
++ struct st_sensor_data *sdata;
++
++ /* range check */
++ if ((val < 0) || (val > 0x7f))
++ return -EINVAL;
++
++ sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_THRESH_ADDR, val);
++
++ return err;
++
++}
++
++/* Configure the INT1 pin to fire an interrupt on a high threshold event.
++ */
++static int lis331dlh_intel_cln_configure_threshold_interrupt(
++ struct iio_dev *indio_dev, bool state)
++{
++ int err = 0;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (sdata->int_thresh == state)
++ return 0;
++
++ if (state) {
++ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
++ NULL,
++ lis331dlh_intel_cln_threshold_event_handler,
++ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
++ "lis331dlh_intel_cln_threshold",
++ indio_dev);
++ if (err == 0) {
++ sdata->int_thresh = true;
++ err = sdata->tf->write_byte(
++ &sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_DURATION_ADDR, 1);
++ }
++ } else {
++ free_irq(sdata->get_irq_data_ready(indio_dev), indio_dev);
++ sdata->int_thresh = false;
++ }
++
++ return err;
++}
++
++static int lis331dlh_intel_cln_read_event_config(
++ struct iio_dev *indio_dev,
++ u64 event_code)
++{
++ int err = 0;
++ u8 data, mask;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ &data);
++
++ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
++
++ return !!(data & mask);
++}
++
++static int lis331dlh_intel_cln_write_event_config(
++ struct iio_dev *indio_dev,
++ u64 event_code,
++ int state)
++{
++ int err;
++ u8 data;
++ u8 mask;
++
++ bool new_int_state;
++
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++ mask = 1 << ((IIO_EVENT_CODE_EXTRACT_MODIFIER(event_code) << 1) - 1);
++
++ err = st_sensors_write_data_with_mask(indio_dev,
++ ST_ACCEL_2_INT1_CFG_ADDR,
++ mask, state);
++
++ if (err == 0)
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT1_CFG_ADDR, &data);
++
++ if (err == 0) {
++ new_int_state = data & (ST_ACCEL_2_INT_CFG_XHIE_EN |
++ ST_ACCEL_2_INT_CFG_YHIE_EN |
++ ST_ACCEL_2_INT_CFG_ZHIE_EN);
++ err = lis331dlh_intel_cln_configure_threshold_interrupt(
++ indio_dev, new_int_state);
++ }
++
++ return err;
++}
++
++/* Configure the INT2 pin to fire an interrupt on a threshold high event. INT2
++ * should be wired to a suspend well IRQ to wake up the host.
++ */
++static int lis331dlh_intel_cln_enable_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err = 0;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (err == 0)
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_THRESH_ADDR,
++ CLN_ACCEL_INT2_WAKEUP_THRESH_VAL);
++
++ /* Latch interrupt request on INT2 */
++ if (err == 0)
++ err = st_sensors_write_data_with_mask(
++ indio_dev, ST_ACCEL_2_DRDY_IRQ_ADDR,
++ ST_ACCEL_2_INT_LIR_MASK, 1);
++
++ if (err == 0)
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_DURATION_ADDR, 0);
++
++ if (err == 0)
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_CFG_ADDR,
++ ST_ACCEL_2_INT_CFG_XHIE_EN |
++ ST_ACCEL_2_INT_CFG_YHIE_EN);
++
++ /* Clean ST_ACCEL_2_INT2_SRC */
++ if (err == 0)
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++
++ return err;
++}
++
++static int lis331dlh_intel_cln_disable_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err = 0;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (err == 0)
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_CFG_ADDR,
++ 0);
++
++ /* Clean ST_ACCEL_2_INT2_SRC */
++ if (err == 0)
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++
++ return err;
++}
++
++static int lis331dlh_intel_cln_handle_wakeup_interrupt(
++ struct iio_dev *indio_dev)
++{
++ int err;
++ u8 data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++ s64 timestamp = iio_get_time_ns();
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_ACCEL_2_INT2_SRC_ADDR,
++ &data);
++
++ if (err == 0)
++ if (data & ST_ACCEL_2_INT_IA_MASK) {
++ iio_push_event(indio_dev,
++ IIO_EVENT_CODE(IIO_ACCEL,
++ 0, /* non differential */
++ IIO_MOD_X_OR_Y_OR_Z,
++ IIO_EV_TYPE_THRESH,
++ IIO_EV_DIR_EITHER, 0, 0, 0),
++ timestamp);
++ }
++
++ return err;
++}
++
++static const struct iio_info accel_info = {
++ .driver_module = THIS_MODULE,
++ .attrs = &lis331dlh_intel_cln_attribute_group,
++ .read_raw = &lis331dlh_intel_cln_read_raw,
++ .write_raw = &lis331dlh_intel_cln_write_raw,
++ .read_event_config = &lis331dlh_intel_cln_read_event_config,
++ .write_event_config = &lis331dlh_intel_cln_write_event_config,
++ .read_event_value = &lis331dlh_intel_cln_read_event_value,
++ .write_event_value = &lis331dlh_intel_cln_write_event_value,
++};
++
++static const struct iio_chan_spec st_accel_12bit_channels[] = {
++ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_X, IIO_MOD_X, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_X_L_ADDR),
++ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Y, IIO_MOD_Y, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Y_L_ADDR),
++ ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_SCAN_Z, IIO_MOD_Z, IIO_LE,
++ ST_SENSORS_DEFAULT_12_REALBITS, ST_ACCEL_DEFAULT_OUT_Z_L_ADDR),
++ IIO_CHAN_SOFT_TIMESTAMP(3)
++};
++
++static struct st_sensors lis331dlh_intel_cln_sensor = {
++ .wai = ST_ACCEL_2_WAI_EXP,
++ .sensors_supported = {
++ [0] = "lis331dlh_cln",
++ },
++ .ch = (struct iio_chan_spec *)st_accel_12bit_channels,
++ .odr = {
++ .addr = ST_ACCEL_2_ODR_ADDR,
++ .mask = ST_ACCEL_2_ODR_MASK,
++ .odr_avl = {
++ { 50, ST_ACCEL_2_ODR_AVL_50HZ_VAL, },
++ { 100, ST_ACCEL_2_ODR_AVL_100HZ_VAL, },
++ { 400, ST_ACCEL_2_ODR_AVL_400HZ_VAL, },
++ { 1000, ST_ACCEL_2_ODR_AVL_1000HZ_VAL, },
++ },
++ },
++ .pw = {
++ .addr = ST_ACCEL_2_PW_ADDR,
++ .mask = ST_ACCEL_2_PW_MASK,
++ .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
++ .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
++ },
++ .enable_axis = {
++ .addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
++ .mask = ST_SENSORS_DEFAULT_AXIS_MASK,
++ },
++ .fs = {
++ .addr = ST_ACCEL_2_FS_ADDR,
++ .mask = ST_ACCEL_2_FS_MASK,
++ .fs_avl = {
++ [0] = {
++ .num = ST_ACCEL_FS_AVL_2G,
++ .value = ST_ACCEL_2_FS_AVL_2_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_2_GAIN,
++ },
++ [1] = {
++ .num = ST_ACCEL_FS_AVL_4G,
++ .value = ST_ACCEL_2_FS_AVL_4_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_4_GAIN,
++ },
++ [2] = {
++ .num = ST_ACCEL_FS_AVL_8G,
++ .value = ST_ACCEL_2_FS_AVL_8_VAL,
++ .gain = ST_ACCEL_2_FS_AVL_8_GAIN,
++ },
++ },
++ },
++ .bdu = {
++ .addr = ST_ACCEL_2_BDU_ADDR,
++ .mask = ST_ACCEL_2_BDU_MASK,
++ },
++ .drdy_irq = {
++ .addr = ST_ACCEL_2_DRDY_IRQ_ADDR,
++ .mask = ST_ACCEL_2_DRDY_IRQ_MASK,
++ },
++ .multi_read_bit = ST_ACCEL_2_MULTIREAD_BIT,
++ .bootime = 2,
++};
++
++static int lis331dlh_intel_cln_probe(
++ struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct iio_dev *indio_dev;
++ struct st_sensor_data *adata;
++ struct lis331dlh_intel_cln_platform_data *pdata;
++ int ret = 0;
++
++ indio_dev = iio_device_alloc(sizeof(*adata));
++ if (indio_dev == NULL) {
++ ret = -ENOMEM;
++ goto iio_device_alloc_error;
++ }
++
++ i2c_set_clientdata(client, indio_dev);
++ indio_dev->dev.parent = &client->dev;
++ indio_dev->name = client->name;
++
++ adata = iio_priv(indio_dev);
++ adata->dev = &client->dev;
++
++ pdata = client->dev.platform_data;
++ if (!pdata) {
++ pr_err("No platform data provided\n");
++ goto lis331dlh_intel_cln_init_err;
++ }
++
++ ret = gpio_to_irq(pdata->irq1_pin);
++ if (ret < 0) {
++ pr_err(
++ "Failed to obtain valid IRQ for GPIO %d, "
++ "gpio_to_irq returned %d\n",
++ pdata->irq1_pin, ret);
++ goto lis331dlh_intel_cln_init_err;
++ }
++ to_i2c_client(adata->dev)->irq = ret;
++
++ st_sensors_i2c_configure(indio_dev, client, adata);
++
++ indio_dev->modes = INDIO_DIRECT_MODE;
++ indio_dev->info = &accel_info;
++
++ ret = st_sensors_check_device_support(indio_dev,
++ 1, &lis331dlh_intel_cln_sensor);
++ if (ret < 0)
++ goto lis331dlh_intel_cln_init_err;
++
++ indio_dev->channels = adata->sensor->ch;
++ indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS;
++
++ adata->multiread_bit = adata->sensor->multi_read_bit;
++ adata->current_fullscale = (struct st_sensor_fullscale_avl *)
++ &adata->sensor->fs.fs_avl[0];
++ adata->odr = adata->sensor->odr.odr_avl[0].hz;
++ adata->int_thresh = false;
++
++ ret = st_sensors_init_sensor(indio_dev);
++ if (ret < 0)
++ goto lis331dlh_intel_cln_init_err;
++
++ ret = iio_device_register(indio_dev);
++ if (ret)
++ goto lis331dlh_intel_cln_init_err;
++
++ return 0;
++
++lis331dlh_intel_cln_init_err:
++ iio_device_free(indio_dev);
++iio_device_alloc_error:
++ return ret;
++}
++
++static int lis331dlh_intel_cln_remove(
++ struct i2c_client *client)
++{
++ struct iio_dev *indio_dev = i2c_get_clientdata(client);
++ struct st_sensor_data *adata = iio_priv(indio_dev);
++
++ st_sensors_set_enable(indio_dev, false);
++
++ if (adata->int_thresh)
++ free_irq(adata->get_irq_data_ready(indio_dev), indio_dev);
++
++ iio_device_unregister(indio_dev);
++
++ iio_device_free(indio_dev);
++
++ return 0;
++}
++
++#ifdef CONFIG_PM
++static int lis331dlh_intel_cln_suspend(
++ struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ lis331dlh_intel_cln_enable_wakeup_interrupt(indio_dev);
++
++ return 0;
++}
++
++static int lis331dlh_intel_cln_resume(
++ struct device *dev)
++{
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ lis331dlh_intel_cln_handle_wakeup_interrupt(indio_dev);
++ lis331dlh_intel_cln_disable_wakeup_interrupt(indio_dev);
++
++ return 0;
++}
++
++static const struct dev_pm_ops lis331dlh_intel_cln_pm_ops = {
++ .suspend = lis331dlh_intel_cln_suspend,
++ .resume = lis331dlh_intel_cln_resume,
++};
++
++#define LIS331DLH_INTEL_CLN_PM_OPS (&lis331dlh_intel_cln_pm_ops)
++#else
++#define LIS331DLH_INTEL_CLN_PM_OPS NULL
++#endif
++
++static const struct i2c_device_id lis331dlh_intel_cln_id_table[] = {
++ { "lis331dlh_cln" },
++ {},
++};
++MODULE_DEVICE_TABLE(i2c, lis331dlh_intel_cln_id_table);
++
++static struct i2c_driver lis331dlh_intel_cln_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "lis331dlh_cln",
++ .pm = LIS331DLH_INTEL_CLN_PM_OPS,
++ },
++ .probe = lis331dlh_intel_cln_probe,
++ .remove = lis331dlh_intel_cln_remove,
++ .id_table = lis331dlh_intel_cln_id_table,
++};
++
++module_i2c_driver(lis331dlh_intel_cln_driver);
++
++MODULE_AUTHOR("Wojciech Ziemba <wojciech.ziemba@emutex.com>");
++MODULE_DESCRIPTION("STMicroelectronics LIS331DLH accelerometer i2c driver for Intel Clanton platform");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c
+index b34d754..60491e4 100644
+--- a/drivers/iio/adc/ad7298.c
++++ b/drivers/iio/adc/ad7298.c
+@@ -33,7 +33,6 @@
+ #define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */
+ #define AD7298_PDD (1 << 0) /* partial power down enable */
+
+-#define AD7298_MAX_CHAN 8
+ #define AD7298_BITS 12
+ #define AD7298_STORAGE_BITS 16
+ #define AD7298_INTREF_mV 2500
+@@ -46,6 +45,7 @@ struct ad7298_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ unsigned ext_ref;
++ u16 ext_vin_max[AD7298_MAX_CHAN];
+ struct spi_transfer ring_xfer[10];
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message ring_msg;
+@@ -64,7 +64,7 @@ struct ad7298_state {
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
+- IIO_CHAN_INFO_SCALE_SHARED_BIT, \
++ IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
+ .address = index, \
+ .scan_index = index, \
+ .scan_type = { \
+@@ -269,7 +269,10 @@ static int ad7298_read_raw(struct iio_dev *indio_dev,
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+- *val = ad7298_get_ref_voltage(st);
++ if (st->ext_vin_max[chan->channel])
++ *val = st->ext_vin_max[chan->channel];
++ else
++ *val = ad7298_get_ref_voltage(st);
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_TEMP:
+@@ -304,8 +307,15 @@ static int ad7298_probe(struct spi_device *spi)
+
+ st = iio_priv(indio_dev);
+
+- if (pdata && pdata->ext_ref)
+- st->ext_ref = AD7298_EXTREF;
++ if (pdata) {
++ int i;
++
++ if (pdata->ext_ref)
++ st->ext_ref = AD7298_EXTREF;
++
++ for (i = 0; i < AD7298_MAX_CHAN; i++)
++ st->ext_vin_max[i] = pdata->ext_vin_max[i];
++ }
+
+ if (st->ext_ref) {
+ st->reg = regulator_get(&spi->dev, "vref");
+diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
+index ed45ee5..3c77727 100644
+--- a/drivers/iio/common/Kconfig
++++ b/drivers/iio/common/Kconfig
+@@ -2,4 +2,4 @@
+ # IIO common modules
+ #
+
+-source "drivers/iio/common/hid-sensors/Kconfig"
++source "drivers/iio/common/st_sensors/Kconfig"
+\ No newline at end of file
+diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
+index 8158400..4d22a20 100644
+--- a/drivers/iio/common/Makefile
++++ b/drivers/iio/common/Makefile
+@@ -6,4 +6,4 @@
+ # instead of duplicating in each module.
+ #
+
+-obj-y += hid-sensors/
++obj-y += st_sensors/
+\ No newline at end of file
+diff --git a/drivers/iio/common/st_sensors/Kconfig b/drivers/iio/common/st_sensors/Kconfig
+new file mode 100644
+index 0000000..d1b474a
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/Kconfig
+@@ -0,0 +1,20 @@
++#
++# STMicroelectronics sensors common library
++#
++
++menu "STMicro sensors"
++config IIO_ST_SENSORS_I2C
++ tristate "IIO ST SENSORS"
++ help
++ Enable SENSORS I2C option
++
++config IIO_ST_SENSORS_SPI
++ tristate "IIO SENSORS SPI"
++ help
++ Enable IIO_ST_SENSORS_SPI
++
++config IIO_ST_SENSORS_CORE
++ tristate "IIO SENSORS CORE"
++ select IIO_ST_SENSORS_I2C if I2C
++ select IIO_ST_SENSORS_SPI if SPI_MASTER
++endmenu
+diff --git a/drivers/iio/common/st_sensors/Makefile b/drivers/iio/common/st_sensors/Makefile
+new file mode 100644
+index 0000000..9f3e24f
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the STMicroelectronics sensor common modules.
++#
++
++obj-$(CONFIG_IIO_ST_SENSORS_I2C) += st_sensors_i2c.o
++obj-$(CONFIG_IIO_ST_SENSORS_SPI) += st_sensors_spi.o
++obj-$(CONFIG_IIO_ST_SENSORS_CORE) += st_sensors.o
++st_sensors-y := st_sensors_core.o
++st_sensors-$(CONFIG_IIO_BUFFER) += st_sensors_buffer.o
++st_sensors-$(CONFIG_IIO_TRIGGER) += st_sensors_trigger.o
+diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c
+new file mode 100644
+index 0000000..09b236d
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c
+@@ -0,0 +1,116 @@
++/*
++ * STMicroelectronics sensors buffer library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/trigger.h>
++#include <linux/interrupt.h>
++#include <linux/iio/buffer.h>
++#include <linux/iio/trigger_consumer.h>
++#include <linux/iio/triggered_buffer.h>
++#include <linux/irqreturn.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf)
++{
++ int i, n = 0, len;
++ u8 addr[ST_SENSORS_NUMBER_DATA_CHANNELS];
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ for (i = 0; i < ST_SENSORS_NUMBER_DATA_CHANNELS; i++) {
++ if (test_bit(i, indio_dev->active_scan_mask)) {
++ addr[n] = indio_dev->channels[i].address;
++ n++;
++ }
++ }
++ switch (n) {
++ case 1:
++ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL, buf,
++ sdata->multiread_bit);
++ break;
++ case 2:
++ if ((addr[1] - addr[0]) == ST_SENSORS_BYTE_FOR_CHANNEL) {
++ len = sdata->tf->read_multiple_byte(&sdata->tb,
++ sdata->dev, addr[0],
++ ST_SENSORS_BYTE_FOR_CHANNEL*n,
++ buf, sdata->multiread_bit);
++ } else {
++ u8 rx_array[ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS];
++ len = sdata->tf->read_multiple_byte(&sdata->tb,
++ sdata->dev, addr[0],
++ ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS,
++ rx_array, sdata->multiread_bit);
++ if (len < 0)
++ goto read_data_channels_error;
++
++ for (i = 0; i < n * ST_SENSORS_NUMBER_DATA_CHANNELS;
++ i++) {
++ if (i < n)
++ buf[i] = rx_array[i];
++ else
++ buf[i] = rx_array[n + i];
++ }
++ len = ST_SENSORS_BYTE_FOR_CHANNEL*n;
++ }
++ break;
++ case 3:
++ len = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ addr[0], ST_SENSORS_BYTE_FOR_CHANNEL*
++ ST_SENSORS_NUMBER_DATA_CHANNELS,
++ buf, sdata->multiread_bit);
++ break;
++ default:
++ len = -EINVAL;
++ goto read_data_channels_error;
++ }
++ if (len != ST_SENSORS_BYTE_FOR_CHANNEL*n) {
++ len = -EIO;
++ goto read_data_channels_error;
++ }
++
++read_data_channels_error:
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_get_buffer_element);
++
++irqreturn_t st_sensors_trigger_handler(int irq, void *p)
++{
++ int len;
++ struct iio_poll_func *pf = p;
++ struct iio_dev *indio_dev = pf->indio_dev;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
++ if (len < 0)
++ goto st_sensors_get_buffer_element_error;
++
++ if (indio_dev->scan_timestamp)
++ *(s64 *)((u8 *)sdata->buffer_data +
++ ALIGN(len, sizeof(s64))) = pf->timestamp;
++
++ iio_push_to_buffers(indio_dev, sdata->buffer_data);
++
++st_sensors_get_buffer_element_error:
++ iio_trigger_notify_done(indio_dev->trig);
++
++ return IRQ_HANDLED;
++}
++EXPORT_SYMBOL(st_sensors_trigger_handler);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors buffer");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c
+new file mode 100644
+index 0000000..9873869
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_core.c
+@@ -0,0 +1,435 @@
++/*
++ * STMicroelectronics sensors core library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/delay.h>
++#include <linux/iio/iio.h>
++#include <asm/unaligned.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++#define ST_SENSORS_WAI_ADDRESS 0x0f
++
++int st_sensors_write_data_with_mask(struct iio_dev *indio_dev,
++ u8 reg_addr, u8 mask, u8 data)
++{
++ int err;
++ u8 new_data;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data);
++ if (err < 0)
++ goto st_sensors_write_data_with_mask_error;
++
++ new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask));
++ err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data);
++
++st_sensors_write_data_with_mask_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_write_data_with_mask);
++
++static int st_sensors_match_odr(struct st_sensors *sensor,
++ unsigned int odr, struct st_sensor_odr_avl *odr_out)
++{
++ int i, ret = -EINVAL;
++
++ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
++ if (sensor->odr.odr_avl[i].hz == 0)
++ goto st_sensors_match_odr_error;
++
++ if (sensor->odr.odr_avl[i].hz == odr) {
++ odr_out->hz = sensor->odr.odr_avl[i].hz;
++ odr_out->value = sensor->odr.odr_avl[i].value;
++ ret = 0;
++ break;
++ }
++ }
++
++st_sensors_match_odr_error:
++ return ret;
++}
++
++int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
++{
++ int err;
++ struct st_sensor_odr_avl odr_out = {0, 0};
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = st_sensors_match_odr(sdata->sensor, odr, &odr_out);
++ if (err < 0)
++ goto st_sensors_match_odr_error;
++
++ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
++ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
++ if (sdata->enabled == true) {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->odr.addr,
++ sdata->sensor->odr.mask,
++ odr_out.value);
++ } else {
++ err = 0;
++ }
++ } else {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->odr.addr, sdata->sensor->odr.mask,
++ odr_out.value);
++ }
++ if (err >= 0)
++ sdata->odr = odr_out.hz;
++
++st_sensors_match_odr_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_odr);
++
++static int st_sensors_match_fs(struct st_sensors *sensor,
++ unsigned int fs, int *index_fs_avl)
++{
++ int i, ret = -EINVAL;
++
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if (sensor->fs.fs_avl[i].num == 0)
++ goto st_sensors_match_odr_error;
++
++ if (sensor->fs.fs_avl[i].num == fs) {
++ *index_fs_avl = i;
++ ret = 0;
++ break;
++ }
++ }
++
++st_sensors_match_odr_error:
++ return ret;
++}
++
++static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
++{
++ int err, i = 0;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = st_sensors_match_fs(sdata->sensor, fs, &i);
++ if (err < 0)
++ goto st_accel_set_fullscale_error;
++
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->fs.addr,
++ sdata->sensor->fs.mask,
++ sdata->sensor->fs.fs_avl[i].value);
++ if (err < 0)
++ goto st_accel_set_fullscale_error;
++
++ sdata->current_fullscale = (struct st_sensor_fullscale_avl *)
++ &sdata->sensor->fs.fs_avl[i];
++ return err;
++
++st_accel_set_fullscale_error:
++ dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
++ return err;
++}
++
++int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable)
++{
++ u8 tmp_value;
++ int err = -EINVAL;
++ bool found = false;
++ struct st_sensor_odr_avl odr_out = {0, 0};
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ if (enable) {
++ tmp_value = sdata->sensor->pw.value_on;
++ if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) &&
++ (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) {
++ err = st_sensors_match_odr(sdata->sensor,
++ sdata->odr, &odr_out);
++ if (err < 0)
++ goto set_enable_error;
++ tmp_value = odr_out.value;
++ found = true;
++ }
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->pw.addr,
++ sdata->sensor->pw.mask, tmp_value);
++ if (err < 0)
++ goto set_enable_error;
++
++ sdata->enabled = true;
++
++ if (found)
++ sdata->odr = odr_out.hz;
++ } else {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->pw.addr,
++ sdata->sensor->pw.mask,
++ sdata->sensor->pw.value_off);
++ if (err < 0)
++ goto set_enable_error;
++
++ sdata->enabled = false;
++ }
++
++set_enable_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_enable);
++
++int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->enable_axis.addr,
++ sdata->sensor->enable_axis.mask, axis_enable);
++}
++EXPORT_SYMBOL(st_sensors_set_axis_enable);
++
++int st_sensors_init_sensor(struct iio_dev *indio_dev)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_init(&sdata->tb.buf_lock);
++
++ err = st_sensors_set_enable(indio_dev, true);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_fullscale(indio_dev,
++ sdata->current_fullscale->num);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_odr(indio_dev, sdata->odr);
++ if (err < 0)
++ goto init_error;
++
++ /* set BDU */
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true);
++ if (err < 0)
++ goto init_error;
++
++ err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS);
++
++init_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_init_sensor);
++
++int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ /* Enable/Disable the interrupt generator 1. */
++ if (sdata->sensor->drdy_irq.ig1.en_addr > 0) {
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->drdy_irq.ig1.en_addr,
++ sdata->sensor->drdy_irq.ig1.en_mask, (int)enable);
++ if (err < 0)
++ goto st_accel_set_dataready_irq_error;
++ }
++
++ /* Enable/Disable the interrupt generator for data ready. */
++ err = st_sensors_write_data_with_mask(indio_dev,
++ sdata->sensor->drdy_irq.addr,
++ sdata->sensor->drdy_irq.mask, (int)enable);
++
++st_accel_set_dataready_irq_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_dataready_irq);
++
++int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale)
++{
++ int err = -EINVAL, i;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if ((sdata->sensor->fs.fs_avl[i].gain == scale) &&
++ (sdata->sensor->fs.fs_avl[i].gain != 0)) {
++ err = 0;
++ break;
++ }
++ }
++ if (err < 0)
++ goto st_sensors_match_scale_error;
++
++ err = st_sensors_set_fullscale(indio_dev,
++ sdata->sensor->fs.fs_avl[i].num);
++
++st_sensors_match_scale_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain);
++
++static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
++ u8 ch_addr, int *data)
++{
++ int err;
++ u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL];
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev,
++ ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL,
++ outdata, sdata->multiread_bit);
++ if (err < 0)
++ goto read_error;
++
++ *data = (s16)get_unaligned_le16(outdata);
++
++read_error:
++ return err;
++}
++
++int st_sensors_read_info_raw(struct iio_dev *indio_dev,
++ struct iio_chan_spec const *ch, int *val)
++{
++ int err;
++
++ mutex_lock(&indio_dev->mlock);
++ err = st_sensors_read_axis_data(indio_dev, ch->address, val);
++ if (err < 0)
++ goto read_error;
++
++ *val = *val >> ch->scan_type.shift;
++ mutex_unlock(&indio_dev->mlock);
++
++ return err;
++
++read_error:
++ mutex_unlock(&indio_dev->mlock);
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_read_info_raw);
++
++int st_sensors_check_device_support(struct iio_dev *indio_dev,
++ int num_sensors_list, const struct st_sensors *sensors)
++{
++ u8 wai;
++ int i, n, err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ err = sdata->tf->read_byte(&sdata->tb, sdata->dev,
++ ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai);
++ if (err < 0) {
++ dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n");
++ goto read_wai_error;
++ }
++
++ for (i = 0; i < num_sensors_list; i++) {
++ if (sensors[i].wai == wai)
++ break;
++ }
++ if (i == num_sensors_list)
++ goto device_not_supported;
++
++ for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) {
++ if (strcmp(indio_dev->name,
++ &sensors[i].sensors_supported[n][0]) == 0)
++ break;
++ }
++ if (n == ARRAY_SIZE(sensors[i].sensors_supported)) {
++ dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n");
++ goto sensor_name_mismatch;
++ }
++
++ sdata->sensor = (struct st_sensors *)&sensors[i];
++
++ return i;
++
++device_not_supported:
++ dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai);
++sensor_name_mismatch:
++ err = -ENODEV;
++read_wai_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_check_device_support);
++
++ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev));
++
++ return sprintf(buf, "%d\n", adata->odr);
++}
++EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency);
++
++ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev,
++ struct device_attribute *attr, const char *buf, size_t size)
++{
++ int err;
++ unsigned int odr;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++
++ err = kstrtoint(buf, 10, &odr);
++ if (err < 0)
++ goto conversion_error;
++
++ mutex_lock(&indio_dev->mlock);
++ err = st_sensors_set_odr(indio_dev, odr);
++ mutex_unlock(&indio_dev->mlock);
++
++conversion_error:
++ return err < 0 ? err : size;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency);
++
++ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i, len = 0;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) {
++ if (sdata->sensor->odr.odr_avl[i].hz == 0)
++ break;
++
++ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
++ sdata->sensor->odr.odr_avl[i].hz);
++ }
++ mutex_unlock(&indio_dev->mlock);
++ buf[len - 1] = '\n';
++
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail);
++
++ssize_t st_sensors_sysfs_scale_avail(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ int i, len = 0;
++ struct iio_dev *indio_dev = dev_get_drvdata(dev);
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ mutex_lock(&indio_dev->mlock);
++ for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) {
++ if (sdata->sensor->fs.fs_avl[i].num == 0)
++ break;
++
++ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
++ sdata->sensor->fs.fs_avl[i].gain);
++ }
++ mutex_unlock(&indio_dev->mlock);
++ buf[len - 1] = '\n';
++
++ return len;
++}
++EXPORT_SYMBOL(st_sensors_sysfs_scale_avail);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors core");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c
+new file mode 100644
+index 0000000..f8e82c5
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c
+@@ -0,0 +1,80 @@
++/*
++ * STMicroelectronics sensors i2c library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++
++#include <linux/iio/common/st_sensors_i2c.h>
++
++#define ST_SENSORS_I2C_MULTIREAD 0x80
++
++static unsigned int st_sensors_i2c_get_irq(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return to_i2c_client(sdata->dev)->irq;
++}
++
++static int st_sensors_i2c_read_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 *res_byte)
++{
++ int err;
++
++ err = i2c_smbus_read_byte_data(to_i2c_client(dev), reg_addr);
++ if (err < 0)
++ goto st_accel_i2c_read_byte_error;
++
++ *res_byte = err & 0xff;
++
++st_accel_i2c_read_byte_error:
++ return err < 0 ? err : 0;
++}
++
++static int st_sensors_i2c_read_multiple_byte(
++ struct st_sensor_transfer_buffer *tb, struct device *dev,
++ u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ if (multiread_bit)
++ reg_addr |= ST_SENSORS_I2C_MULTIREAD;
++
++ return i2c_smbus_read_i2c_block_data(to_i2c_client(dev),
++ reg_addr, len, data);
++}
++
++static int st_sensors_i2c_write_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 data)
++{
++ return i2c_smbus_write_byte_data(to_i2c_client(dev), reg_addr, data);
++}
++
++static const struct st_sensor_transfer_function st_sensors_tf_i2c = {
++ .read_byte = st_sensors_i2c_read_byte,
++ .write_byte = st_sensors_i2c_write_byte,
++ .read_multiple_byte = st_sensors_i2c_read_multiple_byte,
++};
++
++void st_sensors_i2c_configure(struct iio_dev *indio_dev,
++ struct i2c_client *client, struct st_sensor_data *sdata)
++{
++ i2c_set_clientdata(client, indio_dev);
++
++ indio_dev->dev.parent = &client->dev;
++ indio_dev->name = client->name;
++
++ sdata->tf = &st_sensors_tf_i2c;
++ sdata->get_irq_data_ready = st_sensors_i2c_get_irq;
++}
++EXPORT_SYMBOL(st_sensors_i2c_configure);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
+new file mode 100644
+index 0000000..f0aa2f1
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
+@@ -0,0 +1,128 @@
++/*
++ * STMicroelectronics sensors spi library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++
++#include <linux/iio/common/st_sensors_spi.h>
++
++
++#define ST_SENSORS_SPI_MULTIREAD 0xc0
++#define ST_SENSORS_SPI_READ 0x80
++
++static unsigned int st_sensors_spi_get_irq(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ return to_spi_device(sdata->dev)->irq;
++}
++
++static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ struct spi_message msg;
++ int err;
++
++ struct spi_transfer xfers[] = {
++ {
++ .tx_buf = tb->tx_buf,
++ .bits_per_word = 8,
++ .len = 1,
++ },
++ {
++ .rx_buf = tb->rx_buf,
++ .bits_per_word = 8,
++ .len = len,
++ }
++ };
++
++ mutex_lock(&tb->buf_lock);
++ if ((multiread_bit) && (len > 1))
++ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_MULTIREAD;
++ else
++ tb->tx_buf[0] = reg_addr | ST_SENSORS_SPI_READ;
++
++ spi_message_init(&msg);
++ spi_message_add_tail(&xfers[0], &msg);
++ spi_message_add_tail(&xfers[1], &msg);
++ err = spi_sync(to_spi_device(dev), &msg);
++ if (err)
++ goto acc_spi_read_error;
++
++ memcpy(data, tb->rx_buf, len*sizeof(u8));
++ mutex_unlock(&tb->buf_lock);
++ return len;
++
++acc_spi_read_error:
++ mutex_unlock(&tb->buf_lock);
++ return err;
++}
++
++static int st_sensors_spi_read_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 *res_byte)
++{
++ return st_sensors_spi_read(tb, dev, reg_addr, 1, res_byte, false);
++}
++
++static int st_sensors_spi_read_multiple_byte(
++ struct st_sensor_transfer_buffer *tb, struct device *dev,
++ u8 reg_addr, int len, u8 *data, bool multiread_bit)
++{
++ return st_sensors_spi_read(tb, dev, reg_addr, len, data, multiread_bit);
++}
++
++static int st_sensors_spi_write_byte(struct st_sensor_transfer_buffer *tb,
++ struct device *dev, u8 reg_addr, u8 data)
++{
++ struct spi_message msg;
++ int err;
++
++ struct spi_transfer xfers = {
++ .tx_buf = tb->tx_buf,
++ .bits_per_word = 8,
++ .len = 2,
++ };
++
++ mutex_lock(&tb->buf_lock);
++ tb->tx_buf[0] = reg_addr;
++ tb->tx_buf[1] = data;
++
++ spi_message_init(&msg);
++ spi_message_add_tail(&xfers, &msg);
++ err = spi_sync(to_spi_device(dev), &msg);
++ mutex_unlock(&tb->buf_lock);
++
++ return err;
++}
++
++static const struct st_sensor_transfer_function st_sensors_tf_spi = {
++ .read_byte = st_sensors_spi_read_byte,
++ .write_byte = st_sensors_spi_write_byte,
++ .read_multiple_byte = st_sensors_spi_read_multiple_byte,
++};
++
++void st_sensors_spi_configure(struct iio_dev *indio_dev,
++ struct spi_device *spi, struct st_sensor_data *sdata)
++{
++ spi_set_drvdata(spi, indio_dev);
++
++ indio_dev->dev.parent = &spi->dev;
++ indio_dev->name = spi->modalias;
++
++ sdata->tf = &st_sensors_tf_spi;
++ sdata->get_irq_data_ready = st_sensors_spi_get_irq;
++}
++EXPORT_SYMBOL(st_sensors_spi_configure);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors spi driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c
+new file mode 100644
+index 0000000..8b4dd48
+--- /dev/null
++++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c
+@@ -0,0 +1,78 @@
++/*
++ * STMicroelectronics sensors trigger library driver
++ *
++ * Copyright 2012-2013 STMicroelectronics Inc.
++ *
++ * Denis Ciocca <denis.ciocca@st.com>
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/iio/iio.h>
++#include <linux/iio/trigger.h>
++#include <linux/interrupt.h>
++
++#include <linux/iio/common/st_sensors.h>
++
++
++int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
++ const struct iio_trigger_ops *trigger_ops)
++{
++ int err;
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ sdata->trig = iio_trigger_alloc("%s-trigger", indio_dev->name);
++ if (sdata->trig == NULL) {
++ err = -ENOMEM;
++ dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
++ goto iio_trigger_alloc_error;
++ }
++
++ err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
++ iio_trigger_generic_data_rdy_poll,
++ NULL,
++ IRQF_SHARED | /* sharing with the accelerometer events*/
++ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
++ sdata->trig->name,
++ sdata->trig);
++ if (err)
++ goto request_irq_error;
++
++ sdata->trig->private_data = indio_dev;
++ sdata->trig->ops = trigger_ops;
++ sdata->trig->dev.parent = sdata->dev;
++
++ err = iio_trigger_register(sdata->trig);
++ if (err < 0) {
++ dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
++ goto iio_trigger_register_error;
++ }
++ indio_dev->trig = sdata->trig;
++
++ return 0;
++
++iio_trigger_register_error:
++ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
++request_irq_error:
++ iio_trigger_free(sdata->trig);
++iio_trigger_alloc_error:
++ return err;
++}
++EXPORT_SYMBOL(st_sensors_allocate_trigger);
++
++void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
++{
++ struct st_sensor_data *sdata = iio_priv(indio_dev);
++
++ iio_trigger_unregister(sdata->trig);
++ free_irq(sdata->get_irq_data_ready(indio_dev), sdata->trig);
++ iio_trigger_free(sdata->trig);
++}
++EXPORT_SYMBOL(st_sensors_deallocate_trigger);
++
++MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
++MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
++MODULE_LICENSE("GPL v2");
+diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
+index aaadd32..7b8d510 100644
+--- a/drivers/iio/industrialio-buffer.c
++++ b/drivers/iio/industrialio-buffer.c
+@@ -119,8 +119,8 @@ static ssize_t iio_scan_el_show(struct device *dev,
+ int ret;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+
+- ret = test_bit(to_iio_dev_attr(attr)->address,
+- indio_dev->buffer->scan_mask);
++ ret = abs(test_bit(to_iio_dev_attr(attr)->address,
++ indio_dev->buffer->scan_mask));
+
+ return sprintf(buf, "%d\n", ret);
+ }
+@@ -762,7 +762,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev,
+ if (!buffer->scan_mask)
+ return 0;
+
+- return test_bit(bit, buffer->scan_mask);
++ return abs(test_bit(bit, buffer->scan_mask));
+ };
+ EXPORT_SYMBOL_GPL(iio_scan_mask_query);
+
+diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c
+index 3e24571..da30c5c 100644
+--- a/drivers/isdn/mISDN/core.c
++++ b/drivers/isdn/mISDN/core.c
+@@ -168,13 +168,13 @@ static struct class mISDN_class = {
+ };
+
+ static int
+-_get_mdevice(struct device *dev, void *id)
++_get_mdevice(struct device *dev, const void *id)
+ {
+ struct mISDNdevice *mdev = dev_to_mISDN(dev);
+
+ if (!mdev)
+ return 0;
+- if (mdev->id != *(u_int *)id)
++ if (mdev->id != *(const u_int *)id)
+ return 0;
+ return 1;
+ }
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index ff553ba..be79f4a 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -907,6 +907,44 @@ config MFD_TIMBERDALE
+ The timberdale FPGA can be found on the Intel Atom development board
+ for in-vehicle infontainment, called Russellville.
+
++config CY8C9540A
++ tristate "Cypress CY8C9540 GPIO/PWM expander"
++ depends on INTEL_CLN_GIP
++ depends on PWM
++ help
++ I/O expander providing GPIO/PWM functionality.
++ This is Clanton-specific for now.
++
++config INTEL_CLN_GIP
++ tristate "Intel Clanton GIP"
++ depends on PCI && X86 && INTEL_QUARK_X1000_SOC
++ depends on I2C
++ select GENERIC_IRQ_CHIP
++ help
++ GIP driver for Clanton SoC.
++ Clanton GIP is a single PCI function exporting a GPIO and an I2C
++ controller, namely Synopsys DesignWare GPIO and Synopsys DesignWare
++ I2C. The GPIO interface exports a total amount of 8 interrupt-capable
++ GPIOs.
++
++config INTEL_CLN_GIP_TEST
++ tristate "Intel Clanton GIP support for Integration Testing"
++ depends on INTEL_CLN_GIP
++ depends on INTEL_QUARK_X1000_SOC_FPGAEMU || INTEL_QUARK_X1000_SOC_SVP
++ select I2C_CHARDEV
++ select GPIO_SYSFS
++ select SPI
++ select SPI_BITBANG
++ select SPI_GPIO
++ select SPI_MASTER
++ select SPI_SPIDEV
++ help
++ Clanton GIP automated Integration Testing package.
++ It selects kernel components needed for GPIO and I2C tests as per
++ Integration Test Specification, and it also adds a kernel-space
++ facility for testing the GPIO.
++ Note this module is also used to test the Clanton Legacy GPIO.
++
+ config LPC_SCH
+ tristate "Intel SCH LPC"
+ depends on PCI
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 8b977f8..2fb8008 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -123,6 +123,13 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
+ obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
+ obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
+ obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
++obj-$(CONFIG_CY8C9540A) += cy8c9540a.o
++obj-$(CONFIG_INTEL_CLN_GIP) += intel_cln_gip.o
++intel_cln_gip-objs := intel_cln_gip_core.o \
++ intel_cln_gip_gpio.o \
++ intel_cln_gip_i2c.o \
++ ../i2c/busses/i2c-designware-core.o
++obj-$(CONFIG_INTEL_CLN_GIP_TEST)+=intel_cln_gip_test.o
+ obj-$(CONFIG_LPC_SCH) += lpc_sch.o
+ obj-$(CONFIG_LPC_ICH) += lpc_ich.o
+ obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
+diff --git a/drivers/mfd/cy8c9540a.c b/drivers/mfd/cy8c9540a.c
+new file mode 100644
+index 0000000..9d83e32
+--- /dev/null
++++ b/drivers/mfd/cy8c9540a.c
+@@ -0,0 +1,1022 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++
++/*
++ * Driver for Cypress CY8C9540A I/O Expander and PWM
++ *
++ * Izmir-specific.
++ * Based on gpio-adp5588.
++ */
++
++#include <linux/delay.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/gpio.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pwm.h>
++#include <linux/slab.h>
++
++#define DRV_NAME "cy8c9540a"
++
++/* CY8C9540A settings */
++#define NGPIO 40
++#define NPWM 8
++#define PWM_MAX_PERIOD 0xff
++#define DEVID_FAMILY_CY8C9540A 0x40
++#define DEVID_FAMILY_MASK 0xf0
++#define NPORTS 6
++#define I2C_A0_ADDR_MASK 0x0001
++#define POR_SETTINGS_LEN 147
++
++/* Register offset */
++#define REG_INPUT_PORT0 0x00
++#define REG_OUTPUT_PORT0 0x08
++#define REG_INTR_STAT_PORT0 0x10
++#define REG_PORT_SELECT 0x18
++#define REG_INTR_MASK 0x19
++#define REG_SELECT_PWM 0x1a
++#define REG_PIN_DIR 0x1c
++#define REG_DRIVE_PULLUP 0x1d
++#define REG_PWM_SELECT 0x28
++#define REG_PWM_CLK 0x29
++#define REG_PWM_PERIOD 0x2a
++#define REG_PWM_PULSE_W 0x2b
++#define REG_ENABLE 0x2d
++#define REG_DEVID_STAT 0x2e
++#define REG_CMD 0x30
++
++/* Commands */
++#define CMD_W_EEPROM_POR 0x03
++#define CMD_R_EEPROM_POR 0x04
++#define CMD_RECONF_DEV 0x07
++
++/* Galileo-specific POR default settings */
++#define POR_CMD_W_OFFS 2
++static u8 por_default[POR_SETTINGS_LEN + POR_CMD_W_OFFS] = {
++ REG_CMD, CMD_W_EEPROM_POR,
++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Output */
++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Interrupt mask */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* PWM */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Inversion */
++ 0xe0, 0xe0, 0xff, 0xf3, 0x00, 0xff, 0xff, 0xff, /* Direction */
++ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* Port0 drive mode */
++ 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, /* Port1 drive mode */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Port2 drive mode */
++ 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, /* Port3 drive mode */
++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* Port4 drive mode */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Port5 drive mode */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Port6 drive mode */
++ 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Port7 drive mode */
++ 0x00, 0xff, 0x00, /* PWM0 */
++ 0x00, 0xff, 0x00, /* PWM1 */
++ 0x00, 0xff, 0x00, /* PWM2 */
++ 0x00, 0xff, 0x00, /* PWM3 */
++ 0x00, 0xff, 0x00, /* PWM4 */
++ 0x00, 0xff, 0x00, /* PWM5 */
++ 0x00, 0xff, 0x00, /* PWM6 */
++ 0x00, 0xff, 0x00, /* PWM7 */
++ 0x00, 0xff, 0x00, /* PWM8 */
++ 0x00, 0xff, 0x00, /* PWM9 */
++ 0x00, 0xff, 0x00, /* PWM10 */
++ 0x00, 0xff, 0x00, /* PWM11 */
++ 0x00, 0xff, 0x00, /* PWM12 */
++ 0x00, 0xff, 0x00, /* PWM13 */
++ 0x00, 0xff, 0x00, /* PWM14 */
++ 0x00, 0xff, 0x00, /* PWM15 */
++ 0xff, /* PWM CLK divider */
++ 0x02, /* EEPROM enable */
++ 0x00 /* CRC (placeholder) */
++};
++
++struct cy8c9540a {
++ struct i2c_client *client;
++ struct gpio_chip gpio_chip;
++ struct pwm_chip pwm_chip;
++ struct mutex lock;
++ /* protect serialized access to the interrupt controller bus */
++ struct mutex irq_lock;
++ /* cached output registers */
++ u8 outreg_cache[NPORTS];
++ /* cached IRQ mask */
++ u8 irq_mask_cache[NPORTS];
++ /* IRQ mask to be applied */
++ u8 irq_mask[NPORTS];
++ /* Descriptor for raw i2c transactions */
++ struct i2c_msg i2c_segments[2];
++ /* POR settings stored in the EEPROM */
++ u8 por_stored[POR_SETTINGS_LEN];
++};
++
++/* Per-port GPIO offset */
++static const u8 cy8c9540a_port_offs[] = {
++ 0,
++ 8,
++ 16,
++ 20,
++ 28,
++ 36,
++};
++
++/* Galileo-specific data. */
++
++#define GPIO_BASE_ID 16
++#define GPIO_IRQBASE 64
++#define PWM_BASE_ID 0
++#define PWM_CLK 0x00 /* see resulting PWM_TCLK_NS */
++#define PWM_TCLK_NS 31250 /* 32kHz */
++#define SOC_GPIO_INT_PIN 13
++#define SOC_GPIO_I2C_A0 7
++
++/* PWM-to-GPIO mapping (0 == first Cypress GPIO). */
++#define PWM_UNUSED -1
++static const int pwm2gpio_mapping[] = {
++ PWM_UNUSED,
++ 3,
++ PWM_UNUSED,
++ 2,
++ 9,
++ 1,
++ 8,
++ 0,
++};
++
++static inline u8 cypress_get_port(unsigned gpio)
++{
++ u8 i = 0;
++ for (i = 0; i < sizeof(cy8c9540a_port_offs) - 1; i ++) {
++ if (! (gpio / cy8c9540a_port_offs[i + 1]))
++ break;
++ }
++ return i;
++}
++
++static inline u8 cypress_get_offs(unsigned gpio, u8 port)
++{
++ return gpio - cy8c9540a_port_offs[port];
++}
++
++static int cy8c9540a_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
++{
++ s32 ret = 0;
++ u8 port = 0;
++ u8 in_reg = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++
++ port = cypress_get_port(gpio);
++ in_reg = REG_INPUT_PORT0 + port;
++
++ ret = i2c_smbus_read_byte_data(client, in_reg);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read input port%u\n", in_reg);
++ }
++
++ return !!(ret & BIT(cypress_get_offs(gpio, port)));
++}
++
++static void cy8c9540a_gpio_set_value(struct gpio_chip *chip,
++ unsigned gpio, int val)
++{
++ s32 ret = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++ u8 out_reg = REG_OUTPUT_PORT0 + port;
++
++ mutex_lock(&dev->lock);
++
++ if (val) {
++ dev->outreg_cache[port] |= BIT(cypress_get_offs(gpio, port));
++ } else {
++ dev->outreg_cache[port] &= ~BIT(cypress_get_offs(gpio, port));
++ }
++
++ ret = i2c_smbus_write_byte_data(client, out_reg,
++ dev->outreg_cache[port]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write output port%u\n", port);
++ }
++
++ mutex_unlock(&dev->lock);
++}
++
++static int cy8c9540a_gpio_set_drive(struct gpio_chip *chip, unsigned gpio,
++ unsigned mode)
++{
++ int ret = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++ u8 pin = cypress_get_offs(gpio, port);
++ u8 offs = 0;
++ u8 val = 0;
++
++ switch(mode) {
++ case GPIOF_DRIVE_PULLUP:
++ offs = 0x0;
++ break;
++ case GPIOF_DRIVE_STRONG:
++ offs = 0x4;
++ break;
++ case GPIOF_DRIVE_HIZ:
++ offs = 0x6;
++ break;
++ default:
++ /*
++ * See databook for alternative modes. This driver won't
++ * support them though.
++ */
++ return -EINVAL;
++ break;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", port);
++ goto end;
++ }
++
++ ret = i2c_smbus_read_byte_data(client, REG_DRIVE_PULLUP + offs);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read pin direction\n");
++ goto end;
++ }
++
++ val = (u8)(ret | BIT(pin));
++
++ ret = i2c_smbus_write_byte_data(client, REG_DRIVE_PULLUP + offs, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't set drive mode port %u\n", port);
++ goto end;
++ }
++
++ ret = 0;
++
++end:
++ mutex_unlock(&dev->lock);
++ return ret;
++}
++
++static int cy8c9540a_gpio_direction(struct gpio_chip *chip, unsigned gpio,
++ int out, int val)
++{
++ s32 ret = 0;
++ u8 pins = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, gpio_chip);
++ struct i2c_client *client = dev->client;
++ u8 port = cypress_get_port(gpio);
++
++ ret = cy8c9540a_gpio_set_drive(chip, gpio, out ?
++ GPIOF_DRIVE_STRONG : GPIOF_DRIVE_HIZ);
++ if (ret) {
++ return ret;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, port);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", port);
++ goto end;
++ }
++
++ ret = i2c_smbus_read_byte_data(client, REG_PIN_DIR);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't read pin direction\n");
++ goto end;
++ }
++
++ pins = (u8)ret & 0xff;
++ if (out) {
++ pins &= ~BIT(cypress_get_offs(gpio, port));
++ } else {
++ pins |= BIT(cypress_get_offs(gpio, port));
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PIN_DIR, pins);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write pin direction\n");
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++ return ret;
++}
++
++static int cy8c9540a_gpio_direction_output(struct gpio_chip *chip,
++ unsigned gpio, int val)
++{
++ return cy8c9540a_gpio_direction(chip, gpio, 1, val);
++}
++
++static int cy8c9540a_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
++{
++ return cy8c9540a_gpio_direction(chip, gpio, 0, 0);
++}
++
++static void cy8c9540a_irq_bus_lock(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ mutex_lock(&dev->irq_lock);
++}
++
++static void cy8c9540a_irq_bus_sync_unlock(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ struct i2c_client *client = dev->client;
++ int ret = 0;
++ int i = 0;
++
++ for (i = 0; i < NPORTS; i++) {
++ if (dev->irq_mask_cache[i] ^ dev->irq_mask[i]) {
++ dev->irq_mask_cache[i] = dev->irq_mask[i];
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", i);
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write int mask on port %u\n", i);
++ goto end;
++ }
++
++ }
++ }
++
++end:
++ mutex_unlock(&dev->irq_lock);
++}
++
++static void cy8c9540a_irq_mask(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ unsigned gpio = d->irq - GPIO_IRQBASE;
++ u8 port = cypress_get_port(gpio);
++
++ dev->irq_mask[port] |= BIT(cypress_get_offs(gpio, port));
++}
++
++static void cy8c9540a_irq_unmask(struct irq_data *d)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ unsigned gpio = d->irq - GPIO_IRQBASE;
++ u8 port = cypress_get_port(gpio);
++
++ dev->irq_mask[port] &= ~BIT(cypress_get_offs(gpio, port));
++}
++
++static int cy8c9540a_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
++{
++ return GPIO_IRQBASE + gpio;
++}
++
++static int cy8c9540a_irq_set_type(struct irq_data *d, unsigned int type)
++{
++ struct cy8c9540a *dev = irq_data_get_irq_chip_data(d);
++ int ret = 0;
++
++ if ((type != IRQ_TYPE_EDGE_BOTH)) {
++ dev_err(&dev->client->dev, "irq %d: unsupported type %d\n",
++ d->irq, type);
++ ret = -EINVAL;
++ goto end;
++ }
++
++end:
++ return ret;
++}
++
++static struct irq_chip cy8c9540a_irq_chip = {
++ .name = "cy8c9540a-irq",
++ .irq_mask = cy8c9540a_irq_mask,
++ .irq_unmask = cy8c9540a_irq_unmask,
++ .irq_bus_lock = cy8c9540a_irq_bus_lock,
++ .irq_bus_sync_unlock = cy8c9540a_irq_bus_sync_unlock,
++ .irq_set_type = cy8c9540a_irq_set_type,
++};
++
++static irqreturn_t cy8c9540a_irq_handler(int irq, void *devid)
++{
++ struct cy8c9540a *dev = devid;
++ u8 stat[NPORTS], pending = 0;
++ unsigned port = 0, gpio = 0, gpio_irq = 0;
++ int ret = 0;
++
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
++ NPORTS, stat); /* W1C */
++ if (ret < 0) {
++ memset(stat, 0, sizeof(stat));
++ }
++
++ ret = IRQ_NONE;
++
++ for (port = 0; port < NPORTS; port ++) {
++ /* Databook doesn't specify if this is a post-mask status
++ register or not. Consider it 'raw' for safety. */
++ mutex_lock(&dev->irq_lock);
++ pending = stat[port] & (~dev->irq_mask[port]);
++ mutex_unlock(&dev->irq_lock);
++
++ while (pending) {
++ ret = IRQ_HANDLED;
++ gpio = __ffs(pending);
++ pending &= ~BIT(gpio);
++ gpio_irq = GPIO_IRQBASE + cy8c9540a_port_offs[port]
++ + gpio;
++ handle_nested_irq(gpio_irq);
++ }
++ }
++
++ return ret;
++}
++
++static int cy8c9540a_irq_setup(struct cy8c9540a *dev)
++{
++ struct i2c_client *client = dev->client;
++ u8 dummy[NPORTS];
++ unsigned gpio = 0;
++ int ret = 0;
++ int i = 0;
++
++ mutex_init(&dev->irq_lock);
++
++ /* Clear interrupt state */
++
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_INTR_STAT_PORT0,
++ NPORTS, dummy); /* W1C */
++ if (ret < 0) {
++ dev_err(&client->dev, "couldn't clear int status\n");
++ goto err;
++ }
++
++ /* Initialise interrupt mask */
++
++ memset(dev->irq_mask_cache, 0xff, sizeof(dev->irq_mask_cache));
++ memset(dev->irq_mask, 0xff, sizeof(dev->irq_mask));
++ for (i = 0; i < NPORTS; i++) {
++ ret = i2c_smbus_write_byte_data(client, REG_PORT_SELECT, i);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't select port %u\n", i);
++ goto err;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_INTR_MASK, dev->irq_mask[i]);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write int mask on port %u\n", i);
++ goto err;
++ }
++ }
++
++ /* Allocate external interrupt GPIO pin */
++
++ ret = gpio_request(SOC_GPIO_INT_PIN, "cy8c9540a-int");
++ if (ret) {
++ dev_err(&client->dev, "failed to request gpio%u\n",
++ SOC_GPIO_INT_PIN);
++ goto err;
++ }
++
++ /* Allocate IRQ descriptors for Cypress GPIOs and set handler */
++
++ ret = irq_alloc_descs(GPIO_IRQBASE, GPIO_IRQBASE, NGPIO, 0);
++ if (ret < 0) {
++ dev_err(&client->dev, "failed to allocate IRQ numbers\n");
++ goto err_free_gpio;
++ }
++
++ for (gpio = 0; gpio < NGPIO; gpio++) {
++ int irq = gpio + GPIO_IRQBASE;
++ irq_set_chip_data(irq, dev);
++ irq_set_chip_and_handler(irq, &cy8c9540a_irq_chip,
++ handle_edge_irq);
++ irq_set_nested_thread(irq, 1);
++ irq_set_noprobe(irq);
++ }
++
++ ret = request_threaded_irq(gpio_to_irq(SOC_GPIO_INT_PIN),
++ NULL,
++ cy8c9540a_irq_handler,
++ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
++ dev_name(&client->dev), dev);
++ if (ret) {
++ dev_err(&client->dev, "failed to request irq %d\n",
++ client->irq);
++ goto err_free_irq_descs;
++ }
++
++ return 0;
++
++err_free_irq_descs:
++ irq_free_descs(GPIO_IRQBASE, NGPIO);
++err_free_gpio:
++ gpio_free(SOC_GPIO_INT_PIN);
++err:
++ mutex_destroy(&dev->irq_lock);
++ return ret;
++}
++
++static void cy8c9540a_irq_teardown(struct cy8c9540a *dev)
++{
++ mutex_destroy(&dev->irq_lock);
++ irq_free_descs(GPIO_IRQBASE, NGPIO);
++ free_irq(gpio_to_irq(SOC_GPIO_INT_PIN), dev);
++ gpio_free(SOC_GPIO_INT_PIN);
++}
++
++static int cy8c9540a_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ int ret = 0;
++ int period = 0, duty = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm > NPWM) {
++ return -EINVAL;
++ }
++
++ period = period_ns / PWM_TCLK_NS;
++ duty = duty_ns / PWM_TCLK_NS;
++
++ /*
++ * Check period's upper bound. Note the duty cycle is already sanity
++ * checked by the PWM framework.
++ */
++ if (period > PWM_MAX_PERIOD) {
++ dev_err(&client->dev, "period must be within [0-%d]ns\n",
++ PWM_MAX_PERIOD * PWM_TCLK_NS);
++ return -EINVAL;
++ }
++
++ mutex_lock(&dev->lock);
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_SELECT, (u8)pwm->pwm);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_SELECT\n");
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_PERIOD, (u8)period);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_PERIOD\n");
++ goto end;
++ }
++
++ ret = i2c_smbus_write_byte_data(client, REG_PWM_PULSE_W, (u8)duty);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to REG_PWM_PULSE_W\n");
++ goto end;
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return ret;
++}
++
++static int cy8c9540a_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ int ret = 0;
++ int gpio = 0;
++ int port = 0, pin = 0;
++ u8 out_reg = 0;
++ u8 val = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm > NPWM) {
++ return -EINVAL;
++ }
++
++ gpio = pwm2gpio_mapping[pwm->pwm];
++ port = cypress_get_port(gpio);
++ pin = cypress_get_offs(gpio, port);
++ out_reg = REG_OUTPUT_PORT0 + port;
++
++ /* Set pin as output driving high */
++ ret = cy8c9540a_gpio_direction(&dev->gpio_chip, gpio, 1, 1);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't set pwm%u as output\n", pwm->pwm);
++ return ret;
++ }
++
++ mutex_lock(&dev->lock);
++
++ /* Enable PWM */
++ val = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
++ if (val < 0) {
++ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
++ ret = val;
++ goto end;
++ }
++ val |= BIT((u8)pin);
++ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to SELECT_PWM\n");
++ goto end;
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return ret;
++}
++
++static void cy8c9540a_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ int ret = 0;
++ int gpio = 0;
++ int port = 0, pin = 0;
++ u8 val = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm > NPWM) {
++ return;
++ }
++
++ gpio = pwm2gpio_mapping[pwm->pwm];
++ if (PWM_UNUSED == gpio) {
++ dev_err(&client->dev, "pwm%d is unused\n", pwm->pwm);
++ return;
++ }
++
++ port = cypress_get_port(gpio);
++ pin = cypress_get_offs(gpio, port);
++
++ mutex_lock(&dev->lock);
++
++ /* Disable PWM */
++ val = i2c_smbus_read_byte_data(client, REG_SELECT_PWM);
++ if (val < 0) {
++ dev_err(&client->dev, "can't read REG_SELECT_PWM\n");
++ goto end;
++ }
++ val &= ~BIT((u8)pin);
++ ret = i2c_smbus_write_byte_data(client, REG_SELECT_PWM, val);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't write to SELECT_PWM\n");
++ }
++
++end:
++ mutex_unlock(&dev->lock);
++
++ return;
++}
++
++/*
++ * Some PWMs are unavailable on Galileo. Prevent user from reserving them.
++ */
++static int cy8c9540a_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ int gpio = 0;
++ struct cy8c9540a *dev =
++ container_of(chip, struct cy8c9540a, pwm_chip);
++ struct i2c_client *client = dev->client;
++
++ if (pwm->pwm > NPWM) {
++ return -EINVAL;
++ }
++
++ gpio = pwm2gpio_mapping[pwm->pwm];
++ if (PWM_UNUSED == gpio) {
++ dev_err(&client->dev, "pwm%d unavailable\n", pwm->pwm);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static const struct pwm_ops cy8c9540a_pwm_ops = {
++ .request = cy8c9540a_pwm_request,
++ .config = cy8c9540a_pwm_config,
++ .enable = cy8c9540a_pwm_enable,
++ .disable = cy8c9540a_pwm_disable,
++};
++
++/*
++ * cy8c9540a_set_por_default
++ *
++ * Ensure the expander is using platform-specific POR settings.
++ *
++ * Note SMBUS max transaction length is 32 bytes, so we have to fall back to
++ * raw i2c transfers.
++ */
++static int cy8c9540a_set_por_default(struct cy8c9540a *dev)
++{
++ int ret = 0;
++ struct i2c_client *client = dev->client;
++ int i = 0;
++ int segments = -1;
++ int crc_index = sizeof(por_default) - 1;
++ u8 reg_cmd_r_por[] = { REG_CMD, CMD_R_EEPROM_POR };
++
++ /* Read POR settings stored in EEPROM */
++ dev->i2c_segments[0].addr = client->addr;
++ dev->i2c_segments[0].flags = 0; /* write */
++ dev->i2c_segments[0].len = sizeof(reg_cmd_r_por);
++ dev->i2c_segments[0].buf = reg_cmd_r_por;
++ dev->i2c_segments[1].addr = client->addr;
++ dev->i2c_segments[1].flags = I2C_M_RD;
++ dev->i2c_segments[1].len = sizeof(dev->por_stored);
++ dev->i2c_segments[1].buf = dev->por_stored;
++ segments = 2;
++ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
++ if (segments != ret) {
++ dev_err(&client->dev, "can't read POR settings (ret=%d)\n", ret);
++ goto end;
++ } else {
++ ret = 0;
++ }
++
++ /* Compute CRC for platform-defined POR settings */
++ por_default[crc_index] = 0;
++ for (i = POR_CMD_W_OFFS; i < crc_index; i ++) {
++ por_default[crc_index] ^= por_default[i];
++ }
++
++ /* Compare POR settings with platform-defined ones */
++ for (i = 0; i < sizeof(dev->por_stored); i ++) {
++ if (dev->por_stored[i] != por_default[i + POR_CMD_W_OFFS]) {
++ break;
++ }
++ }
++ if (sizeof(dev->por_stored) == i) {
++ goto end;
++ }
++
++ /* Update POR settings to EEPROM */
++
++ dev_info(&client->dev, "updating EEPROM with platform POR settings\n");
++
++ /* Store default POR settings into EEPROM */
++ dev->i2c_segments[0].addr = client->addr;
++ dev->i2c_segments[0].flags = 0; /* write */
++ dev->i2c_segments[0].len = sizeof(por_default);
++ dev->i2c_segments[0].buf = por_default;
++ segments = 1;
++ ret = i2c_transfer(client->adapter, dev->i2c_segments, segments);
++ if (segments != ret) {
++ dev_err(&client->dev, "can't write POR settings (ret=%d)\n", ret);
++ goto end;
++ } else {
++ ret = 0;
++ }
++
++ /* Let EEPROM terminate its last page write. 200ms as per datasheet. */
++ mdelay(200);
++
++ /* Reconfigure device with newly stored POR settings */
++ ret = i2c_smbus_write_byte_data(client, REG_CMD, CMD_RECONF_DEV);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't reconfigure device\n");
++ goto end;
++ }
++
++end:
++ return ret;
++}
++
++/*
++ * cy8c9540a_setup
++ *
++ * Initialise the device with default setup.
++ * No need to roll back if this fails.
++ */
++static int cy8c9540a_setup(struct cy8c9540a *dev)
++{
++ int ret = 0;
++ struct i2c_client *client = dev->client;
++ const u8 eeprom_enable_seq[] = {0x43, 0x4D, 0x53, 0x2};
++
++ /* Test/set platform-specific POR settings */
++ ret = cy8c9540a_set_por_default(dev);
++ if (ret) {
++ dev_err(&client->dev, "can't set POR settings (err=%d)\n", ret);
++ goto end;
++ }
++
++ /* Cache the output registers */
++ ret = i2c_smbus_read_i2c_block_data(dev->client, REG_OUTPUT_PORT0,
++ sizeof(dev->outreg_cache),
++ dev->outreg_cache);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't cache output registers\n");
++ goto end;
++ }
++
++ /* Enable the EEPROM */
++ ret = i2c_smbus_write_i2c_block_data(client, REG_ENABLE,
++ sizeof(eeprom_enable_seq),
++ eeprom_enable_seq);
++ if (ret < 0) {
++ dev_err(&client->dev, "can't enable EEPROM\n");
++ goto end;
++ }
++
++end:
++ return ret;
++}
++
++static int cy8c9540a_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct cy8c9540a *dev;
++ struct gpio_chip *gc;
++ int ret = 0;
++ s32 dev_id = 0;
++
++ ret = gpio_request(SOC_GPIO_I2C_A0, "cy8c9540a-addr0");
++ if (ret) {
++ pr_err("%s: failed to request gpio%u\n", __func__,
++ SOC_GPIO_I2C_A0);
++ return ret;
++ }
++
++ /*
++ * Galileo uses A0 Extendable Soft Addressing pin on the Cypress part.
++ * The inverted value of A0 is exposed to a SoC GPIO.
++ *
++ * Work out the I2C address of the device based on A0.
++ */
++ if (gpio_get_value(SOC_GPIO_I2C_A0)) {
++ client->addr &= ~I2C_A0_ADDR_MASK;
++ } else {
++ client->addr |= I2C_A0_ADDR_MASK;
++ }
++
++ if (!i2c_check_functionality(client->adapter,
++ I2C_FUNC_I2C |
++ I2C_FUNC_SMBUS_I2C_BLOCK |
++ I2C_FUNC_SMBUS_BYTE_DATA)) {
++ dev_err(&client->dev, "i2c adapter doesn't support required "
++ "functionality\n");
++ ret = -EIO;
++ goto err_i2c_addr;
++ }
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (dev == NULL) {
++ dev_err(&client->dev, "failed to alloc memory\n");
++ ret = -ENOMEM;
++ goto err_i2c_addr;
++ }
++
++ dev->client = client;
++
++ gc = &dev->gpio_chip;
++ gc->direction_input = cy8c9540a_gpio_direction_input;
++ gc->direction_output = cy8c9540a_gpio_direction_output;
++ gc->get = cy8c9540a_gpio_get_value;
++ gc->set = cy8c9540a_gpio_set_value;
++ gc->set_drive = cy8c9540a_gpio_set_drive;
++
++ gc->can_sleep = 1;
++
++ gc->base = GPIO_BASE_ID;
++ gc->ngpio = NGPIO;
++ gc->label = client->name;
++ gc->owner = THIS_MODULE;
++ gc->to_irq = cy8c9540a_gpio_to_irq;
++
++ mutex_init(&dev->lock);
++
++ /* Whoami */
++ dev_id = i2c_smbus_read_byte_data(client, REG_DEVID_STAT);
++ if (dev_id < 0) {
++ dev_err(&client->dev, "can't read device ID\n");
++ ret = dev_id;
++ goto err;
++ }
++ dev_info(&client->dev, "dev_id=0x%x\n", dev_id & 0xff);
++ if (DEVID_FAMILY_CY8C9540A != (dev_id & DEVID_FAMILY_MASK)) {
++ dev_err(&client->dev, "unknown/unsupported dev_id 0x%x\n",
++ dev_id & 0xff);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ ret = cy8c9540a_setup(dev);
++ if (ret) {
++ goto err;
++ }
++
++ ret = cy8c9540a_irq_setup(dev);
++ if (ret) {
++ goto err;
++ }
++ ret = gpiochip_add(&dev->gpio_chip);
++ if (ret) {
++ dev_err(&client->dev, "gpiochip_add failed %d\n", ret);
++ goto err_irq;
++ }
++
++ dev->pwm_chip.dev = &client->dev;
++ dev->pwm_chip.ops = &cy8c9540a_pwm_ops;
++ dev->pwm_chip.base = PWM_BASE_ID;
++ dev->pwm_chip.npwm = NPWM;
++
++ ret = pwmchip_add(&dev->pwm_chip);
++ if (ret) {
++ dev_err(&client->dev, "pwmchip_add failed %d\n", ret);
++ goto err_gpiochip;
++ }
++
++ i2c_set_clientdata(client, dev);
++
++ return 0;
++
++err_gpiochip:
++ if(gpiochip_remove(&dev->gpio_chip))
++ dev_warn(&client->dev, "gpiochip_remove failed\n");
++err_irq:
++ cy8c9540a_irq_teardown(dev);
++err:
++ mutex_destroy(&dev->lock);
++ kfree(dev);
++err_i2c_addr:
++ gpio_free(SOC_GPIO_I2C_A0);
++
++ return ret;
++}
++
++static int cy8c9540a_remove(struct i2c_client *client)
++{
++ struct cy8c9540a *dev = i2c_get_clientdata(client);
++ int ret = 0;
++ int err = 0;
++
++ ret = pwmchip_remove(&dev->pwm_chip);
++ if (ret < 0) {
++ dev_err(&client->dev, "pwmchip_remove failed %d\n", ret);
++ err = ret;
++ }
++
++ ret = gpiochip_remove(&dev->gpio_chip);
++ if (ret) {
++ dev_err(&client->dev, "gpiochip_remove failed %d\n", ret);
++ err = ret;
++ }
++
++ cy8c9540a_irq_teardown(dev);
++
++ mutex_destroy(&dev->lock);
++ kfree(dev);
++
++ gpio_free(SOC_GPIO_I2C_A0);
++
++ return err;
++}
++
++static const struct i2c_device_id cy8c9540a_id[] = {
++ {DRV_NAME, 0},
++ {}
++};
++
++MODULE_DEVICE_TABLE(i2c, cy8c9540a_id);
++
++static struct i2c_driver cy8c9540a_driver = {
++ .driver = {
++ .name = DRV_NAME,
++ },
++ .probe = cy8c9540a_probe,
++ .remove = cy8c9540a_remove,
++ .id_table = cy8c9540a_id,
++};
++
++module_i2c_driver(cy8c9540a_driver);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@linux.intel.com>");
++MODULE_DESCRIPTION("GPIO/PWM driver for CY8C9540A I/O expander");
++MODULE_LICENSE("GPL");
++
+diff --git a/drivers/mfd/intel_cln_gip.h b/drivers/mfd/intel_cln_gip.h
+new file mode 100644
+index 0000000..18ab774
+--- /dev/null
++++ b/drivers/mfd/intel_cln_gip.h
+@@ -0,0 +1,101 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton GIP (GPIO/I2C) driver
++ */
++
++#ifndef __INTEL_CLNGIP_H__
++#define __INTEL_CLNGIP_H__
++
++#include <linux/i2c.h>
++#include <linux/pci.h>
++#include "../i2c/busses/i2c-designware-core.h"
++
++/* PCI BAR for register base address */
++#define GIP_I2C_BAR 0
++#define GIP_GPIO_BAR 1
++
++/**
++ * intel_cln_gpio_probe
++ *
++ * @param pdev: Pointer to GIP PCI device
++ * @return 0 success < 0 failure
++ *
++ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
++ */
++int intel_cln_gpio_probe(struct pci_dev *pdev);
++
++/**
++ * intel_cln_gpio_remove
++ *
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Perform GPIO-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_cln_gpio_remove(struct pci_dev *pdev);
++
++/**
++ * intel_cln_gpio_isr
++ *
++ * @param irq: IRQ number to be served
++ * @param dev_id: used to distinguish the device (for shared interrupts)
++ *
++ * Perform GPIO-specific ISR of the top-level GIP driver.
++ */
++irqreturn_t intel_cln_gpio_isr(int irq, void *dev_id);
++
++/**
++ * intel_cln_gpio_save_state
++ *
++ * Save GPIO register state for system-wide suspend events and mask out
++ * interrupts.
++ */
++void intel_cln_gpio_save_state(void);
++
++/**
++ * intel_cln_gpio_restore_state
++ *
++ * Restore GPIO register state for system-wide resume events and clear out
++ * spurious interrupts.
++ */
++void intel_cln_gpio_restore_state(void);
++
++/**
++ * intel_cln_i2c_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @param drvdata: private driver data
++ * @return 0 success < 0 failure
++ *
++ * Perform I2C-specific probing on behalf of the top-level GIP driver.
++ */
++int intel_cln_i2c_probe(struct pci_dev *pdev,
++ struct dw_i2c_dev **drvdata);
++
++/**
++ * intel_cln_i2c_remove
++ * @param pdev: Pointer to GIP PCI device
++ * @param dev: Pointer to I2C private data
++ *
++ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_cln_i2c_remove(struct pci_dev *pdev,
++ struct dw_i2c_dev *dev);
++
++#endif /* __INTEL_CLNGIP_H__ */
+diff --git a/drivers/mfd/intel_cln_gip_core.c b/drivers/mfd/intel_cln_gip_core.c
+new file mode 100644
+index 0000000..7464b32
+--- /dev/null
++++ b/drivers/mfd/intel_cln_gip_core.c
+@@ -0,0 +1,327 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton GIP (GPIO/I2C) PCI driver
++ *
++ * PCI glue logic for Clanton GIP driver.
++ * Clanton GIP is a single PCI function exporting a GPIO and an I2C device.
++ * The PCI driver performs the bus-dependent probe/release operations, and
++ * call into GPIO/I2C specific modules for handling the two diffrerent
++ * functionalities.
++ */
++
++#include <asm/cln.h>
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include "intel_cln_gip.h"
++
++static unsigned int enable_msi = 1;
++module_param(enable_msi, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
++
++static unsigned int i2c = 1;
++module_param(i2c, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(i2c, "Register I2C adapter");
++
++static unsigned int gpio = 1;
++module_param(gpio, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio, "Register GPIO chip");
++
++/* GIP private data, supporting only a single instance of the device. */
++struct intel_cln_gip_data {
++ struct pci_dev *pci_device;
++ struct dw_i2c_dev *i2c_drvdata;
++};
++
++/**
++ * intel_cln_gip_handler
++ *
++ * @param irq: IRQ number to be served
++ * @param dev_id: device private data
++ *
++ * Top-level interrupt handler for GIP driver.
++ * It calls into the appropriate sub-routines and gathers the return values.
++ */
++static irqreturn_t intel_cln_gip_handler(int irq, void *dev_id)
++{
++ irqreturn_t ret_i2c = IRQ_NONE;
++ irqreturn_t ret_gpio = IRQ_NONE;
++ struct intel_cln_gip_data *data = (struct intel_cln_gip_data *)dev_id;
++
++ mask_pvm(data->pci_device);
++
++ if (likely(i2c)) {
++ /* Only I2C gets platform data */
++ ret_i2c = i2c_dw_isr(irq, data->i2c_drvdata);
++ }
++
++ if (likely(gpio)) {
++ ret_gpio = intel_cln_gpio_isr(irq, NULL);
++ }
++
++ unmask_pvm(data->pci_device);
++
++ if (likely(IRQ_HANDLED == ret_i2c || IRQ_HANDLED == ret_gpio))
++ return IRQ_HANDLED;
++
++ /* Each sub-ISR routine returns either IRQ_HANDLED or IRQ_NONE. */
++ return IRQ_NONE;
++}
++
++static DEFINE_PCI_DEVICE_TABLE(intel_cln_gip_ids) = {
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0934), },
++ { 0, }
++};
++MODULE_DEVICE_TABLE(pci, intel_cln_gip_ids);
++
++#ifdef CONFIG_PM
++
++/**
++ * cln_gip_suspend
++ *
++ * @param device: Pointer to device
++ * @return 0 success < 0 failure
++ *
++ * Prepare GIP for system-wide transition to sleep state.
++ * Save context, disable GPIO chip and I2C adapter, transition PCI device into
++ * low-power state.
++ */
++static int cln_gip_suspend(struct device *dev)
++{
++ int err = 0;
++ struct intel_cln_gip_data *data = NULL;
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
++
++ i2c_dw_disable(data->i2c_drvdata);
++ intel_cln_gpio_save_state();
++
++ err = pci_save_state(pdev);
++ if (err) {
++ dev_err(&pdev->dev, "pci_save_state failed\n");
++ return err;
++ }
++
++ err = pci_set_power_state(pdev, PCI_D3hot);
++ if (err) {
++ dev_err(&pdev->dev, "pci_set_power_state failed\n");
++ return err;
++ }
++
++ return 0;
++}
++
++/**
++ * cln_gip_resume
++ *
++ * @param device: Pointer to device
++ * @return 0 success < 0 failure
++ *
++ * Prepare GIP for system-wide transition to fully active state.
++ * Set PCI device into full-power state, restore context, enable I2C adapter
++ * and GPIO chip.
++ */
++static int cln_gip_resume(struct device *dev)
++{
++ int err = 0;
++ struct intel_cln_gip_data *data = NULL;
++ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
++ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
++
++ err = pci_set_power_state(pdev, PCI_D0);
++ if (err) {
++ dev_err(&pdev->dev, "pci_set_power_state() failed\n");
++ return err;
++ }
++
++ pci_restore_state(pdev);
++
++ intel_cln_gpio_restore_state();
++ i2c_dw_init(data->i2c_drvdata);
++
++ return 0;
++}
++
++#else
++#define cln_gip_suspend NULL
++#define cln_gip_resume NULL
++#endif
++
++static const struct dev_pm_ops cln_gip_pm_ops = {
++ .resume = cln_gip_resume,
++ .suspend = cln_gip_suspend,
++};
++
++/**
++ * intel_cln_gip_probe
++ *
++ * @param pdev: Pointer to GIP PCI device
++ * @param id: GIP PCI Device ID
++ * @return 0 success < 0 failure
++ *
++ * GIP PCI driver probing. Calls into the appropriate probe routines for GPIO
++ * and I2C too.
++ */
++static int intel_cln_gip_probe(struct pci_dev *pdev,
++ const struct pci_device_id *id)
++{
++ int retval = 0;
++ struct intel_cln_gip_data *gip_drvdata = NULL;
++
++ retval = pci_enable_device(pdev);
++ if (retval)
++ return retval;
++
++ retval = pci_request_regions(pdev, "cln-gip");
++ if (retval) {
++ dev_err(&pdev->dev, "error requesting PCI region\n");
++ goto err_pcidev_disable;
++ }
++
++ gip_drvdata = kzalloc(sizeof(struct intel_cln_gip_data), GFP_KERNEL);
++ if (NULL == gip_drvdata) {
++ retval = -ENOMEM;
++ goto err_pciregions_release;
++ }
++ pci_set_drvdata(pdev, gip_drvdata);
++
++ gip_drvdata->pci_device = pdev;
++
++ if (gpio) {
++ retval = intel_cln_gpio_probe(pdev);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ if (i2c) {
++ retval = intel_cln_i2c_probe(pdev,
++ (struct dw_i2c_dev **)&gip_drvdata->i2c_drvdata);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ if (enable_msi) {
++ pci_set_master(pdev);
++ retval = pci_enable_msi(pdev);
++ if (retval)
++ goto err_release_drvdata;
++ }
++
++ /*
++ * Request a shared IRQ.
++ * Since the dev_id cannot be NULL, it points to PCI device descriptor
++ * if I2C is not registered.
++ */
++ retval = request_irq(pdev->irq, intel_cln_gip_handler, IRQF_SHARED,
++ "intel_cln_gip", gip_drvdata);
++ if (retval) {
++ dev_err(&pdev->dev, "error requesting IRQ\n");
++ goto err;
++ }
++
++ return 0;
++
++err_release_drvdata:
++ pci_set_drvdata(pdev, NULL);
++ kfree(gip_drvdata);
++err:
++ if (enable_msi)
++ pci_disable_msi(pdev);
++err_pciregions_release:
++ pci_release_regions(pdev);
++err_pcidev_disable:
++ pci_disable_device(pdev);
++
++ return retval;
++}
++
++/**
++ * intel_cln_gip_remove
++ *
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Release resources. Calls into GPIO/I2C dedicate routines too.
++ */
++static void intel_cln_gip_remove(struct pci_dev *pdev)
++{
++ struct intel_cln_gip_data *data = NULL;
++
++ data = (struct intel_cln_gip_data *)pci_get_drvdata(pdev);
++
++ if (NULL == data) {
++ dev_err(&pdev->dev, "%s: failure getting driver data\n",
++ __func__);
++ return;
++ }
++
++ free_irq(pdev->irq, data);
++
++ if (enable_msi) {
++ pci_clear_master(pdev);
++ if (pci_dev_msi_enabled(pdev))
++ pci_disable_msi(pdev);
++ }
++
++ if (i2c)
++ intel_cln_i2c_remove(pdev, data->i2c_drvdata);
++
++ if (gpio)
++ intel_cln_gpio_remove(pdev);
++
++ pci_set_drvdata(pdev, NULL);
++ kfree(data);
++
++ pci_release_regions(pdev);
++ pci_disable_device(pdev);
++}
++
++static struct pci_driver intel_cln_gip_driver = {
++ .name = "intel_cln_gip",
++ .id_table = intel_cln_gip_ids,
++ .probe = intel_cln_gip_probe,
++ .remove = intel_cln_gip_remove,
++ .driver = {
++ .pm = &cln_gip_pm_ops,
++ },
++};
++
++static int intel_cln_gip_init(void)
++{
++ return pci_register_driver(&intel_cln_gip_driver);
++}
++
++static void intel_cln_gip_exit(void)
++{
++ pci_unregister_driver(&intel_cln_gip_driver);
++}
++
++module_init(intel_cln_gip_init);
++module_exit(intel_cln_gip_exit);
++
++MODULE_AUTHOR("Intel Corporation");
++MODULE_DESCRIPTION("Clanton GIP driver");
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/mfd/intel_cln_gip_gpio.c b/drivers/mfd/intel_cln_gip_gpio.c
+new file mode 100644
+index 0000000..6e2bbbf
+--- /dev/null
++++ b/drivers/mfd/intel_cln_gip_gpio.c
+@@ -0,0 +1,660 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton GIP (GPIO/I2C) - GPIO-specific PCI and core driver
++ *
++ * PCI glue logic and core driver for Clanton GIP/GPIO.
++ * The GIP GPIO device is the DesignWare GPIO. This file defines the PCI glue
++ * for this driver and as well as the core logic for the device.
++ * Please note only a single instance of the GPIO device is supported.
++ * The default number of GPIO is 8, all interrupt-capable.
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/irq.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/uio_driver.h>
++#include "intel_cln_gip.h"
++
++static void cln_gpio_restrict_release(struct device *dev) {}
++static struct platform_device cln_gpio_restrict_pdev =
++{
++ .name = "cln-gpio-restrict-sc",
++ .dev.release = cln_gpio_restrict_release,
++};
++struct uio_info *info;
++
++/* The base GPIO number under GPIOLIB framework */
++#define INTEL_CLN_GIP_GPIO_BASE 8
++
++/* The default number of South-Cluster GPIO on Clanton. */
++#define INTEL_CLN_GIP_NGPIO 8
++
++/*
++ * The default base IRQ for searching and allocating the range of GPIO IRQ
++ * descriptors.
++ */
++#define INTEL_CLN_GIP_GPIO_IRQBASE 56
++
++/* The GPIO private data. */
++static struct gpio_chip *gc;
++static struct irq_chip_generic *igc;
++static void __iomem *reg_base;
++static spinlock_t lock;
++static int irq_base;
++static unsigned int n_gpio = INTEL_CLN_GIP_NGPIO;
++static unsigned int gpio_irqbase = INTEL_CLN_GIP_GPIO_IRQBASE;
++
++/* Store GPIO context across system-wide suspend/resume transitions */
++static struct gpio_saved_regs {
++ u32 data;
++ u32 dir;
++ u32 int_en;
++ u32 int_mask;
++ u32 int_type;
++ u32 int_pol;
++ u32 int_deb;
++} saved_regs;
++
++/* PortA registers set. Note other ports are unused */
++#define PORTA_DATA 0x00 /* Data */
++#define PORTA_DIR 0x04 /* Direction */
++#define PORTA_INT_EN 0x30 /* Interrupt enable */
++#define PORTA_INT_MASK 0x34 /* Interrupt mask */
++#define PORTA_INT_TYPE_LEVEL 0x38 /* Interrupt level*/
++#define PORTA_INT_POLARITY 0x3c /* Interrupt polarity */
++#define PORTA_INT_STATUS 0x40 /* Interrupt status */
++#define PORTA_INT_RAW_STATUS 0x44 /* Interrupt raw status */
++#define PORTA_DEBOUNCE 0x48 /* Debounce enable */
++#define PORTA_INT_EOI 0x4c /* Clear interrupt */
++#define PORTA_EXT 0x50 /* External */
++
++module_param(n_gpio, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(n_gpio, "Number of GPIO");
++
++module_param(gpio_irqbase, uint, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio_irqbase, "Base IRQ for GPIO range");
++
++/**
++ * intel_cln_gpio_get
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return 0 if GPIO is deasserted, 1 if GPIO is asserted
++ *
++ * Read back the value of a GPIO.
++ */
++static int intel_cln_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++ void __iomem *reg_ext = reg_base + PORTA_EXT;
++ u32 val_ext = ioread32(reg_ext);
++
++ val_ext &= BIT(offset % 32);
++ return (val_ext > 0);
++}
++
++/**
++ * intel_cln_gpio_set
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ *
++ * Set value of a GPIO.
++ */
++static void intel_cln_gpio_set(struct gpio_chip *chip, unsigned offset,
++ int value)
++{
++ void __iomem *reg_data = reg_base + PORTA_DATA;
++ u32 val_data = 0;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_data = ioread32(reg_data);
++ if (value)
++ iowrite32(val_data | BIT(offset % 32), reg_data);
++ else
++ iowrite32(val_data & ~BIT(offset % 32), reg_data);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_direction_input
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return always 0 (success)
++ *
++ * Set direction of a GPIO as input.
++ */
++static int intel_cln_gpio_direction_input(struct gpio_chip *chip,
++ unsigned offset)
++{
++ u32 val_dir = 0;
++ void __iomem *reg_dir = reg_base + PORTA_DIR;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_dir = ioread32(reg_dir);
++ iowrite32(val_dir & ~BIT(offset % 32), reg_dir);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_cln_gpio_direction_output
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @param value: value to be driven to the GPIO
++ * @return always 0 (success)
++ *
++ * Set the default value of a GPIO, and then set direction as output.
++ */
++static int intel_cln_gpio_direction_output(struct gpio_chip *chip,
++ unsigned offset, int value)
++{
++ u32 val_dir = 0;
++ void __iomem *reg_dir = reg_base + PORTA_DIR;
++ unsigned long flags = 0;
++
++ /* Ensure glitch-free operation. */
++ intel_cln_gpio_set(chip, offset, value);
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_dir = ioread32(reg_dir);
++ iowrite32(val_dir | BIT(offset % 32), reg_dir);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_cln_gpio_set_debounce
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @param debounce: 1 to enable, 0 to disable
++ * @return always 0 (success)
++ *
++ * Enable/disable interrupt debounce logic for a GPIO.
++ */
++static int intel_cln_gpio_set_debounce(struct gpio_chip *chip,
++ unsigned offset, unsigned debounce)
++{
++ u32 val_deb = 0;
++ void __iomem *reg_deb = reg_base + PORTA_DEBOUNCE;
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_deb = ioread32(reg_deb);
++ if (debounce)
++ iowrite32(val_deb | BIT(offset % 32), reg_deb);
++ else
++ iowrite32(val_deb & ~BIT(offset % 32), reg_deb);
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return 0;
++}
++
++/**
++ * intel_cln_gpio_irq_type
++ * @param irq_data: Pointer to information about the IRQ
++ * @param type: set the triggering type of the interrupt
++ * @return always 0 (success)
++ *
++ * Set interrupt triggering type for a GPIO.
++ */
++static int intel_cln_gpio_irq_type(struct irq_data *d, unsigned type)
++{
++ int ret = 0;
++ unsigned long flags = 0;
++ void __iomem *reg_level = reg_base + PORTA_INT_TYPE_LEVEL;
++ void __iomem *reg_pol = reg_base + PORTA_INT_POLARITY;
++ u32 val_level = 0;
++ u32 val_pol = 0;
++ u32 gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return -EFAULT;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++
++ val_level = ioread32(reg_level);
++ val_pol = ioread32(reg_pol);
++
++ switch (type) {
++ case IRQ_TYPE_EDGE_RISING:
++ iowrite32(val_level | BIT(gpio % 32), reg_level);
++ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_EDGE_FALLING:
++ iowrite32(val_level | BIT(gpio % 32), reg_level);
++ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
++ iowrite32(val_pol | BIT(gpio % 32), reg_pol);
++ break;
++ case IRQ_TYPE_LEVEL_LOW:
++ iowrite32(val_level & ~BIT(gpio % 32), reg_level);
++ iowrite32(val_pol & ~BIT(gpio % 32), reg_pol);
++ break;
++ default:
++ ret = -EINVAL;
++ break;
++ }
++
++ spin_unlock_irqrestore(&lock, flags);
++
++ return ret;
++}
++
++/**
++ * intel_cln_gpio_irq_unmask
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Unmask interrupts for a GPIO.
++ */
++static void intel_cln_gpio_irq_unmask(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
++ u32 val_mask = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_mask = ioread32(reg_mask);
++ iowrite32(val_mask | BIT(gpio % 32), reg_mask);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_irq_mask
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Mask interrupts for a GPIO.
++ */
++static void intel_cln_gpio_irq_mask(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_mask = reg_base + PORTA_INT_MASK;
++ u32 val_mask = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_mask = ioread32(reg_mask);
++ iowrite32(val_mask & ~BIT(gpio % 32), reg_mask);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_irq_enable
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Enable interrupts for a GPIO.
++ */
++static void intel_cln_gpio_irq_enable(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
++ u32 val_inte = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_inte = ioread32(reg_inte);
++ iowrite32(val_inte | BIT(gpio % 32), reg_inte);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_irq_disable
++ * @param irq_data: Pointer to information about the IRQ
++ *
++ * Disable interrupts for a GPIO.
++ */
++static void intel_cln_gpio_irq_disable(struct irq_data *d)
++{
++ unsigned long flags = 0;
++ void __iomem *reg_inte = reg_base + PORTA_INT_EN;
++ u32 val_inte = 0;
++ unsigned gpio = 0;
++
++ if (NULL == d) {
++ pr_err("%s(): null irq_data\n", __func__);
++ return;
++ }
++
++ gpio = d->irq - irq_base;
++
++ spin_lock_irqsave(&lock, flags);
++ val_inte = ioread32(reg_inte);
++ iowrite32(val_inte & ~BIT(gpio % 32), reg_inte);
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_to_irq
++ * @param chip: Pointer to GPIO chip registered by GPIOLIB
++ * @param offset: the GPIO number within the GPIOLIB chip
++ * @return IRQ associated to GPIO
++ *
++ * Compute the IRQ number based on the GPIO.
++ */
++static int intel_cln_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
++{
++ return irq_base + offset;
++}
++
++/**
++ * intel_cln_gpio_isr
++ * @param irq: IRQ number
++ * @param dev_id: cookie used to tell what instance of the driver the interrupt
++ * belongs to
++ * @return IRQ_HANDLED if interrupt served, IRQ_NONE if no interrupt pending
++ *
++ * Interrupt Service Routine for GPIO. Identify which GPIOs (if any) is pending
++ * for interrupt to be served, acknowledge the interrupt and serve it.
++ */
++irqreturn_t intel_cln_gpio_isr(int irq, void *dev_id)
++{
++ irqreturn_t ret = IRQ_NONE;
++ u32 pending = 0, gpio = 0;
++ void __iomem *reg_pending = reg_base + PORTA_INT_STATUS;
++ void __iomem *reg_eoi = reg_base + PORTA_INT_EOI;
++
++ /* Which pin (if any) triggered the interrupt */
++ while ((pending = ioread32(reg_pending))) {
++ /*
++ * Acknowledge all the asserted GPIO interrupt lines before
++ * serving them, so that we don't lose an edge.
++ * This has only effect on edge-triggered interrupts.
++ */
++ iowrite32(pending, reg_eoi);
++
++ /* Serve each asserted interrupt */
++ do {
++ gpio = __ffs(pending);
++ generic_handle_irq(
++ gpio_to_irq(INTEL_CLN_GIP_GPIO_BASE + gpio));
++ pending &= ~BIT(gpio);
++ ret = IRQ_HANDLED;
++ } while(pending);
++ }
++
++ return ret;
++}
++
++/**
++ * intel_cln_gpio_save_state
++ *
++ * Save GPIO register state for system-wide suspend events and mask out
++ * interrupts.
++ */
++void intel_cln_gpio_save_state(void)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ saved_regs.int_mask = ioread32(reg_base + PORTA_INT_MASK);
++ saved_regs.int_en = ioread32(reg_base + PORTA_INT_EN);
++ saved_regs.int_deb = ioread32(reg_base + PORTA_DEBOUNCE);
++ saved_regs.int_pol = ioread32(reg_base + PORTA_INT_POLARITY);
++ saved_regs.int_type = ioread32(reg_base + PORTA_INT_TYPE_LEVEL);
++ saved_regs.dir = ioread32(reg_base + PORTA_DIR);
++ saved_regs.data = ioread32(reg_base + PORTA_DATA);
++
++ /* Mask out interrupts */
++ iowrite32(0xffffffff, reg_base + PORTA_INT_MASK);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_restore_state
++ *
++ * Restore GPIO register state for system-wide resume events and clear out
++ * spurious interrupts.
++ */
++void intel_cln_gpio_restore_state(void)
++{
++ unsigned long flags = 0;
++
++ spin_lock_irqsave(&lock, flags);
++
++ iowrite32(saved_regs.data, reg_base + PORTA_DATA);
++ iowrite32(saved_regs.dir, reg_base + PORTA_DIR);
++ iowrite32(saved_regs.int_type, reg_base + PORTA_INT_TYPE_LEVEL);
++ iowrite32(saved_regs.int_pol, reg_base + PORTA_INT_POLARITY);
++ iowrite32(saved_regs.int_deb, reg_base + PORTA_DEBOUNCE);
++ iowrite32(saved_regs.int_en, reg_base + PORTA_INT_EN);
++ iowrite32(saved_regs.int_mask, reg_base + PORTA_INT_MASK);
++
++ /* Clear out spurious interrupts */
++ iowrite32(0xffffffff, reg_base + PORTA_INT_EOI);
++
++ spin_unlock_irqrestore(&lock, flags);
++}
++
++/**
++ * intel_cln_gpio_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @return 0 success < 0 failure
++ *
++ * Perform GPIO-specific probing on behalf of the top-level GIP driver.
++ * Initiate the GPIO device.
++ */
++int intel_cln_gpio_probe(struct pci_dev *pdev)
++{
++ int retval = 0;
++ resource_size_t start = 0, len = 0;
++
++ /* Get UIO memory */
++ info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
++ if (!info)
++ return -ENOMEM;
++
++ /* Determine the address of the GPIO area */
++ start = pci_resource_start(pdev, GIP_GPIO_BAR);
++ len = pci_resource_len(pdev, GIP_GPIO_BAR);
++ if (!start || len == 0) {
++ dev_err(&pdev->dev, "bar%d not set\n", GIP_GPIO_BAR);
++ retval = -ENODEV;
++ goto exit;
++ }
++
++ reg_base = ioremap_nocache(start, len);
++ if (NULL == reg_base) {
++ dev_err(&pdev->dev, "I/O memory remapping failed\n");
++ retval = -EFAULT;
++ goto exit;
++ }
++
++ memset(&saved_regs, 0x0, sizeof(saved_regs));
++
++ gc = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL);
++ if (!gc) {
++ retval = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ if (n_gpio == 0 || n_gpio > INTEL_CLN_GIP_NGPIO) {
++ dev_err(&pdev->dev, "n_gpio outside range [1,%d]\n",
++ INTEL_CLN_GIP_NGPIO);
++ retval = -EINVAL;
++ goto err_free_gpiochip;
++ }
++
++ gc->label = "intel_cln_gip_gpio";
++ gc->owner = THIS_MODULE;
++ gc->direction_input = intel_cln_gpio_direction_input;
++ gc->direction_output = intel_cln_gpio_direction_output;
++ gc->get = intel_cln_gpio_get;
++ gc->set = intel_cln_gpio_set;
++ gc->set_debounce = intel_cln_gpio_set_debounce;
++ gc->to_irq = intel_cln_gpio_to_irq;
++ gc->base = INTEL_CLN_GIP_GPIO_BASE;
++ gc->ngpio = n_gpio;
++ gc->can_sleep = 0;
++ retval = gpiochip_add(gc);
++ if (retval) {
++ dev_err(&pdev->dev, "failure adding GPIO chip\n");
++ goto err_free_gpiochip;
++ }
++
++ spin_lock_init(&lock);
++
++ /*
++ * Allocate a range of IRQ descriptor for the available GPIO.
++ * IRQs are allocated dynamically.
++ */
++ irq_base = irq_alloc_descs(-1, gpio_irqbase, n_gpio, NUMA_NO_NODE);
++ if (irq_base < 0) {
++ dev_err(&pdev->dev, "failure adding GPIO IRQ descriptors\n");
++ goto err_remove_gpiochip;
++ }
++
++ retval = platform_device_register(&cln_gpio_restrict_pdev);
++ if (retval < 0){
++ goto err_free_irq_descs;
++ }
++
++ igc = irq_alloc_generic_chip("intel_cln_gip_gpio", 1, irq_base,
++ reg_base, handle_simple_irq);
++ if (NULL == igc) {
++ retval = -ENOMEM;
++ goto err_free_irq_descs;
++ }
++
++ /* UIO */
++ info->mem[0].addr = start;
++ info->mem[0].internal_addr = reg_base;
++ info->mem[0].size = len;
++ info->mem[0].memtype = UIO_MEM_PHYS;
++ info->mem[0].name = "gpio_regs";
++ info->name = "gpio uio";
++ info->version = "0.0.1";
++
++ if (uio_register_device(&pdev->dev, info))
++ goto err_free_irq_descs;
++
++ pr_info("%s UIO addr 0x%08x internal_addr 0x%08x size %lu memtype %d\n",
++ __func__, (unsigned int)info->mem[0].addr,
++ (unsigned int)info->mem[0].internal_addr, info->mem[0].size,
++ info->mem[0].memtype);
++ igc->chip_types->chip.irq_mask = intel_cln_gpio_irq_mask;
++ igc->chip_types->chip.irq_unmask = intel_cln_gpio_irq_unmask;
++ igc->chip_types->chip.irq_set_type = intel_cln_gpio_irq_type;
++ igc->chip_types->chip.irq_enable = intel_cln_gpio_irq_enable;
++ igc->chip_types->chip.irq_disable = intel_cln_gpio_irq_disable;
++
++ irq_setup_generic_chip(igc, IRQ_MSK(n_gpio), IRQ_GC_INIT_MASK_CACHE,
++ IRQ_NOREQUEST | IRQ_NOPROBE, 0);
++
++ return 0;
++
++err_free_irq_descs:
++ irq_free_descs(irq_base, n_gpio);
++err_remove_gpiochip:
++ if (0 != gpiochip_remove(gc))
++ dev_err(&pdev->dev, "failed removing gpio_chip\n");
++err_free_gpiochip:
++ kfree(gc);
++err_iounmap:
++ iounmap(reg_base);
++exit:
++ if (info != NULL)
++ kfree(info);
++ return retval;
++}
++
++/**
++ * intel_cln_gpio_remove
++ * @param pdev: Pointer to GIP PCI device
++ *
++ * Perform GPIO-specific resource release on behalf of the top-level GIP
++ * driver.
++ */
++void intel_cln_gpio_remove(struct pci_dev *pdev)
++{
++ if (NULL == igc) {
++ dev_err(&pdev->dev, "null pointer to irq_generic_chip\n");
++ return;
++ }
++ if (NULL == gc) {
++ dev_err(&pdev->dev, "null pointer to gpio_chip\n");
++ return;
++ }
++
++ /* Tear down IRQ descriptors */
++ irq_remove_generic_chip(igc, IRQ_MSK(n_gpio), 0,
++ IRQ_NOREQUEST | IRQ_NOPROBE);
++ kfree(igc);
++ irq_free_descs(irq_base, n_gpio);
++
++ platform_device_unregister(&cln_gpio_restrict_pdev);
++
++ /* Release GPIO chip */
++ if (0 != gpiochip_remove(gc))
++ dev_err(&pdev->dev, "failed removing gpio_chip\n");
++
++
++ if (info != NULL){
++ uio_unregister_device(info);
++ iounmap(info->mem[0].internal_addr);
++ kfree(info);
++ }
++
++ kfree(gc);
++ iounmap(reg_base);
++}
+diff --git a/drivers/mfd/intel_cln_gip_i2c.c b/drivers/mfd/intel_cln_gip_i2c.c
+new file mode 100644
+index 0000000..3675e50
+--- /dev/null
++++ b/drivers/mfd/intel_cln_gip_i2c.c
+@@ -0,0 +1,204 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton GIP (GPIO/I2C) - I2C-specific PCI driver
++ *
++ * PCI glue logic for Clanton GIP/I2C.
++ * The GIP I2C device is the DesignWare I2C. This file defines the PCI glue
++ * for this driver and is heavily based on
++ * on drivers/i2c/busses/i2c-designware-pcidrv.c. Also, it relies on
++ * drivers/i2c/busses/i2c-designware-core.c for the core logic.
++ * Please note only a single instance of the I2C device is supported.
++ */
++
++#include <linux/errno.h>
++#include <linux/i2c.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include "intel_cln_gip.h"
++
++enum dw_pci_ctl_id_t {
++ clanton_0,
++};
++
++static unsigned int i2c_std_mode;
++module_param(i2c_std_mode, uint, S_IRUSR);
++MODULE_PARM_DESC(i2c_std_mode, "Force I2C standard mode");
++
++#define INTEL_CLN_STD_CFG (DW_IC_CON_MASTER | \
++ DW_IC_CON_SLAVE_DISABLE | \
++ DW_IC_CON_RESTART_EN)
++
++static struct dw_pci_controller cln_gip_i2c_controller = {
++ .bus_num = 0,
++ .bus_cfg = INTEL_CLN_STD_CFG | DW_IC_CON_SPEED_FAST,
++ .tx_fifo_depth = 16,
++ .rx_fifo_depth = 16,
++ .clk_khz =
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC_FPGAEMU
++ 14000,
++#else
++ 33000,
++#endif
++ .explicit_stop = 1,
++};
++
++static struct i2c_algorithm i2c_dw_algo = {
++ .master_xfer = i2c_dw_xfer,
++ .functionality = i2c_dw_func,
++};
++
++/**
++ * i2c_dw_get_clk_rate_khz
++ * @param dev: Pointer to I2C device private data
++ * @return clock rate in kHz
++ *
++ * Ancillary function returning the frequency of the clock supplied to the
++ * interface.
++ */
++static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
++{
++ return dev->controller->clk_khz;
++}
++
++/**
++ * intel_cln_i2c_probe
++ * @param pdev: Pointer to GIP PCI device
++ * @param drvdata: private driver data
++ * @return 0 success < 0 failure
++ *
++ * Perform I2C-specific probing on behalf of the top-level GIP driver.
++ * Also call into I2C core driver routines for initiating the device.
++ */
++int intel_cln_i2c_probe(struct pci_dev *pdev,
++ struct dw_i2c_dev **drvdata)
++{
++ int retval = 0;
++ resource_size_t start = 0, len = 0;
++ struct dw_i2c_dev *dev = NULL;
++ struct i2c_adapter *adap = NULL;
++ void __iomem *reg_base = NULL;
++ struct dw_pci_controller *controller = NULL;
++
++ controller = &cln_gip_i2c_controller;
++
++ /* Clanton default configuration is fast mode, unless otherwise asked */
++ if (i2c_std_mode)
++ controller->bus_cfg = INTEL_CLN_STD_CFG | DW_IC_CON_SPEED_STD;
++
++ /* Determine the address of the I2C area */
++ start = pci_resource_start(pdev, GIP_I2C_BAR);
++ len = pci_resource_len(pdev, GIP_I2C_BAR);
++ if (!start || len == 0) {
++ dev_err(&pdev->dev, "bar%d not set\n", GIP_I2C_BAR);
++ retval = -ENODEV;
++ goto err;
++ }
++
++ reg_base = ioremap_nocache(start, len);
++ if (!reg_base) {
++ dev_err(&pdev->dev, "I/O memory remapping failed\n");
++ retval = -ENOMEM;
++ goto err;
++ }
++
++ dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL);
++ if (!dev) {
++ retval = -ENOMEM;
++ goto err_iounmap;
++ }
++
++ init_completion(&dev->cmd_complete);
++ mutex_init(&dev->lock);
++ dev->clk = NULL;
++ dev->controller = controller;
++ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
++ dev->base = reg_base;
++ dev->dev = get_device(&pdev->dev);
++ dev->functionality =
++ I2C_FUNC_I2C |
++ I2C_FUNC_10BIT_ADDR |
++ I2C_FUNC_SMBUS_BYTE |
++ I2C_FUNC_SMBUS_BYTE_DATA |
++ I2C_FUNC_SMBUS_WORD_DATA |
++ I2C_FUNC_SMBUS_I2C_BLOCK;
++ dev->master_cfg = controller->bus_cfg;
++
++ *drvdata = dev;
++
++ dev->tx_fifo_depth = controller->tx_fifo_depth;
++ dev->rx_fifo_depth = controller->rx_fifo_depth;
++ dev->explicit_stop = controller->explicit_stop;
++ retval = i2c_dw_init(dev);
++ if (retval)
++ goto err_release_drvdata;
++
++ adap = &dev->adapter;
++ i2c_set_adapdata(adap, dev);
++ adap->owner = THIS_MODULE;
++ adap->class = 0;
++ adap->algo = &i2c_dw_algo;
++ adap->dev.parent = &pdev->dev;
++ adap->nr = controller->bus_num;
++ snprintf(adap->name, sizeof(adap->name), "intel_cln_gip_i2c");
++
++ i2c_dw_disable_int(dev);
++ i2c_dw_clear_int(dev);
++ retval = i2c_add_numbered_adapter(adap);
++ if (retval) {
++ dev_err(&pdev->dev, "failure adding I2C adapter\n");
++ goto err_release_drvdata;
++ }
++
++ return 0;
++
++err_release_drvdata:
++ put_device(&pdev->dev);
++ kfree(dev);
++err_iounmap:
++ iounmap(reg_base);
++err:
++ return retval;
++}
++
++/**
++ * intel_cln_i2c_remove
++ * @param pdev: Pointer to GIP PCI device
++ * @param dev: Pointer to I2C private data
++ *
++ * Perform I2C-specific resource release on behalf of the top-level GIP driver.
++ */
++void intel_cln_i2c_remove(struct pci_dev *pdev,
++ struct dw_i2c_dev *dev)
++{
++
++ if (NULL == dev) {
++ dev_err(&pdev->dev, "%s: failure getting driver data\n",
++ __func__);
++ return;
++ }
++
++ i2c_dw_disable(dev);
++ i2c_del_adapter(&dev->adapter);
++ iounmap(dev->base);
++
++ kfree(dev);
++}
+diff --git a/drivers/mfd/intel_cln_gip_test.c b/drivers/mfd/intel_cln_gip_test.c
+new file mode 100644
+index 0000000..ea8d846
+--- /dev/null
++++ b/drivers/mfd/intel_cln_gip_test.c
+@@ -0,0 +1,1202 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton GIP (GPIO/I2C) Test module
++ *
++ * Clanton GIP + North-Cluster GPIO test module.
++ */
++
++#include <asm/tsc.h>
++#include <linux/cdev.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/gpio.h>
++#include <linux/interrupt.h>
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++#include <linux/spi/spi_gpio.h>
++#include <linux/slab.h>
++#include <linux/workqueue.h>
++
++#define DRIVER_NAME "intel_cln_gip_test"
++
++/**************************** Exported to LISA *******************************/
++
++/*
++ * Internally-used ioctl code. At the moment it is not reserved by any mainline
++ * driver.
++ */
++#define GIP_TEST_IOCTL_CODE 0xE0
++
++/*
++ * Integers for ioctl operation.
++ */
++#define IOCTL_CLN_GPIO_11 _IO(GIP_TEST_IOCTL_CODE, 0x00)
++#define IOCTL_CLN_GPIO_11_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x01)
++#define IOCTL_CLN_GPIO_12 _IO(GIP_TEST_IOCTL_CODE, 0x02)
++#define IOCTL_CLN_GPIO_12_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x03)
++#define IOCTL_CLN_GPIO_13 _IO(GIP_TEST_IOCTL_CODE, 0x04)
++#define IOCTL_CLN_GPIO_13_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x05)
++#define IOCTL_CLN_GPIO_14 _IO(GIP_TEST_IOCTL_CODE, 0x06)
++#define IOCTL_CLN_GPIO_14_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x07)
++#define IOCTL_CLN_GPIO_15 _IO(GIP_TEST_IOCTL_CODE, 0x08)
++#define IOCTL_CLN_GPIO_15_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x09)
++#define IOCTL_CLN_GPIO_16 _IO(GIP_TEST_IOCTL_CODE, 0x0A)
++#define IOCTL_CLN_GPIO_16_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0B)
++#define IOCTL_CLN_GPIO_17 _IO(GIP_TEST_IOCTL_CODE, 0x0C)
++#define IOCTL_CLN_GPIO_17_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0D)
++#define IOCTL_CLN_GPIO_19 _IO(GIP_TEST_IOCTL_CODE, 0x0E)
++#define IOCTL_CLN_GPIO_19_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x0F)
++#define IOCTL_CLN_GPIO_20 _IO(GIP_TEST_IOCTL_CODE, 0x10)
++#define IOCTL_CLN_GPIO_20_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x11)
++#define IOCTL_CLN_GPIO_21 _IO(GIP_TEST_IOCTL_CODE, 0x12)
++#define IOCTL_CLN_GPIO_21_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x13)
++#define IOCTL_CLN_GPIO_24 _IO(GIP_TEST_IOCTL_CODE, 0x14)
++#define IOCTL_CLN_GPIO_26 _IO(GIP_TEST_IOCTL_CODE, 0x15)
++#define IOCTL_CLN_GPIO_26_CLEANUP _IO(GIP_TEST_IOCTL_CODE, 0x16)
++/* Exercise callbacks for S0/S3 power-state transitions and vice-versa */
++#define IOCTL_CLN_GIP_SYSTEM_SUSPEND _IO(GIP_TEST_IOCTL_CODE, 0x17)
++#define IOCTL_CLN_GIP_SYSTEM_RESUME _IO(GIP_TEST_IOCTL_CODE, 0x18)
++
++#define GPIO_INT_EDGE_POS_LABEL "gpio-edge-pos"
++#define GPIO_INT_EDGE_NEG_LABEL "gpio-edge-neg"
++#define GPIO_INT_LEVEL_HIGH_LABEL "gpio-level-hi"
++#define GPIO_INT_LEVEL_LOW_LABEL "gpio-level-lo"
++#define GPIO_INT_BASIC_LABEL "gpio-edge-pos-basic"
++#define GPIO_PM_TEST_IRQ_LABEL "gpio_pm_test_irq"
++
++/*
++ * Board GPIO numbers.
++ * Mapping between the North/South cluster GPIO and GPIOLIB IDs.
++ */
++#define SUT_GPIO_NC_0 0x00
++#define SUT_GPIO_NC_1 0x01
++#define SUT_GPIO_NC_2 0x02
++#define SUT_GPIO_NC_3 0x03
++#define SUT_GPIO_NC_4 0x04
++#define SUT_GPIO_NC_5 0x05
++#define SUT_GPIO_NC_6 0x06
++#define SUT_GPIO_NC_7 0x07
++#define SUT_GPIO_SC_0 0x08
++#define SUT_GPIO_SC_1 0x09
++#define SUT_GPIO_SC_2 0x0A
++#define SUT_GPIO_SC_3 0x0B
++#define SUT_GPIO_SC_4 0x0C
++#define SUT_GPIO_SC_5 0x0D
++#define SUT_GPIO_SC_6 0x0E
++#define SUT_GPIO_SC_7 0x0F
++
++/*
++ * Bitbanged SPI bus numbers.
++ */
++#define GPIO_NC_BITBANG_SPI_BUS 0x0
++#define GPIO_SC_BITBANG_SPI_BUS 0x1
++
++/*****************************************************************************/
++
++/**
++ * struct intel_cln_gip_dev
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_cln_gip_test_dev {
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++};
++
++static struct intel_cln_gip_test_dev gip_test_dev;
++static struct class *gip_test_class;
++static DEFINE_MUTEX(gip_test_mutex);
++static int gip_test_major;
++
++/* Private pointers to NC/SC bitbanged SPI devices */
++static struct platform_device *spi_gpio_nc_pdev = NULL;
++static struct platform_device *spi_gpio_sc_pdev = NULL;
++
++/*
++ * Level-triggered interrupt variables
++ */
++/* Level-triggered GPIO workqueue */
++static struct delayed_work work;
++/* Level-triggered interrupt counter */
++static unsigned int level_int_count;
++/* By default, a level-triggered interrupt is a low-level triggered */
++static int level_high_triggered = 0;
++
++/*
++ * Interrupt performance metrics variables and parameters
++ */
++/* How many captures */
++#define INT_PERF_TEST_CAPTURES 10000
++/* Timestamp for latency test interrupt handler */
++static cycles_t perf_t1;
++/* Captures to be returned to user space */
++static cycles_t deltas[INT_PERF_TEST_CAPTURES];
++/* Couldn't find the actual define for this */
++#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
++
++static irqreturn_t gpio_pm_test_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_latency_handler(int irq, void *dev_id)
++{
++ /* t0 */
++ perf_t1 = get_cycles();
++
++ gpio_set_value(SUT_GPIO_SC_0, 0);
++
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_basic_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_pos_edge_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_neg_edge_handler(int irq, void *dev_id)
++{
++ /* Do nothing, just acknowledge the IRQ subsystem */
++ return IRQ_HANDLED;
++}
++
++static irqreturn_t gpio_level_handler(int irq, void *dev_id)
++{
++ /* Untrigger the interrupt */
++ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 0 : 1);
++
++ level_int_count ++;
++ if (level_int_count < 1000) {
++ /* Next task due in a jiffy */
++ schedule_delayed_work(&work, 1);
++ } else if (level_int_count == 1000){
++ /* OK */
++ } else {
++ /*
++ * We may get spurious interrupts. This because the TE requires
++ * some time to drive the actual value to the GPIO.
++ */
++ pr_info("Spurious interrupt\n");
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void gpio_level_drive(struct work_struct *work)
++{
++ /* TE to trigger the interrupt */
++ gpio_set_value(SUT_GPIO_SC_7, level_high_triggered ? 1 : 0);
++}
++
++/*
++ * Define bitbanged SPI interface over Nort-Cluster South-Cluster GPIO blocks.
++ * Assign GPIO to SCK/MOSI/MISO
++ */
++static struct spi_gpio_platform_data spi_gpio_nc_data = {
++ .sck = SUT_GPIO_NC_3,
++ .mosi = SUT_GPIO_NC_4,
++ .miso = SUT_GPIO_NC_5,
++ .num_chipselect = 1,
++};
++static struct spi_gpio_platform_data spi_gpio_sc_data = {
++ .sck = SUT_GPIO_SC_2,
++ .mosi = SUT_GPIO_SC_3,
++ .miso = SUT_GPIO_SC_4,
++ .num_chipselect = 1,
++};
++
++/*
++ * Board information for SPI devices.
++ */
++static struct spi_board_info spi_gpio_nc_board_info[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 1000,
++ .bus_num = GPIO_NC_BITBANG_SPI_BUS,
++ .mode = SPI_MODE_0,
++ .platform_data = &spi_gpio_nc_data,
++ /* Assign GPIO to CS */
++ .controller_data = (void *)SUT_GPIO_NC_6,
++ },
++};
++static struct spi_board_info spi_gpio_sc_board_info[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 1000,
++ .bus_num = GPIO_SC_BITBANG_SPI_BUS,
++ .mode = SPI_MODE_0,
++ .platform_data = &spi_gpio_sc_data,
++ /* Assign GPIO to CS */
++ .controller_data = (void *)SUT_GPIO_SC_5,
++ },
++};
++
++/**
++ * gpio_sc_level_int
++ *
++ * Request level triggered IRQ for SUT_GPIO_SC_6 and register
++ * SUT_GPIO_SC_7 as output GPIO.
++ * If positive equals to 0, the IRQ is high-level triggered.
++ * Otherwise, low-level triggered.
++ * Mask the IRQ if requested.
++ */
++static int gpio_sc_level_int(int positive, int masking)
++{
++ int ret = 0;
++ int irq = -1;
++
++ unsigned long out_init_val =
++ (positive ? GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
++
++ level_high_triggered = positive;
++
++ /* Initialise workqueue task */
++ INIT_DELAYED_WORK(&work, gpio_level_drive);
++
++ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_hi_level");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(SUT_GPIO_SC_7, out_init_val, "gpio_output");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
++ goto fail_release_first_gpio;
++ }
++
++ irq = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq, gpio_level_handler,
++ positive ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW,
++ positive ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_LEVEL_LOW_LABEL,
++ NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++
++ level_int_count = 0;
++
++ pr_info("Registered output gpio%d and IRQ for gpio%d\n", SUT_GPIO_SC_7,
++ SUT_GPIO_SC_6);
++
++ if (masking) {
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
++ pr_info("Masked gpio%d IRQ\n", SUT_GPIO_SC_6);
++ }
++
++ /*
++ * Submit task to workqueue to drive the external Test Equipment.
++ * Note the task is delayed long enough to have Aarvark already set up.
++ * This because Aardvark has to ignore the initial glitches during the
++ * previous GPIO setup phase.
++ */
++ schedule_delayed_work(&work, 20 * HZ);
++
++ return 0;
++
++fail_release_second_gpio:
++ gpio_free(SUT_GPIO_SC_7);
++fail_release_first_gpio:
++ gpio_free(SUT_GPIO_SC_6);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_level_int_teardown
++ *
++ * Release resources reserved by gpio_sc_level_int().
++ */
++static int gpio_sc_level_int_teardown(void)
++{
++ int irq = -1;
++
++ if (0 != cancel_delayed_work_sync(&work))
++ pr_warn("delayed work was still pending\n");
++
++ irq = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ /* Make sure no handler is still running by this time */
++ mdelay(20);
++
++ gpio_free(SUT_GPIO_SC_7);
++ gpio_free(SUT_GPIO_SC_6);
++
++ return 0;
++}
++
++/*
++ * gpio_sc_interrupt_perf
++ *
++ * Performs a basic GPIO interrupt latency test by timestamping delta between
++ * interrupt driven and handled over a GPIO loopback.
++ *
++ * Returns to userspace the array of deltas obtained during each capture.
++ * A total amount of INT_PERF_TEST_CAPTURES captures is performed.
++ *
++ */
++static int gpio_sc_interrupt_perf(unsigned long user_memloc)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio_input = SUT_GPIO_SC_1;
++ int gpio_output = SUT_GPIO_SC_0;
++ unsigned int i = 0;
++ cycles_t perf_t0 = 0;
++ cycles_t delta = 0;
++
++ /* Casting pointer to user-space location to write */
++ cycles_t __user *user_ptr = (cycles_t __user *)user_memloc;
++
++ /* Can we copy the captures array into user-space location? */
++ if (!access_ok(VERIFY_WRITE, user_ptr, sizeof(deltas))) {
++ pr_err("can't copy 0x%x bytes to user-space address 0x%p\n",
++ sizeof(deltas),user_ptr);
++ return -EFAULT;
++ }
++
++ /* Setup the GPIO */
++ if (!gpio_is_valid(gpio_input)) {
++ pr_err("gpio%d is invalid\n", gpio_input);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(gpio_output)) {
++ pr_err("gpio%d is invalid\n", gpio_output);
++ ret = -1;
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_intperf_in");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_output, GPIOF_OUT_INIT_LOW, "gpio_intperf_out");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_output, ret);
++ goto fail_release_input_gpio;
++ }
++
++ /* Setup IRQ handler for input GPIO */
++ irq = gpio_to_irq(gpio_input);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio_input);
++ goto fail_release_output_gpio;
++ }
++ if (0 != (ret = request_irq(irq, gpio_latency_handler,
++ IRQF_TRIGGER_RISING, "gpio_latency_handler", NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio_input);
++ goto fail_release_output_gpio;
++ }
++
++ /* Perform test */
++ for (i = 0; i < INT_PERF_TEST_CAPTURES; i ++) {
++ /* t0 */
++ perf_t0 = get_cycles();
++
++ /* Trigger interrupt */
++ gpio_set_value(gpio_output, 1);
++ mdelay(2);
++
++ /* Check for wrap-around and store delta */
++ if(perf_t0 < perf_t1) {
++ delta = perf_t1 - perf_t0;
++ } else {
++ delta = perf_t1 + (UINT64_MAX - perf_t0);
++ }
++ deltas[i] = delta;
++ }
++
++ /* Expose results to userspace */
++ ret = copy_to_user(user_ptr, &deltas, sizeof(deltas));
++
++ /* Release resources */
++
++ free_irq(irq, NULL);
++
++fail_release_output_gpio:
++ gpio_free(gpio_output);
++fail_release_input_gpio:
++ gpio_free(gpio_input);
++fail:
++ if (0 != ret) {
++ pr_err("%s() failed\n", __func__);
++ }
++
++ return ret;
++}
++
++/**
++ * gpio_sc_pm_test_int
++ *
++ * Request rising edge-triggered IRQ for SUT_GPIO_SC_0
++ */
++static int gpio_sc_pm_test_int(void)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio_input = SUT_GPIO_SC_0;
++
++ /* Setup the GPIO */
++ if (!gpio_is_valid(gpio_input)) {
++ pr_err("gpio%d is invalid\n", gpio_input);
++ ret = -1;
++ goto fail;
++ }
++ ret = gpio_request_one(gpio_input, GPIOF_IN, "gpio_pm_test_in");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio_input, ret);
++ goto fail;
++ }
++
++ /* Setup IRQ handler for input GPIO */
++ irq = gpio_to_irq(gpio_input);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio_input);
++ goto fail_release_input_gpio;
++ }
++ if (0 != (ret = request_irq(irq, gpio_pm_test_handler,
++ IRQF_TRIGGER_RISING, GPIO_PM_TEST_IRQ_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio_input);
++ goto fail_release_input_gpio;
++ }
++
++ return 0;
++
++fail_release_input_gpio:
++ gpio_free(gpio_input);
++fail:
++ return ret;
++}
++
++/**
++ * gpio_sc_pm_test_int
++ *
++ * Release resources reserved by gpio_sc_edge_int()
++ */
++static int gpio_sc_pm_test_int_teardown(void)
++{
++ int irq = -1;
++
++ irq = gpio_to_irq(SUT_GPIO_SC_0);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_0);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(SUT_GPIO_SC_0);
++
++ return 0;
++}
++
++/**
++ * gpio_sc_edge_int
++ *
++ * Request IRQ for SUT_GPIO_SC_6 and SUT_GPIO_SC_7, respectively positive-edge
++ * and negative edge-triggered.
++ * Mask the IRQs if requested.
++ */
++static int gpio_sc_edge_int(int masking)
++{
++ int ret = 0;
++ int irq_pos = -1, irq_neg = -1;
++
++ if (!gpio_is_valid(SUT_GPIO_SC_6)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_6);
++ ret = -1;
++ goto fail;
++ }
++ if (!gpio_is_valid(SUT_GPIO_SC_7)) {
++ pr_err("gpio%d is invalid\n", SUT_GPIO_SC_7);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(SUT_GPIO_SC_6, GPIOF_IN, "gpio_pos_edge");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_6, ret);
++ goto fail;
++ }
++ ret = gpio_request_one(SUT_GPIO_SC_7, GPIOF_IN, "gpio_neg_edge");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", SUT_GPIO_SC_7, ret);
++ goto fail_release_first_gpio;
++ }
++
++ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq_pos < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
++ if (irq_neg < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
++ goto fail_release_second_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq_pos, gpio_pos_edge_handler,
++ IRQF_TRIGGER_RISING, GPIO_INT_EDGE_POS_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_6);
++ goto fail_release_second_gpio;
++ }
++ if (0 != (ret = request_irq(irq_neg, gpio_neg_edge_handler,
++ IRQF_TRIGGER_FALLING, GPIO_INT_EDGE_NEG_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", SUT_GPIO_SC_7);
++ goto fail_release_first_gpio_irq;
++ }
++
++ pr_info("Registered gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
++ SUT_GPIO_SC_7);
++
++ if (masking) {
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_6));
++ disable_irq(gpio_to_irq(SUT_GPIO_SC_7));
++ pr_info("Masked gpio%d and gpio%d IRQs\n", SUT_GPIO_SC_6,
++ SUT_GPIO_SC_7);
++ }
++
++ return 0;
++
++fail_release_first_gpio_irq:
++ free_irq(irq_pos, NULL);
++fail_release_second_gpio:
++ gpio_free(SUT_GPIO_SC_7);
++fail_release_first_gpio:
++ gpio_free(SUT_GPIO_SC_6);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_edge_int_teardown
++ *
++ * Release resources reserved by gpio_sc_edge_int()
++ */
++static int gpio_sc_edge_int_teardown(void)
++{
++ int irq_pos = -1, irq_neg = -1;
++
++ irq_neg = gpio_to_irq(SUT_GPIO_SC_7);
++ if (irq_neg < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_7);
++ } else {
++ free_irq(irq_neg, NULL);
++ }
++ irq_pos = gpio_to_irq(SUT_GPIO_SC_6);
++ if (irq_pos < 0) {
++ pr_err("can't map gpio%d to IRQ\n", SUT_GPIO_SC_6);
++ } else {
++ free_irq(irq_pos, NULL);
++ }
++
++ gpio_free(SUT_GPIO_SC_7);
++ gpio_free(SUT_GPIO_SC_6);
++
++ return 0;
++}
++
++/**
++ * gpio_sc_basic_int
++ *
++ * Register rising-edge interrupt handler on SUT_GPIO_SC_1
++ */
++static int gpio_sc_basic_int(void)
++{
++ int ret = 0;
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_1;
++
++ if (!gpio_is_valid(gpio)) {
++ pr_err("gpio%d is invalid\n", gpio);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(gpio, GPIOF_IN, "gpio_pos_edge_basic");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
++ goto fail;
++ }
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ if (0 != (ret = request_irq(irq, gpio_basic_handler,
++ IRQF_TRIGGER_RISING, GPIO_INT_BASIC_LABEL, NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ pr_info("Registered gpio%d IRQ\n", gpio);
++
++ return 0;
++
++fail_release_gpio:
++ gpio_free(gpio);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_basic_int_teardown
++ *
++ * Release resources reserved by gpio_sc_basic_int()
++ */
++static int gpio_sc_basic_int_teardown(void)
++{
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_1;
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(gpio);
++
++ return 0;
++}
++
++/**
++ * gpio_spidev_register
++ *
++ * Register a bitbanged SPI platform device and export a `spidev' to userspace.
++ * For North Cluster and South Cluster.
++ */
++static int gpio_spidev_register(int north_cluster)
++{
++ int err = -ENOMEM;
++ struct platform_device *pdev = NULL;
++ struct spi_gpio_platform_data *pdata =
++ north_cluster ? &spi_gpio_nc_data : &spi_gpio_sc_data;
++ struct spi_board_info *gpio_spi_board_info =
++ (north_cluster ? spi_gpio_nc_board_info : spi_gpio_sc_board_info);
++
++ if (north_cluster) {
++ spi_gpio_nc_pdev = NULL;
++ } else {
++ spi_gpio_sc_pdev = NULL;
++ }
++
++ pdev = platform_device_alloc("spi_gpio",
++ north_cluster ? GPIO_NC_BITBANG_SPI_BUS : GPIO_SC_BITBANG_SPI_BUS);
++ if (NULL == pdev) {
++ goto err_out;
++ }
++ err = platform_device_add_data(pdev, pdata, sizeof(*pdata));
++ if (err) {
++ goto err_put_pd;
++ }
++ err = platform_device_add(pdev);
++ if (err) {
++ goto err_put_pd;
++ }
++
++ err = spi_register_board_info(gpio_spi_board_info,
++ /*
++ * Note I pass an array here instead of a pointer in order not
++ * to break ARRAY_SIZE.
++ */
++ ARRAY_SIZE(spi_gpio_sc_board_info));
++ if (err) {
++ goto err_del_pd;
++ }
++
++ if (north_cluster) {
++ spi_gpio_nc_pdev = pdev;
++ } else {
++ spi_gpio_sc_pdev = pdev;
++ }
++
++ return 0;
++
++err_del_pd:
++ platform_device_del(pdev);
++err_put_pd:
++ platform_device_put(pdev);
++err_out:
++ return err;
++}
++
++/**
++ * gpio_spidev_unregister
++ *
++ * Release a bitbanged SPI platform device and its `spidev' interface.
++ * For North Cluster and South Cluster.
++ */
++static int gpio_spidev_unregister(int north_cluster)
++{
++ int ret = 0;
++
++ struct platform_device *pdev =
++ (north_cluster ? spi_gpio_nc_pdev : spi_gpio_sc_pdev);
++ struct spi_board_info *gpio_spi_board_info =
++ (north_cluster ? spi_gpio_nc_board_info : spi_gpio_sc_board_info);
++
++ ret = spi_unregister_board_info(gpio_spi_board_info,
++ /*
++ * Note I pass an array here instead of a pointer in order not
++ * to break ARRAY_SIZE.
++ */
++ ARRAY_SIZE(spi_gpio_sc_board_info));
++
++ if (0 == ret) {
++ platform_device_unregister(pdev);
++ }
++
++ if (north_cluster) {
++ spi_gpio_nc_pdev = NULL;
++ } else {
++ spi_gpio_sc_pdev = NULL;
++ }
++
++ return ret;
++}
++
++/**
++ * gip_system_power_transition
++ *
++ * @param state: 0 if transition to S3, !0 if transition to S0
++ * @return 0 success < 0 failure
++ *
++ * Exercise system-wide suspend/resume power management transitions.
++ *
++ */
++static int gip_system_power_transition(int state)
++{
++ struct pci_dev *gip = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, NULL);
++ if (NULL == gip) {
++ pr_err("can't find GIP PCI device\n");
++ return -ENOENT;
++ }
++
++ if (0 == state) {
++ gip->driver->driver.pm->suspend(&gip->dev);
++ } else {
++ gip->driver->driver.pm->resume(&gip->dev);
++ }
++
++ /* Decrement reference count of PCI device */
++ if (NULL != pci_get_device(PCI_VENDOR_ID_INTEL, 0x0934, gip)) {
++ pr_warn("found duplicate of GIP PCI device?!\n");
++ }
++
++ return 0;
++}
++
++/**
++ * gpio_sc_debounce
++ *
++ * Enable GPIO debounce functionality for SC_GPIO_1 (edge and level triggered)
++ *
++ */
++static int gpio_sc_debounce(int level)
++{
++ int ret = 0;
++ int irq = -1;
++ int gpio = SUT_GPIO_SC_0;
++
++ if (!gpio_is_valid(gpio)) {
++ pr_err("gpio%d is invalid\n", gpio);
++ ret = -1;
++ goto fail;
++ }
++
++ ret = gpio_request_one(gpio, GPIOF_IN,
++ level ? "gpio_level_mask" : "gpio_edge_mask");
++ if (ret) {
++ pr_err("can't request gpio%d (error %d)\n", gpio, ret);
++ goto fail;
++ }
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ /*
++ * Register IRQ. gpio_pos_edge_handler will do for both level and edge
++ * interrupts, as it's nooping.
++ */
++ if (0 != (ret = request_irq(irq, gpio_pos_edge_handler,
++ level ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_RISING,
++ level ? GPIO_INT_LEVEL_HIGH_LABEL : GPIO_INT_EDGE_POS_LABEL,
++ NULL))) {
++ pr_err("can't request IRQ for gpio%d\n", gpio);
++ goto fail_release_gpio;
++ }
++
++ /* Set debounce */
++ if (0 != (ret = gpio_set_debounce(gpio, 1))) {
++ pr_err("can't set debounce for gpio%d\n", gpio);
++ goto fail_free_irq;
++ }
++
++ return 0;
++
++fail_free_irq:
++ free_irq(irq, NULL);
++fail_release_gpio:
++ gpio_free(gpio);
++fail:
++ pr_err("%s() failed\n", __func__);
++
++ return ret;
++}
++
++/**
++ * gpio_sc_debounce_teardown
++ *
++ * Undo gpio_sc_debounce
++ *
++ */
++static int gpio_sc_debounce_teardown(int level)
++{
++ int irq = -1;
++ unsigned int gpio = SUT_GPIO_SC_0;
++
++ irq = gpio_to_irq(gpio);
++ if (irq < 0) {
++ pr_err("can't map gpio%d to IRQ\n", gpio);
++ } else {
++ free_irq(irq, NULL);
++ }
++
++ gpio_free(gpio);
++
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long gip_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ switch (cmd) {
++ case IOCTL_CLN_GPIO_11:
++ /* Edge-triggered interrupts */
++ ret = gpio_sc_edge_int(0);
++ break;
++ case IOCTL_CLN_GPIO_11_CLEANUP:
++ /* Edge-triggered interrupts cleanup */
++ ret = gpio_sc_edge_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_12:
++ /* Edge-triggered interrupts (masking) */
++ ret = gpio_sc_edge_int(1);
++ break;
++ case IOCTL_CLN_GPIO_12_CLEANUP:
++ /* Edge-triggered interrupts (masking) cleanup */
++ ret = gpio_sc_edge_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_13:
++ /* GPIO debounce (edge) */
++ ret = gpio_sc_debounce(0);
++ break;
++ case IOCTL_CLN_GPIO_13_CLEANUP:
++ /* GPIO debounce cleanup (edge) */
++ ret = gpio_sc_debounce_teardown(0);
++ break;
++ case IOCTL_CLN_GPIO_14:
++ /* High-level triggered interrupts */
++ ret = gpio_sc_level_int(1, 0);
++ break;
++ case IOCTL_CLN_GPIO_14_CLEANUP:
++ /* High-level triggered interrupts cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_15:
++ /* Low-level triggered interrupts */
++ ret = gpio_sc_level_int(0, 0);
++ break;
++ case IOCTL_CLN_GPIO_15_CLEANUP:
++ /*Low-level triggered interrupts cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_16:
++ /* Level triggered interrupts (masking) */
++ ret = gpio_sc_level_int(1, 1);
++ break;
++ case IOCTL_CLN_GPIO_16_CLEANUP:
++ /* Level triggered interrupts (masking) cleanup */
++ ret = gpio_sc_level_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_17:
++ /* GPIO debounce (level) */
++ ret = gpio_sc_debounce(1);
++ break;
++ case IOCTL_CLN_GPIO_17_CLEANUP:
++ /* GPIO debounce cleanup (level) */
++ ret = gpio_sc_debounce_teardown(1);
++ break;
++ case IOCTL_CLN_GPIO_19:
++ /* Register IRQ for SC_GPIO0 (PM transitions test) */
++ ret = gpio_sc_pm_test_int();
++ break;
++ case IOCTL_CLN_GPIO_19_CLEANUP:
++ /* Free IRQ for SC_GPIO0 (PM transitions test) */
++ ret = gpio_sc_pm_test_int_teardown();
++ break;
++ case IOCTL_CLN_GPIO_20:
++ /* NC bitbanged SPI */
++ ret = gpio_spidev_register(1);
++ break;
++ case IOCTL_CLN_GPIO_20_CLEANUP:
++ /* NC bitbanged SPI cleanup */
++ ret = gpio_spidev_unregister(1);
++ break;
++ case IOCTL_CLN_GPIO_21:
++ /* SC bitbanged SPI */
++ ret = gpio_spidev_register(0);
++ break;
++ case IOCTL_CLN_GPIO_21_CLEANUP:
++ /* SC bitbanged SPI cleanup */
++ ret = gpio_spidev_unregister(0);
++ break;
++ case IOCTL_CLN_GPIO_24:
++ /*
++ * SC GPIO interrupt performance test.
++ * Note it's shared between CLN_GPIO_24 and CLN_GPIO_25
++ * plus it doesn't need any cleanup call.
++ */
++ ret = gpio_sc_interrupt_perf(arg);
++ break;
++ case IOCTL_CLN_GPIO_26:
++ /* Interrupt for basic loopback test */
++ ret = gpio_sc_basic_int();
++ break;
++ case IOCTL_CLN_GPIO_26_CLEANUP:
++ /* Interrupt for basic loopback test cleanup */
++ ret = gpio_sc_basic_int_teardown();
++ break;
++ case IOCTL_CLN_GIP_SYSTEM_SUSPEND:
++ ret = gip_system_power_transition(0);
++ break;
++ case IOCTL_CLN_GIP_SYSTEM_RESUME:
++ ret = gip_system_power_transition(1);
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int gip_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&gip_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&gip_test_dev.open_lock)) {
++ mutex_unlock(&gip_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (gip_test_dev.opened) {
++ mutex_unlock(&gip_test_dev.open_lock);
++ mutex_unlock(&gip_test_mutex);
++ return -EINVAL;
++ }
++
++ gip_test_dev.opened++;
++ mutex_unlock(&gip_test_dev.open_lock);
++ mutex_unlock(&gip_test_mutex);
++ return 0;
++}
++
++static int gip_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&gip_test_dev.open_lock);
++ gip_test_dev.opened = 0;
++ mutex_unlock(&gip_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations gip_test_file_ops = {
++ .open = gip_test_open,
++ .release = gip_test_release,
++ .unlocked_ioctl = gip_test_ioctl,
++ .llseek = no_llseek,
++};
++
++/**
++ * intel_cln_gip_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ */
++static int intel_cln_gip_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ mutex_init(&gip_test_dev.open_lock);
++ cdev_init(&gip_test_dev.cdev, &gip_test_file_ops);
++ gip_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&gip_test_dev.cdev, MKDEV(gip_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(gip_test_class, NULL,
++ MKDEV(gip_test_major, minor), NULL,
++ "giptest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ return -EINVAL;
++ }
++
++ return 0;
++
++}
++
++static int intel_cln_gip_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(gip_test_dev.cdev.dev);
++
++ device_destroy(gip_test_class, MKDEV(gip_test_major, minor));
++ cdev_del(&gip_test_dev.cdev);
++
++ class_destroy(gip_test_class);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_gip_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_cln_gip_test_remove,
++};
++
++/**
++ * intel_cln_gip_test_init
++ *
++ * Load module.
++ */
++static int __init intel_cln_gip_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ gip_test_class = class_create(THIS_MODULE,"cln_gip_test");
++ if (IS_ERR(gip_test_class)) {
++ retval = PTR_ERR(gip_test_class);
++ printk(KERN_ERR "gip_test: can't register gip_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "gip_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ gip_test_major = MAJOR(dev);
++
++ memset(&gip_test_dev, 0x00, sizeof(gip_test_dev));
++ gip_test_dev.pldev = platform_create_bundle(
++ &intel_cln_gip_test_driver, intel_cln_gip_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(gip_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(gip_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(gip_test_class);
++err:
++ return retval;
++}
++
++static void __exit intel_cln_gip_test_exit(void)
++{
++ platform_device_unregister(gip_test_dev.pldev);
++ platform_driver_unregister(&intel_cln_gip_test_driver);
++}
++
++module_init(intel_cln_gip_test_init);
++module_exit(intel_cln_gip_test_exit);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
++MODULE_DESCRIPTION("Clanton GIP test module");
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
+index 5624fcb..4fbb1fd 100644
+--- a/drivers/mfd/lpc_sch.c
++++ b/drivers/mfd/lpc_sch.c
+@@ -41,21 +41,41 @@
+ #define WDTBASE 0x84
+ #define WDT_IO_SIZE 64
+
++/* BIOS control reg */
++#define LPC_BIOS_CNTL 0xD8
++#define LPC_BIOS_CNTL_WE 0x01
++
++/* Root complex base address derived registers */
++#define RCBA_BASE 0xF0
++
+ static struct resource smbus_sch_resource = {
+ .flags = IORESOURCE_IO,
+ };
+
+-
+ static struct resource gpio_sch_resource = {
+ .flags = IORESOURCE_IO,
+ };
+
++static struct resource spi_res = {
++ .flags = IORESOURCE_MEM,
++ .start = 0,
++ .end = 0,
++};
++
++static struct platform_device lpc_sch_spi = {
++ .name = "spi-lpc-sch",
++ .id = -1,
++ .resource = &spi_res,
++};
++
+ static struct mfd_cell lpc_sch_cells[] = {
++#ifndef CONFIG_INTEL_QUARK_X1000_SOC
+ {
+ .name = "isch_smbus",
+ .num_resources = 1,
+ .resources = &smbus_sch_resource,
+ },
++#endif
+ {
+ .name = "sch_gpio",
+ .num_resources = 1,
+@@ -79,6 +99,7 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_sch_ids) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) },
++ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CLANTON_ILB) },
+ { 0, }
+ };
+ MODULE_DEVICE_TABLE(pci, lpc_sch_ids);
+@@ -88,22 +109,26 @@ static int lpc_sch_probe(struct pci_dev *dev,
+ {
+ unsigned int base_addr_cfg;
+ unsigned short base_addr;
++ u32 rcba_base, bios_cntl;
+ int i;
+ int ret;
+
+- pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
+- if (!(base_addr_cfg & (1 << 31))) {
+- dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
+- return -ENODEV;
+- }
+- base_addr = (unsigned short)base_addr_cfg;
+- if (base_addr == 0) {
+- dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
+- return -ENODEV;
+- }
++ /* Clanton does not support iLB SMBUS */
++ if (id->device != PCI_DEVICE_ID_INTEL_CLANTON_ILB) {
++ pci_read_config_dword(dev, SMBASE, &base_addr_cfg);
++ if (!(base_addr_cfg & (1 << 31))) {
++ dev_err(&dev->dev, "Decode of the SMBus I/O range disabled\n");
++ return -ENODEV;
++ }
++ base_addr = (unsigned short)base_addr_cfg;
++ if (base_addr == 0) {
++ dev_err(&dev->dev, "I/O space for SMBus uninitialized\n");
++ return -ENODEV;
++ }
+
+- smbus_sch_resource.start = base_addr;
+- smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
++ smbus_sch_resource.start = base_addr;
++ smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1;
++ }
+
+ pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
+ if (!(base_addr_cfg & (1 << 31))) {
+@@ -132,6 +157,31 @@ static int lpc_sch_probe(struct pci_dev *dev,
+ if (ret)
+ goto out_dev;
+
++ /* Add RCBA SPI device */
++ if (id->device == PCI_DEVICE_ID_INTEL_CLANTON_ILB) {
++ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
++ pr_info("%s BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
++
++ /* Enable flash write */
++ bios_cntl |= LPC_BIOS_CNTL_WE;
++ pci_write_config_dword(dev, LPC_BIOS_CNTL, bios_cntl);
++
++ /* Verify */
++ pci_read_config_dword(dev, LPC_BIOS_CNTL, &bios_cntl);
++ pr_info("%s new BIOS_CNTL 0x%08x\n", __func__, bios_cntl);
++ }
++
++ pci_read_config_dword(dev, RCBA_BASE, &rcba_base);
++ rcba_base &= 0xFFFFC000;
++ spi_res.start = rcba_base + 0x3020;
++ spi_res.end = rcba_base + 0x3088;
++ pr_info("%s RCBA @ 0x%08x\n", __func__, rcba_base);
++ ret = platform_device_register(&lpc_sch_spi);
++ if (ret < 0){
++ pr_err("unable to register %s plat dev\n", lpc_sch_spi.name);
++ goto out_dev;
++ }
++
+ if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC
+ || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) {
+ pci_read_config_dword(dev, WDTBASE, &base_addr_cfg);
+diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
+index c7dd0cb..4352c6a 100644
+--- a/drivers/mmc/host/sdhci-pci.c
++++ b/drivers/mmc/host/sdhci-pci.c
+@@ -162,6 +162,10 @@ static const struct sdhci_pci_fixes sdhci_cafe = {
+ SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
+ };
+
++static const struct sdhci_pci_fixes sdhci_intel_cln = {
++ .quirks = SDHCI_QUIRK_NO_HISPD_BIT,
++};
++
+ static int mrst_hc_probe_slot(struct sdhci_pci_slot *slot)
+ {
+ slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+@@ -777,6 +781,14 @@ static const struct pci_device_id pci_ids[] = {
+
+ {
+ .vendor = PCI_VENDOR_ID_INTEL,
++ .device = PCI_DEVICE_ID_INTEL_CLN_SD,
++ .subvendor = PCI_ANY_ID,
++ .subdevice = PCI_ANY_ID,
++ .driver_data = (kernel_ulong_t)&sdhci_intel_cln,
++ },
++
++ {
++ .vendor = PCI_VENDOR_ID_INTEL,
+ .device = PCI_DEVICE_ID_INTEL_MRST_SD0,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
+index 46dcb54..7af4129 100644
+--- a/drivers/mtd/devices/Kconfig
++++ b/drivers/mtd/devices/Kconfig
+@@ -159,6 +159,11 @@ config MTD_MTDRAM
+ provide storage. You probably want to say 'N' unless you're
+ testing stuff.
+
++config MTD_MTD_CLN_ROM
++ bool "Simple R/O drive for SPI flash in Clanton x86 legacy block"
++ help
++ Driver to enable reading directly from legacy block SPI /sketch part
++
+ config MTDRAM_TOTAL_SIZE
+ int "MTDRAM device size in KiB"
+ depends on MTD_MTDRAM
+diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
+index 395733a..4c8e399 100644
+--- a/drivers/mtd/devices/Makefile
++++ b/drivers/mtd/devices/Makefile
+@@ -20,5 +20,4 @@ obj-$(CONFIG_MTD_M25P80) += m25p80.o
+ obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o
+ obj-$(CONFIG_MTD_SST25L) += sst25l.o
+ obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
+-
+-CFLAGS_docg3.o += -I$(src)
+\ No newline at end of file
++CFLAGS_docg3.o += -I$(src)
+diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+index 1164930..4e10f27 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
+@@ -26,8 +26,8 @@ config STMMAC_PLATFORM
+ If unsure, say N.
+
+ config STMMAC_PCI
+- bool "STMMAC PCI bus support (EXPERIMENTAL)"
+- depends on STMMAC_ETH && PCI && EXPERIMENTAL
++ bool "STMMAC PCI bus support"
++ depends on STMMAC_ETH && PCI
+ ---help---
+ This is to select the Synopsys DWMAC available on PCI devices,
+ if you have a controller with this interface, say Y or M here.
+@@ -54,6 +54,27 @@ config STMMAC_DA
+ By default, the DMA arbitration scheme is based on Round-robin
+ (rx:tx priority is 1:1).
+
++config STMMAC_PTP
++ bool "STMMAC PTP (1588-2005) Clock Support"
++ default n
++ depends on EXPERIMENTAL
++ select PPS
++ select PTP_1588_CLOCK
++ ---help---
++ Say Y here if you want support for 1588 Timestamping with a
++ Clanton device, using the PTP 1588 Clock support. This is
++ required to enable timestamping support for the device.
++
++ If unsure, say N.
++
++config STMMAC_PTP_CLK_MHZ
++ depends on STMMAC_PTP
++ int "Reference clock in Mhz"
++ default 50
++ ---help---
++ Frequency if MHz of the reference clock used to derive PTP time
++ locally. Permissable values are 1 - 255 inclusive
++
+ choice
+ prompt "Select the DMA TX/RX descriptor operating modes"
+ depends on STMMAC_ETH
+diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
+index c8e8ea6..0995db5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
+@@ -3,6 +3,7 @@ stmmac-$(CONFIG_STMMAC_RING) += ring_mode.o
+ stmmac-$(CONFIG_STMMAC_CHAINED) += chain_mode.o
+ stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o
+ stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o
++stmmac-$(CONFIG_STMMAC_PTP) += stmmac_ptp.o
+ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
+ dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
+ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
+diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
+index 186d148..ad16e73 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/common.h
++++ b/drivers/net/ethernet/stmicro/stmmac/common.h
+@@ -32,9 +32,15 @@
+ #include <linux/init.h>
+ #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+ #define STMMAC_VLAN_TAG_USED
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++#define STMMAC_VLAN_HASH
++#endif
+ #include <linux/if_vlan.h>
+ #endif
+
++#if defined(STMMAC_VLAN_HASH) || defined(CONFIG_STMMAC_PTP)
++#define STMMAC_ATDS_USED
++#endif
+ #include "descs.h"
+ #include "mmc.h"
+
+@@ -319,15 +325,16 @@ struct stmmac_dma_ops {
+ void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
+ };
+
++struct stmmac_priv;
+ struct stmmac_ops {
+ /* MAC core initialization */
+ void (*core_init) (void __iomem *ioaddr) ____cacheline_aligned;
+ /* Enable and verify that the IPC module is supported */
+- int (*rx_ipc) (void __iomem *ioaddr);
++ int (*set_rx_ipc) (void __iomem *ioaddr, bool on);
+ /* Dump MAC registers */
+ void (*dump_regs) (void __iomem *ioaddr);
+ /* Handle extra events on specific interrupts hw dependent */
+- int (*host_irq_status) (void __iomem *ioaddr);
++ int (*host_irq_status) (struct stmmac_priv * priv);
+ /* Multicast filter setting */
+ void (*set_filter) (struct net_device *dev, int id);
+ /* Flow control setting */
+@@ -340,6 +347,9 @@ struct stmmac_ops {
+ unsigned int reg_n);
+ void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
+ unsigned int reg_n);
++ /* Enable/Disable VLAN Hash filters */
++ int (*vlan_rx_add_vid)(struct stmmac_priv *priv, unsigned short vid);
++ int (*vlan_rx_kill_vid)(struct stmmac_priv *priv, unsigned short vid);
+ void (*set_eee_mode) (void __iomem *ioaddr);
+ void (*reset_eee_mode) (void __iomem *ioaddr);
+ void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
+diff --git a/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h
+index 223adf9..ce08163 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/descs.h
++++ b/drivers/net/ethernet/stmicro/stmmac/descs.h
+@@ -25,8 +25,8 @@
+ #define __DESCS_H__
+
+ struct dma_desc {
+- /* Receive descriptor */
+ union {
++ /* Receive descriptor */
+ struct {
+ /* RDES0 */
+ u32 payload_csum_error:1;
+@@ -160,6 +160,49 @@ struct dma_desc {
+ } des01;
+ unsigned int des2;
+ unsigned int des3;
++
++ /* Enhanced mode - with VLAN/1588-2005/IPC CHKSUM offload */
++ #if defined(STMMAC_ATDS_USED)
++ union {
++ /* Receive descriptor */
++ struct {
++ /* RDES4 */
++ u32 ip_payload_type:3;
++ u32 ip_header_error:1;
++ u32 ip_payload_error:1;
++ u32 ip_checksum_bypassed:1;
++ u32 ipv4_packet_received:1;
++ u32 ipv6_packet_received:1;
++ u32 message_type:4;
++ u32 ptp_frame_type:1;
++ u32 ptp_version:1;
++ u32 timestamp_dropped:1;
++ u32 reserved1:1;
++ u32 av_packet_received:1;
++ u32 av_tagged_packet_received:1;
++ u32 vlan_tag_priority_value:3;
++ u32 reserved2:3;
++ u32 layer3_filter_match:1;
++ u32 layer4_filter_match:1;
++ u32 layer3_layer4_filter_num_matched:2;
++ u32 reserved3:4;
++
++ /* RDES5 */
++ u32 reserved4;
++ }erx;
++
++ /* Transmit descriptor */
++ struct {
++ /* TDES4 */
++ u32 reserved1;
++
++ /* TDES5 */
++ u32 reserved2;
++ } etx;
++ } des05;
++ unsigned int ts_lo; /* des6 Tx/Rx timestmp lo */
++ unsigned int ts_hi; /* des7 Tx/Rx timestamp hi */
++ #endif
+ };
+
+ /* Transmit checksum insertion control */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+index 7ad56af..3042098 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+@@ -50,7 +50,14 @@ enum dwmac1000_irq_status {
+ rgmii_irq = 0x0001,
+ };
+ #define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
+-
++#define GMAC_INT_MASK_LPIIM 0x00000200 /* LPI Interrupt Mask */
++#define GMAC_INT_MASK_TSIM 0x00000100 /* Timestamp Interrupt Mask */
++#define GMAC_INT_MASK_PMTIM 0x00000004 /* PMT Interrupt Mask */
++#define GMAC_INT_MASK_PCSANCIM 0x00000002 /* PCS AN Completion */
++#define GMAC_INT_MASK_PCSLCHGIM 0x00000001 /* PCS Link Status */
++#define GMAC_INT_MASK_DEFAULT GMAC_INT_MASK_PCSLCHGIM | GMAC_INT_MASK_PCSANCIM\
++ | GMAC_INT_MASK_PMTIM | GMAC_INT_MASK_TSIM\
++ | GMAC_INT_MASK_LPIIM
+ /* PMT Control and Status */
+ #define GMAC_PMT 0x0000002c
+ enum power_event {
+@@ -135,6 +142,7 @@ enum inter_frame_gap {
+ #define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
+ #define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
+ #define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
++#define GMAC_FRAME_FILTER_VTFE 0x00010000 /* VLAN Tag Filter Enable */
+ #define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
+ /* GMII ADDR defines */
+ #define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
+@@ -145,11 +153,17 @@ enum inter_frame_gap {
+ #define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
+ #define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
+-
++/* GMAC VLAN TAG defines */
++#define GMAC_VLAN_TAG_VTHM 0x00080000 /* Hash Table Match Enable */
++#define GMAC_VLAN_TAG_ESVL 0x00040000 /* Enable S-VLAN */
++#define GMAC_VLAN_TAG_VTIM 0x00020000 /* VLAN Tag inverse match */
++#define GMAC_VLAN_TAG_ETV 0x00010000 /* Enable 12-bit tag comp */
++#define GMAC_VLAN_TAG_VLMASK 0x0000FFFF /* VLAN tag ID for Rx frames */
+ /*--- DMA BLOCK defines ---*/
+ /* DMA Bus Mode register defines */
+ #define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
+ #define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
++#define DMA_BUS_MODE_ATDS 0X00000080 /* Alternate Descriptor Size */
+ #define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
+ #define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
+ /* Programmable burst length (passed thorugh platform)*/
+@@ -169,6 +183,7 @@ enum rx_tx_priority_ratio {
+ #define DMA_BUS_MODE_USP 0x00800000
+ #define DMA_BUS_MODE_PBL 0x01000000
+ #define DMA_BUS_MODE_AAL 0x02000000
++#define DMA_BUS_MODE_RIX 0x80000000
+
+ /* DMA CRS Control and Status Register Mapping */
+ #define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
+@@ -230,5 +245,50 @@ enum rtc_control {
+ #define GMAC_MMC_TX_INTR 0x108
+ #define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
+
++/* VLAN Hash register offset */
++#define GMAC_VLAN_TAG_REP 0x584
++#define GMAC_VLAN_HASH 0x588
++#define GMAC_VLAN_HASH_MAXID 0x0F
++
++/***************** 1588 regs *****************/
++#define GMAC_TS_CTRL 0x700 /* Timestamp control reg */
++#define GMAC_TS_CTRL_TSENA 0x00000001 /* Timestamp enable */
++#define GMAC_TS_CTRL_TSCFUPDT 0x00000002 /* Timestamp fine/coarse */
++#define GMAC_TS_CTRL_TSINT 0x00000004 /* Timestamp initialise */
++#define GMAC_TS_CTRL_TSUPDT 0x00000008 /* Timestamp update */
++#define GMAC_TS_CTRL_TSTRIG 0x00000010 /* Timestamp trigger en */
++#define GMAC_TS_CTRL_TSADDREG 0x00000020 /* Timestamp addreg update */
++#define GMAC_TS_CTRL_TSENALL 0x00000100 /* Timestamp RX enable all */
++#define GMAC_TS_CTRL_TSCTRLSSR 0x00000200 /* Timestamp rollover ctr */
++#define GMAC_TS_CTRL_TSVER2ENA 0x00000400 /* Timestamp PTP v2 en */
++#define GMAC_TS_CTRL_TSIPENA 0x00000800 /* Timestamp PTP over eth */
++#define GMAC_TS_CTRL_TSIPV6ENA 0x00001000 /* Timestamp over IPV6 */
++#define GMAC_TS_CTRL_TSIPV4ENA 0x00002000 /* Timestamp over IPV4 */
++#define GMAC_TS_CTRL_TSEVNTENA 0x00004000 /* Timestamp event only */
++#define GMAC_TS_CTRL_TSMSTRENA 0x00008000 /* Timestamp master enable */
++#define GMAC_TS_CTRL_SNTYPSEL0 0x00000000 /* Timestamp type 0 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL1 0x00010000 /* Timestamp type 1 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL2 0x00020000 /* Timestamp type 2 snapshot */
++#define GMAC_TS_CTRL_SNTYPSEL3 0x00030000 /* Timestamp type 3 snapshot */
++#define GMAC_TS_CTRL_TSENMACADR 0x00040000 /* Timestamp mac filter en */
++#define GMAC_TS_CTRL_ATSFC 0x01000000 /* Timestamp aux fifo clear */
++#define GMAC_TS_CTRL_ATSEN0 0x02000000 /* Timestamp aux0 snap en */
++#define GMAC_TS_CTRL_ATSEN1 0x04000000 /* Timestamp aux1 snap en */
++#define GMAC_TS_CTRL_ATSEN2 0x08000000 /* Timestamp aux2 snap en */
++#define GMAC_TS_CTRL_ATSEN3 0x10000000 /* Timestamp aux3 enable */
++#define GMAC_SS_INC 0x704 /* Sub-second increment reg */
++#define GMAC_ST_SEC 0x708 /* System time seconds */
++#define GMAC_ST_NSEC 0x70C /* System time nseconds */
++#define GMAC_ST_SECUP 0x710 /* System time sec-update */
++#define GMAC_ST_NSECUP 0x714 /* System time nsec-update */
++#define GMAC_TS_APPEND 0x718 /* Timestamp append */
++#define GMAC_TT_SEC 0x71C /* Target time seconds */
++#define GMAC_TT_NSEC 0x720 /* Target time nseconds */
++#define GMAC_ST_HWSEC 0x724 /* System time high word sec */
++#define GMAC_ST_TS_STAT 0x728 /* Timestamp status */
++#define GMAC_PPS_CTRL 0x72C /* PPS signal output control */
++#define GMAC_AUXTS_NSEC 0x730 /* Aux timestamp counter nsec */
++#define GMAC_AUXTS_SEC 0x734 /* Aux timestamp counter sec */
++
+ extern const struct stmmac_dma_ops dwmac1000_dma_ops;
+ #endif /* __DWMAC1000_H__ */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+index bfe0226..b6d04ca 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+@@ -30,6 +30,7 @@
+ #include <linux/slab.h>
+ #include <asm/io.h>
+ #include "dwmac1000.h"
++#include "stmmac.h"
+
+ static void dwmac1000_core_init(void __iomem *ioaddr)
+ {
+@@ -38,7 +39,7 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ /* Mask GMAC interrupts */
+- writel(0x207, ioaddr + GMAC_INT_MASK);
++ writel(GMAC_INT_MASK_DEFAULT, ioaddr + GMAC_INT_MASK);
+
+ #ifdef STMMAC_VLAN_TAG_USED
+ /* Tag detection without filtering */
+@@ -46,11 +47,15 @@ static void dwmac1000_core_init(void __iomem *ioaddr)
+ #endif
+ }
+
+-static int dwmac1000_rx_ipc_enable(void __iomem *ioaddr)
++static int dwmac1000_set_rx_ipc(void __iomem *ioaddr, bool on)
+ {
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+
+- value |= GMAC_CONTROL_IPC;
++ if(on == true){
++ value |= GMAC_CONTROL_IPC;
++ }else{
++ value &= ~GMAC_CONTROL_IPC;
++ }
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ value = readl(ioaddr + GMAC_CONTROL);
+@@ -87,6 +92,7 @@ static void dwmac1000_get_umac_addr(void __iomem *ioaddr, unsigned char *addr,
+ static void dwmac1000_set_filter(struct net_device *dev, int id)
+ {
+ void __iomem *ioaddr = (void __iomem *) dev->base_addr;
++ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned int value = 0;
+ unsigned int perfect_addr_number;
+
+@@ -147,6 +153,10 @@ static void dwmac1000_set_filter(struct net_device *dev, int id)
+ /* Enable Receive all mode (to debug filtering_fail errors) */
+ value |= GMAC_FRAME_FILTER_RA;
+ #endif
++ if (priv->active_vlans != 0){
++ /* VLAN hash filtering is active on this interface */
++ value |= GMAC_FRAME_FILTER_VTFE;
++ }
+ writel(value, ioaddr + GMAC_FRAME_FILTER);
+
+ CHIP_DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+@@ -194,38 +204,42 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
+ }
+
+
+-static int dwmac1000_irq_status(void __iomem *ioaddr)
++#ifndef CONFIG_STMMAC_PTP
++#define stmmac_ptp_check_pps_event(x){}
++#endif
++
++static int dwmac1000_irq_status(struct stmmac_priv *priv)
+ {
+- u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
++ u32 intr_status = readl(priv->ioaddr + GMAC_INT_STATUS);
+ int status = 0;
+
+ /* Not used events (e.g. MMC interrupts) are not handled. */
+ if ((intr_status & mmc_tx_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_TX_INTR));
++ readl(priv->ioaddr + GMAC_MMC_TX_INTR));
+ status |= core_mmc_tx_irq;
+ }
+ if (unlikely(intr_status & mmc_rx_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_RX_INTR));
++ readl(priv->ioaddr + GMAC_MMC_RX_INTR));
+ status |= core_mmc_rx_irq;
+ }
+ if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
+- readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
++ readl(priv->ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ status |= core_mmc_rx_csum_offload_irq;
+ }
+ if (unlikely(intr_status & pmt_irq)) {
+ CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
+ /* clear the PMT bits 5 and 6 by reading the PMT
+ * status register. */
+- readl(ioaddr + GMAC_PMT);
++ readl(priv->ioaddr + GMAC_PMT);
+ status |= core_irq_receive_pmt_irq;
+ }
+ /* MAC trx/rx EEE LPI entry/exit interrupts */
+ if (intr_status & lpiis_irq) {
+ /* Clean LPI interrupt by reading the Reg 12 */
+- u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
++ u32 lpi_status = readl(priv->ioaddr + LPI_CTRL_STATUS);
+
+ if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
+ CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
+@@ -244,10 +258,110 @@ static int dwmac1000_irq_status(void __iomem *ioaddr)
+ status |= core_irq_rx_path_exit_lpi_mode;
+ }
+ }
++ if (unlikely(intr_status & time_stamp_irq)){
++ stmmac_ptp_check_pps_event(priv);
++ }
+
+ return status;
+ }
+
++static unsigned int dwmac1000_calc_vlan_4bit_crc ( const char * vlan )
++{
++ int i = 0, j = 0, len = 0, bit = 0;
++ unsigned int crc = 0xFFFFFFFF;
++ unsigned int poly = 0x04C11DB7;
++ unsigned char data;
++
++ if(unlikely(vlan == NULL)){
++ return 0;
++ }
++
++ for( i = 0; i < 2; i++ ) {
++ data = vlan[i];
++
++ if (i==0){
++ len = 8;
++ }else{
++ len = 4;
++ }
++
++ for( bit = 0; bit < len; bit++ ) {
++
++ j = ((crc >> 31) ^ data) & 0x1;
++ crc <<= 1;
++
++ if( j != 0 ){
++ crc ^= poly;
++ }
++
++ data >>= 1;
++ }
++ }
++ return crc;
++
++}
++
++static int dwmac1000_vlan_rx_add_vid(struct stmmac_priv *priv, unsigned short vid)
++{
++ u32 reg = 0;
++ u32 bit_nr = 0;
++
++ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
++ return -EINVAL;
++ }
++
++ if(priv->active_vlans == 0){
++
++ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
++ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
++ reg |= GMAC_FRAME_FILTER_VTFE;
++ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
++
++ /* Enable hash filtering - based on 12 bit vid */
++ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
++ reg |= GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x0000FFFF;
++ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
++ }
++
++ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
++ priv->active_vlans |= 1 << bit_nr;
++
++ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
++
++ return 0;
++}
++
++static int dwmac1000_vlan_rx_kill_vid(struct stmmac_priv *priv, unsigned short vid)
++{
++ u32 reg = 0;
++ u32 bit_nr = 0;
++
++ if(unlikely(priv == NULL || vid > GMAC_VLAN_HASH_MAXID)){
++ return -EINVAL;
++ }
++
++ bit_nr = (~dwmac1000_calc_vlan_4bit_crc((const char*)&vid)) >> 28;
++
++ priv->active_vlans &= ~(1 << bit_nr);
++ writel(priv->active_vlans, priv->ioaddr + GMAC_VLAN_HASH);
++
++ if(priv->active_vlans == 0){
++
++ /* Disable hash filtering */
++ reg = readl(priv->ioaddr + GMAC_VLAN_TAG);
++ reg &= ~(GMAC_VLAN_TAG_VTHM | GMAC_VLAN_TAG_ETV | 0x00000001);
++ writel(reg, priv->ioaddr + GMAC_VLAN_TAG);
++
++ /* Flip the VTFE bit in GMAC_FRAME_FILTER */
++ reg = readl(priv->ioaddr + GMAC_FRAME_FILTER);
++ reg &= ~GMAC_FRAME_FILTER_VTFE;
++ writel(reg, priv->ioaddr + GMAC_FRAME_FILTER);
++
++ }
++
++ return 0;
++}
++
+ static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
+ {
+ u32 value;
+@@ -297,9 +411,10 @@ static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
+ writel(value, ioaddr + LPI_TIMER_CTRL);
+ }
+
++
+ static const struct stmmac_ops dwmac1000_ops = {
+ .core_init = dwmac1000_core_init,
+- .rx_ipc = dwmac1000_rx_ipc_enable,
++ .set_rx_ipc = dwmac1000_set_rx_ipc,
+ .dump_regs = dwmac1000_dump_regs,
+ .host_irq_status = dwmac1000_irq_status,
+ .set_filter = dwmac1000_set_filter,
+@@ -307,6 +422,8 @@ static const struct stmmac_ops dwmac1000_ops = {
+ .pmt = dwmac1000_pmt,
+ .set_umac_addr = dwmac1000_set_umac_addr,
+ .get_umac_addr = dwmac1000_get_umac_addr,
++ .vlan_rx_add_vid = dwmac1000_vlan_rx_add_vid,
++ .vlan_rx_kill_vid = dwmac1000_vlan_rx_kill_vid,
+ .set_eee_mode = dwmac1000_set_eee_mode,
+ .reset_eee_mode = dwmac1000_reset_eee_mode,
+ .set_eee_timer = dwmac1000_set_eee_timer,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+index bf83c03..a0c08e1 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+@@ -59,9 +59,12 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
+ * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
+ * depending on pbl value.
+ */
++#ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ value = DMA_BUS_MODE_RIX | (pbl << DMA_BUS_MODE_PBL_SHIFT);
++#else
+ value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
+ (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+-
++#endif
+ /* Set the Fixed burst mode */
+ if (fb)
+ value |= DMA_BUS_MODE_FB;
+@@ -70,6 +73,10 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
+ if (mb)
+ value |= DMA_BUS_MODE_MB;
+
++#if defined(STMMAC_ATDS_USED)
++ value |= DMA_BUS_MODE_ATDS;
++#endif
++
+ #ifdef CONFIG_STMMAC_DA
+ value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
+ #endif
+diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+index f83210e..43472c0 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+@@ -67,12 +67,12 @@ static void dwmac100_dump_mac_regs(void __iomem *ioaddr)
+ readl(ioaddr + MAC_VLAN2));
+ }
+
+-static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
++static int dwmac100_set_rx_ipc(void __iomem *ioaddr, bool on)
+ {
+ return 0;
+ }
+
+-static int dwmac100_irq_status(void __iomem *ioaddr)
++static int dwmac100_irq_status(struct stmmac_priv *priv)
+ {
+ return 0;
+ }
+@@ -160,7 +160,7 @@ static void dwmac100_pmt(void __iomem *ioaddr, unsigned long mode)
+
+ static const struct stmmac_ops dwmac100_ops = {
+ .core_init = dwmac100_core_init,
+- .rx_ipc = dwmac100_rx_ipc_enable,
++ .set_rx_ipc = dwmac100_set_rx_ipc,
+ .dump_regs = dwmac100_dump_mac_regs,
+ .host_irq_status = dwmac100_irq_status,
+ .set_filter = dwmac100_set_filter,
+diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+index 0c74a70..50617c5 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
+@@ -149,6 +149,7 @@ void dwmac_mmc_intr_all_mask(void __iomem *ioaddr)
+ {
+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_INTR_MASK);
+ writel(MMC_DEFAULT_MASK, ioaddr + MMC_TX_INTR_MASK);
++ writel(MMC_DEFAULT_MASK, ioaddr + MMC_RX_IPC_INTR_MASK);
+ }
+
+ /* This reads the MAC core counters (if actaully supported).
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+index b05df89..611f70e 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+@@ -27,9 +27,11 @@
+ #define DRV_MODULE_VERSION "Nov_2012"
+
+ #include <linux/clk.h>
++#include <linux/clocksource.h>
+ #include <linux/stmmac.h>
+ #include <linux/phy.h>
+ #include <linux/pci.h>
++#include <linux/ptp_clock_kernel.h>
+ #include "common.h"
+
+ struct stmmac_priv {
+@@ -72,8 +74,22 @@ struct stmmac_priv {
+ u32 msg_enable;
+ spinlock_t lock;
+ spinlock_t tx_lock;
++
++ /* PTP */
++ struct ptp_clock *ptp_clock;
++ struct ptp_clock_info ptp_caps;
++ struct delayed_work overflow_work;
++ spinlock_t tmreg_lock;
++ struct cyclecounter ccnt;
++ struct timecounter tcnt;
++// struct timecompare tcmp;
++ int hwts;
++ struct stmmac_timer *tm;
++
+ int wolopts;
+ int wol_irq;
++
++ int active_vlans;
+ struct plat_stmmacenet_data *plat;
+ struct stmmac_counters mmc;
+ struct dma_features dma_cap;
+@@ -81,6 +97,8 @@ struct stmmac_priv {
+ struct clk *stmmac_clk;
+ int clk_csr;
+ int synopsys_id;
++ int irqmode_msi;
++ struct pci_dev * pdev;
+ struct timer_list eee_ctrl_timer;
+ bool tx_path_in_lpi_mode;
+ int lpi_irq;
+@@ -110,6 +128,63 @@ int stmmac_dvr_remove(struct net_device *ndev);
+ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ struct plat_stmmacenet_data *plat_dat,
+ void __iomem *addr);
++#ifdef CONFIG_STMMAC_PTP
++
++#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
++#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
++#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
++#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
++
++extern void stmmac_ptp_init(struct net_device *ndev, struct device * pdev);
++extern void stmmac_ptp_remove(struct stmmac_priv *priv);
++extern int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
++ struct ifreq *ifr, int cmd);
++extern void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb);
++extern void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb);
++extern void stmmac_ptp_check_pps_event(struct stmmac_priv *priv);
++#endif
++
++#ifdef CONFIG_HAVE_CLK
++static inline int stmmac_clk_enable(struct stmmac_priv *priv)
++{
++ if (!IS_ERR(priv->stmmac_clk))
++ return clk_prepare_enable(priv->stmmac_clk);
++
++ return 0;
++}
++
++static inline void stmmac_clk_disable(struct stmmac_priv *priv)
++{
++ if (IS_ERR(priv->stmmac_clk))
++ return;
++
++ clk_disable_unprepare(priv->stmmac_clk);
++}
++static inline int stmmac_clk_get(struct stmmac_priv *priv)
++{
++ priv->stmmac_clk = clk_get(priv->device, NULL);
++
++ if (IS_ERR(priv->stmmac_clk))
++ return PTR_ERR(priv->stmmac_clk);
++
++ return 0;
++}
++#else
++static inline int stmmac_clk_enable(struct stmmac_priv *priv)
++{
++ return 0;
++}
++static inline void stmmac_clk_disable(struct stmmac_priv *priv)
++{
++}
++static inline int stmmac_clk_get(struct stmmac_priv *priv)
++{
++ return 0;
++}
++#endif /* CONFIG_HAVE_CLK */
++
+ void stmmac_disable_eee_mode(struct stmmac_priv *priv);
+ bool stmmac_eee_init(struct stmmac_priv *priv);
+
+@@ -167,6 +242,7 @@ static inline int stmmac_register_pci(void)
+ static inline void stmmac_unregister_pci(void)
+ {
+ }
++
+ #endif /* CONFIG_STMMAC_PCI */
+
+ #endif /* __STMMAC_H__ */
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+index 1372ce2..0644dcd 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+@@ -31,6 +31,7 @@
+
+ #include "stmmac.h"
+ #include "dwmac_dma.h"
++#include "dwmac1000.h"
+
+ #define REG_SPACE_SIZE 0x1054
+ #define MAC100_ETHTOOL_NAME "st_mac100"
+@@ -231,9 +232,7 @@ static int stmmac_ethtool_getsettings(struct net_device *dev,
+ return -EBUSY;
+ }
+ cmd->transceiver = XCVR_INTERNAL;
+- spin_lock_irq(&priv->lock);
+ rc = phy_ethtool_gset(phy, cmd);
+- spin_unlock_irq(&priv->lock);
+ return rc;
+ }
+
+@@ -244,10 +243,7 @@ static int stmmac_ethtool_setsettings(struct net_device *dev,
+ struct phy_device *phy = priv->phydev;
+ int rc;
+
+- spin_lock(&priv->lock);
+ rc = phy_ethtool_sset(phy, cmd);
+- spin_unlock(&priv->lock);
+-
+ return rc;
+ }
+
+@@ -279,7 +275,7 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev)
+ static void stmmac_ethtool_gregs(struct net_device *dev,
+ struct ethtool_regs *regs, void *space)
+ {
+- int i;
++ int i, offset = 0;
+ u32 *reg_space = (u32 *) space;
+
+ struct stmmac_priv *priv = netdev_priv(dev);
+@@ -300,9 +296,20 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
+ /* MAC registers */
+ for (i = 0; i < 55; i++)
+ reg_space[i] = readl(priv->ioaddr + (i * 4));
++
++ /* VLAN registers */
++ offset = i;
++ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_TAG_REP);
++ reg_space[offset++] = readl(priv->ioaddr + GMAC_VLAN_HASH);
++
++ /* 1588 registers */
++ for(i = 0; i < 13; i++);
++ reg_space[i + offset] = readl(priv->ioaddr + (GMAC_TS_CTRL + (i * 4)));
++
+ /* DMA registers */
++ offset += i;
+ for (i = 0; i < 22; i++)
+- reg_space[i + 55] =
++ reg_space[i + offset] =
+ readl(priv->ioaddr + (DMA_BUS_MODE + (i * 4)));
+ }
+ }
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+index b75f4b2..f74b542 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+@@ -28,6 +28,9 @@
+ https://bugzilla.stlinux.com/
+ *******************************************************************************/
+
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++#include <asm/cln.h>
++#endif
+ #include <linux/clk.h>
+ #include <linux/kernel.h>
+ #include <linux/interrupt.h>
+@@ -135,6 +138,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+ #ifdef CONFIG_STMMAC_DEBUG_FS
+ static int stmmac_init_fs(struct net_device *dev);
+ static void stmmac_exit_fs(void);
++static int debugfs_registered = 0;
++
+ #endif
+
+ #define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
+@@ -502,13 +507,29 @@ static int stmmac_set_bfsize(int mtu, int bufsize)
+ }
+
+ /**
++ * init_dma_err_cleanup
++ *
++ * @dev: net device to clean
++ * Description: Does a cleanup if kmalloc fails during init
++ */
++static void init_dma_err_cleanup(struct stmmac_priv * priv)
++{
++ if (priv->tx_skbuff != NULL)
++ kfree(priv->tx_skbuff);
++ if (priv->rx_skbuff_dma != NULL)
++ kfree (priv->rx_skbuff_dma);
++ if (priv->rx_skbuff != NULL)
++ kfree (priv->rx_skbuff);
++}
++
++/**
+ * init_dma_desc_rings - init the RX/TX descriptor rings
+ * @dev: net device structure
+ * Description: this function initializes the DMA RX/TX descriptors
+ * and allocates the socket buffers. It suppors the chained and ring
+ * modes.
+ */
+-static void init_dma_desc_rings(struct net_device *dev)
++static int init_dma_desc_rings(struct net_device *dev)
+ {
+ int i;
+ struct stmmac_priv *priv = netdev_priv(dev);
+@@ -532,8 +553,16 @@ static void init_dma_desc_rings(struct net_device *dev)
+ txsize, rxsize, bfsize);
+
+ priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
++ if (priv->rx_skbuff_dma == NULL)
++ return -ENOMEM;
++
+ priv->rx_skbuff =
+ kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
++ if (priv->rx_skbuff == NULL){
++ init_dma_err_cleanup(priv);
++ return -ENOMEM;
++ }
++
+ priv->dma_rx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ rxsize *
+@@ -542,6 +571,11 @@ static void init_dma_desc_rings(struct net_device *dev)
+ GFP_KERNEL);
+ priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
+ GFP_KERNEL);
++ if (priv->tx_skbuff == NULL){
++ init_dma_err_cleanup(priv);
++ return -ENOMEM;
++ }
++
+ priv->dma_tx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ txsize *
+@@ -550,8 +584,9 @@ static void init_dma_desc_rings(struct net_device *dev)
+ GFP_KERNEL);
+
+ if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
++ init_dma_err_cleanup(priv);
+ pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
+- return;
++ return -ENOMEM;
+ }
+
+ DBG(probe, INFO, "stmmac (%s) DMA desc: virt addr (Rx %p, "
+@@ -569,8 +604,9 @@ static void init_dma_desc_rings(struct net_device *dev)
+ skb = __netdev_alloc_skb(dev, bfsize + NET_IP_ALIGN,
+ GFP_KERNEL);
+ if (unlikely(skb == NULL)) {
++ init_dma_err_cleanup(priv);
+ pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+- break;
++ return -ENOMEM;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+ priv->rx_skbuff[i] = skb;
+@@ -615,6 +651,8 @@ static void init_dma_desc_rings(struct net_device *dev)
+ pr_info("TX descriptor ring:\n");
+ display_ring(priv->dma_tx, txsize);
+ }
++
++ return 0;
+ }
+
+ static void dma_free_rx_skbufs(struct stmmac_priv *priv)
+@@ -736,6 +774,10 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
+ DMA_TO_DEVICE);
+ priv->hw->ring->clean_desc3(p);
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_tx_hwtstamp(priv, p, skb);
++#endif
++
+ if (likely(skb != NULL)) {
+ dev_kfree_skb(skb);
+ priv->tx_skbuff[entry] = NULL;
+@@ -963,6 +1005,25 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
+ }
+
+ /**
++ * stmmac_hw_set_rx_ipc
++ * @priv : pointer to the private device structure.
++ * Enables RX IPC offload if the feature is supported in hardware
++ */
++static int stmmac_hw_set_rx_ipc(struct stmmac_priv *priv, bool on)
++{
++ int ret = 0;
++
++ /* Enable the IPC (Checksum Offload) and check if the feature has been
++ * enabled during the core configuration. */
++ ret = priv->hw->mac->set_rx_ipc(priv->ioaddr, on);
++ if (on == true && !ret) {
++ pr_warning(" RX IPC Checksum Offload not configured.\n");
++ priv->plat->rx_coe = STMMAC_RX_COE_NONE;
++ }
++ return ret;
++}
++
++/**
+ * stmmac_tx_timer:
+ * @data: data pointer
+ * Description:
+@@ -1022,7 +1083,12 @@ static int stmmac_open(struct net_device *dev)
+ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
+ priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
+ priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
+- init_dma_desc_rings(dev);
++ ret = init_dma_desc_rings(dev);
++ if (ret < 0){
++ pr_err("%s: DMA initialization failed\n", __func__);
++ goto open_error;
++ }
++
+
+ /* DMA initialization and SW reset */
+ ret = stmmac_init_dma_engine(priv);
+@@ -1078,6 +1144,9 @@ static int stmmac_open(struct net_device *dev)
+ /* Set the HW DMA mode and the COE */
+ stmmac_dma_operation_mode(priv);
+
++ /* Enable RX IPC if supported by silicon */
++ ret = stmmac_hw_set_rx_ipc(priv, true);
++
+ /* Extra statistics */
+ memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
+ priv->xstats.threshold = tc;
+@@ -1085,9 +1154,12 @@ static int stmmac_open(struct net_device *dev)
+ stmmac_mmc_setup(priv);
+
+ #ifdef CONFIG_STMMAC_DEBUG_FS
+- ret = stmmac_init_fs(dev);
+- if (ret < 0)
+- pr_warning("%s: failed debugFS registration\n", __func__);
++ if (debugfs_registered == 0){
++ debugfs_registered = 1;
++ ret = stmmac_init_fs(dev);
++ if (ret < 0)
++ pr_warning("%s: failed debugFS registration\n", __func__);
++ }
+ #endif
+ /* Start the ball rolling... */
+ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
+@@ -1430,6 +1502,9 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
+ #endif
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_tx_hwtstamp(priv, priv->dma_rx + entry, skb);
++#endif
+ if (unlikely(!priv->plat->rx_coe))
+ skb_checksum_none_assert(skb);
+ else
+@@ -1588,9 +1663,19 @@ static netdev_features_t stmmac_fix_features(struct net_device *dev,
+ if (priv->plat->bugged_jumbo && (dev->mtu > ETH_DATA_LEN))
+ features &= ~NETIF_F_ALL_CSUM;
+
++ stmmac_hw_set_rx_ipc(priv, features & NETIF_F_RXCSUM);
++
+ return features;
+ }
+
++#if defined(CONFIG_INTEL_QUARK_X1000_SOC)
++ #define mask_pvm(x) cln_pci_pvm_mask(x)
++ #define unmask_pvm(x) cln_pci_pvm_unmask(x)
++#else
++ #define mask_pvm(x)
++ #define unmask_pvm(x)
++#endif
++
+ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ {
+ struct net_device *dev = (struct net_device *)dev_id;
+@@ -1601,10 +1686,12 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ return IRQ_NONE;
+ }
+
++ mask_pvm(priv->pdev);
++
+ /* To handle GMAC own interrupts */
+ if (priv->plat->has_gmac) {
+- int status = priv->hw->mac->host_irq_status((void __iomem *)
+- dev->base_addr);
++ int status = priv->hw->mac->host_irq_status(priv);
++
+ if (unlikely(status)) {
+ if (status & core_mmc_tx_irq)
+ priv->xstats.mmc_tx_irq_n++;
+@@ -1634,6 +1721,8 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+ /* To handle DMA interrupts */
+ stmmac_dma_interrupt(priv);
+
++ unmask_pvm(priv->pdev);
++
+ return IRQ_HANDLED;
+ }
+
+@@ -1669,7 +1758,15 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+ if (!priv->phydev)
+ return -EINVAL;
+
+- ret = phy_mii_ioctl(priv->phydev, rq, cmd);
++ switch (cmd) {
++#ifdef CONFIG_STMMAC_PTP
++ case SIOCSHWTSTAMP:
++ ret = stmmac_ptp_hwtstamp_ioctl(priv, rq, cmd);
++ break;
++#endif
++ default:
++ ret = phy_mii_ioctl(priv->phydev, rq, cmd);
++ }
+
+ return ret;
+ }
+@@ -1850,6 +1947,21 @@ static void stmmac_exit_fs(void)
+ }
+ #endif /* CONFIG_STMMAC_DEBUG_FS */
+
++#ifdef STMMAC_VLAN_HASH
++static int stmmac_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
++{
++ struct stmmac_priv *priv = netdev_priv(dev);
++ return priv->hw->mac->vlan_rx_add_vid(priv, vid);
++}
++
++static int stmmac_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
++{
++ struct stmmac_priv *priv = netdev_priv(dev);
++ return priv->hw->mac->vlan_rx_kill_vid(priv, vid);
++}
++
++#endif
++
+ static const struct net_device_ops stmmac_netdev_ops = {
+ .ndo_open = stmmac_open,
+ .ndo_start_xmit = stmmac_xmit,
+@@ -1860,6 +1972,10 @@ static const struct net_device_ops stmmac_netdev_ops = {
+ .ndo_tx_timeout = stmmac_tx_timeout,
+ .ndo_do_ioctl = stmmac_ioctl,
+ .ndo_set_config = stmmac_config,
++#ifdef STMMAC_VLAN_HASH
++ .ndo_vlan_rx_add_vid = stmmac_vlan_rx_add_vid,
++ .ndo_vlan_rx_kill_vid = stmmac_vlan_rx_kill_vid,
++#endif
+ #ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = stmmac_poll_controller,
+ #endif
+@@ -1924,13 +2040,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
+ /* Select the enhnaced/normal descriptor structures */
+ stmmac_selec_desc_mode(priv);
+
+- /* Enable the IPC (Checksum Offload) and check if the feature has been
+- * enabled during the core configuration. */
+- ret = priv->hw->mac->rx_ipc(priv->ioaddr);
+- if (!ret) {
+- pr_warning(" RX IPC Checksum Offload not configured.\n");
+- priv->plat->rx_coe = STMMAC_RX_COE_NONE;
+- }
++ ret = stmmac_hw_set_rx_ipc(priv, true);
+
+ if (priv->plat->rx_coe)
+ pr_info(" RX Checksum Offload Engine supported (type %d)\n",
+@@ -2001,6 +2111,12 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ /* Both mac100 and gmac support receive VLAN tag detection */
+ ndev->features |= NETIF_F_HW_VLAN_RX;
+ #endif
++#ifdef STMMAC_VLAN_HASH
++ ndev->features |= NETIF_F_HW_VLAN_FILTER;
++ ndev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
++ NETIF_F_RXCSUM;
++#endif
++
+ priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ if (flow_ctrl)
+@@ -2044,6 +2160,10 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
+ else
+ priv->clk_csr = priv->plat->clk_csr;
+
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_init(ndev, device);
++#endif
++
+ /* MDIO bus Registration */
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0) {
+@@ -2060,6 +2180,9 @@ error_clk_get:
+ unregister_netdev(ndev);
+ error_netdev_register:
+ netif_napi_del(&priv->napi);
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_remove(priv);
++#endif
+ free_netdev(ndev);
+
+ return NULL;
+@@ -2075,7 +2198,7 @@ int stmmac_dvr_remove(struct net_device *ndev)
+ {
+ struct stmmac_priv *priv = netdev_priv(ndev);
+
+- pr_info("%s:\n\tremoving driver", __func__);
++ pr_info("%s:\n\tremoving driver\n", __func__);
+
+ priv->hw->dma->stop_rx(priv->ioaddr);
+ priv->hw->dma->stop_tx(priv->ioaddr);
+@@ -2083,6 +2206,10 @@ int stmmac_dvr_remove(struct net_device *ndev)
+ stmmac_set_mac(priv->ioaddr, false);
+ stmmac_mdio_unregister(ndev);
+ netif_carrier_off(ndev);
++
++#ifdef CONFIG_STMMAC_PTP
++ stmmac_ptp_remove(priv);
++#endif
+ unregister_netdev(ndev);
+ free_netdev(ndev);
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+index 064eaac..38213d2 100644
+--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+@@ -24,29 +24,186 @@
+ *******************************************************************************/
+
+ #include <linux/pci.h>
++#include <linux/platform_data/clanton.h>
+ #include "stmmac.h"
+
+-struct plat_stmmacenet_data plat_dat;
+-struct stmmac_mdio_bus_data mdio_data;
+-struct stmmac_dma_cfg dma_cfg;
++/* List of supported PCI device IDs */
++#define STMMAC_VENDOR_ID 0x700
++#define STMMAC_DEVICE_ID 0x1108
++#define STMMAC_CLANTON_ID 0x0937
++#define MAX_INTERFACES 0x02
++
++#if defined (CONFIG_INTEL_QUARK_X1000_SOC)
++static int enable_msi = 1;
++#else
++static int enable_msi = 0;
++#endif
++module_param(enable_msi, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(enable_msi, "Enable PCI MSI mode");
++
++static int bus_id = 1;
++static char stmmac_mac_data[MAX_INTERFACES][ETH_ALEN];
++
++struct stmmac_cln_mac_data {
++ int phy_addr;
++ int bus_id;
++ cln_plat_id_t plat_id;
++};
++
++static struct stmmac_cln_mac_data phy_data [] = {
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 1,
++ .plat_id = CLANTON_EMULATION,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .plat_id = CLANTON_EMULATION,
++ },
++ {
++ .phy_addr = 3,
++ .bus_id = 1,
++ .plat_id = CLANTON_PEAK,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .plat_id = CLANTON_PEAK,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .plat_id = KIPS_BAY,
++ },
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 2,
++ .plat_id = KIPS_BAY,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .plat_id = CROSS_HILL,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .plat_id = CROSS_HILL,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .plat_id = CLANTON_HILL,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 2,
++ .plat_id = CLANTON_HILL,
++ },
++ {
++ .phy_addr = 1,
++ .bus_id = 1,
++ .plat_id = IZMIR,
++ },
++ {
++ .phy_addr = -1, /* not connected */
++ .bus_id = 2,
++ .plat_id = IZMIR,
++ },
++};
++
++
++static int stmmac_find_phy_addr(int mdio_bus_id, cln_plat_id_t cln_plat_id)
++{
++ int i = 0;
++
++ for (; i < sizeof(phy_data)/sizeof(struct stmmac_cln_mac_data); i++){
++ if ( phy_data[i].plat_id == cln_plat_id &&
++ phy_data[i].bus_id == mdio_bus_id)
++ return phy_data[i].phy_addr;
++ }
++
++ return -1;
++}
++
++static int stmmac_default_data(struct plat_stmmacenet_data *plat_dat,
++ int mdio_bus_id, const struct pci_device_id *id)
++{
++ int phy_addr = 0;
++ memset(plat_dat, 0, sizeof(struct plat_stmmacenet_data));
++
++ plat_dat->mdio_bus_data = kzalloc(sizeof(struct stmmac_mdio_bus_data),
++ GFP_KERNEL);
++ if (plat_dat->mdio_bus_data == NULL)
++ return -ENOMEM;
++
++ plat_dat->dma_cfg = kzalloc(sizeof(struct stmmac_dma_cfg),GFP_KERNEL);
++ if (plat_dat->dma_cfg == NULL)
++ return -ENOMEM;
++
++ if (id->device == STMMAC_CLANTON_ID) {
++
++ phy_addr = stmmac_find_phy_addr(mdio_bus_id,
++ intel_cln_plat_get_id());
++ if (phy_addr == -1)
++ return -ENODEV;
++
++ plat_dat->bus_id = mdio_bus_id;
++ plat_dat->phy_addr = phy_addr;
++ plat_dat->interface = PHY_INTERFACE_MODE_RMII;
++ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
++ plat_dat->clk_csr = 2;
++ plat_dat->has_gmac = 1;
++ plat_dat->force_sf_dma_mode = 1;
++
++ plat_dat->mdio_bus_data->phy_reset = NULL;
++ plat_dat->mdio_bus_data->phy_mask = 0;
++
++ plat_dat->dma_cfg->pbl = 16;
++ plat_dat->dma_cfg->fixed_burst = 1;
++ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++
++ } else {
++
++ plat_dat->bus_id = mdio_bus_id;
++ plat_dat->phy_addr = phy_addr;
++ plat_dat->interface = PHY_INTERFACE_MODE_GMII;
++ /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
++ plat_dat->clk_csr = 2;
++ plat_dat->has_gmac = 1;
++ plat_dat->force_sf_dma_mode = 1;
++
++ plat_dat->mdio_bus_data->phy_reset = NULL;
++ plat_dat->mdio_bus_data->phy_mask = 0;
++
++ plat_dat->dma_cfg->pbl = 32;
++ plat_dat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
++
++ }
++
++ return 0;
++}
+
+-static void stmmac_default_data(void)
++/**
++ * stmmac_pci_find_mac
++ *
++ * @prive: pointer to private stmmac structure
++ * @mdio_bus_id : MDIO bus identifier used to find the platform MAC id
++ *
++ * Attempt to find MAC in platform data. If not found then driver will generate
++ * a random one for itself in any case
++ */
++void stmmac_pci_find_mac (struct stmmac_priv * priv, unsigned int mdio_bus_id)
+ {
+- memset(&plat_dat, 0, sizeof(struct plat_stmmacenet_data));
+- plat_dat.bus_id = 1;
+- plat_dat.phy_addr = 0;
+- plat_dat.interface = PHY_INTERFACE_MODE_GMII;
+- plat_dat.clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */
+- plat_dat.has_gmac = 1;
+- plat_dat.force_sf_dma_mode = 1;
+-
+- mdio_data.phy_reset = NULL;
+- mdio_data.phy_mask = 0;
+- plat_dat.mdio_bus_data = &mdio_data;
+-
+- dma_cfg.pbl = 32;
+- dma_cfg.burst_len = DMA_AXI_BLEN_256;
+- plat_dat.dma_cfg = &dma_cfg;
++ unsigned int id = mdio_bus_id - 1;
++ if (priv == NULL || id >= MAX_INTERFACES)
++ return;
++
++ if (intel_cln_plat_get_mac(PLAT_DATA_MAC0+id,
++ (char*)&stmmac_mac_data[id]) == 0){
++ memcpy(priv->dev->dev_addr, &stmmac_mac_data[id], ETH_ALEN);
++ }
+ }
+
+ /**
+@@ -67,8 +224,21 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ int ret = 0;
+ void __iomem *addr = NULL;
+ struct stmmac_priv *priv = NULL;
++ struct plat_stmmacenet_data *plat_dat = NULL;
+ int i;
+
++ plat_dat = kmalloc(sizeof(struct plat_stmmacenet_data), GFP_KERNEL);
++ if (plat_dat == NULL){
++ ret = -ENOMEM;
++ goto err_out_map_failed;
++ }
++
++ /* return -ENODEV for non existing PHY, stop probing here */
++ ret = stmmac_default_data(plat_dat, bus_id, id);
++ if (ret != 0)
++ goto err_platdata;
++
++
+ /* Enable pci device */
+ ret = pci_enable_device(pdev);
+ if (ret) {
+@@ -96,30 +266,51 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
+ break;
+ }
+ pci_set_master(pdev);
++ if(enable_msi == 1){
++ pci_enable_msi(pdev);
++ pr_info("stmmac MSI mode enabled");
++ }
+
+- stmmac_default_data();
++ pr_info("Vendor 0x%04x Device 0x%04x\n",
++ id->vendor, id->device);
+
+- priv = stmmac_dvr_probe(&(pdev->dev), &plat_dat, addr);
++ priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
+ if (!priv) {
+ pr_err("%s: main driver probe failed", __func__);
+ goto err_out;
+ }
++
++ stmmac_pci_find_mac(priv, bus_id);
++
+ priv->dev->irq = pdev->irq;
+ priv->wol_irq = pdev->irq;
+-
++ priv->irqmode_msi = enable_msi;
++ priv->pdev = pdev;
++ #ifdef CONFIG_INTEL_QUARK_X1000_SOC
++ priv->lpi_irq = -ENXIO;
++ #endif
+ pci_set_drvdata(pdev, priv->dev);
+
+ pr_debug("STMMAC platform driver registration completed");
++ bus_id++;
+
+ return 0;
+
+ err_out:
+ pci_clear_master(pdev);
+-err_out_map_failed:
+ pci_release_regions(pdev);
+ err_out_req_reg_failed:
+ pci_disable_device(pdev);
+-
++err_platdata:
++ if (plat_dat != NULL){
++ if (plat_dat->dma_cfg != NULL)
++ kfree (plat_dat->dma_cfg);
++ if (plat_dat->mdio_bus_data != NULL)
++ kfree (plat_dat->mdio_bus_data);
++ kfree(plat_dat);
++ }
++err_out_map_failed:
++ bus_id++;
+ return ret;
+ }
+
+@@ -138,6 +329,21 @@ static void stmmac_pci_remove(struct pci_dev *pdev)
+ stmmac_dvr_remove(ndev);
+
+ pci_set_drvdata(pdev, NULL);
++
++ if(enable_msi == 1) {
++ if(pci_dev_msi_enabled(pdev)) {
++ pci_disable_msi(pdev);
++ }
++ }
++
++ if (priv->plat != NULL) {
++ if (priv->plat->dma_cfg != NULL)
++ kfree (priv->plat->dma_cfg);
++ if (priv->plat->mdio_bus_data != NULL)
++ kfree (priv->plat->mdio_bus_data);
++ kfree(priv->plat);
++ }
++
+ pci_iounmap(pdev, priv->ioaddr);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+@@ -167,12 +373,10 @@ static int stmmac_pci_resume(struct pci_dev *pdev)
+ }
+ #endif
+
+-#define STMMAC_VENDOR_ID 0x700
+-#define STMMAC_DEVICE_ID 0x1108
+-
+ static DEFINE_PCI_DEVICE_TABLE(stmmac_id_table) = {
+ {PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
+ {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
++ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, STMMAC_CLANTON_ID)},
+ {}
+ };
+
+diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+new file mode 100644
+index 0000000..8552d0c
+--- /dev/null
++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+@@ -0,0 +1,723 @@
++/*******************************************************************************
++
++ STMMAC 1588-2005 hardware accel
++ Copyright(c) 2012 Intel Corporation. This code is based on IXGBE_PTP
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms and conditions of the GNU General Public License,
++ version 2, as published by the Free Software Foundation.
++
++ This program is distributed in the hope it will be useful, but WITHOUT
++ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
++ more details.
++
++ You should have received a copy of the GNU General Public License along with
++ this program; if not, write to the Free Software Foundation, Inc.,
++ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
++
++ The full GNU General Public License is included in this distribution in
++ the file called "COPYING".
++
++ Contact Information::w
++ Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
++
++*******************************************************************************/
++#include "stmmac.h"
++#include "dwmac1000.h"
++#include <linux/export.h>
++#include <linux/net_tstamp.h>
++
++/* PPSCMD0 */
++#define STMMAC_PPSCMD_NONE 0x00 /* No command */
++#define STMMAC_PPSCMD_START_SINGLE 0x01 /* Start single pulse */
++#define STMMAC_PPSCMD_START_PULSE 0x02 /* Start pulse train */
++#define STMMAC_PPSCMD_START_CANCEL 0x03 /* Cancel start */
++#define STMMAC_PPSCMD_STOP_PULSE_ATTIME 0x04 /* Stop pulse train at time */
++#define STMMAC_PPSCMD_STOP_PULSE_IMMED 0x05 /* Stop pulse train immediate */
++#define STMMAC_PPSCMD_STOP_CANCEL 0x06 /* Stop cancel pulse train */
++
++#define STMMAC_PTP_OVERFLOW_CHECK_ENABLED (u32)(1)
++#define STMMAC_PTP_PPS_ENABLED (u32)(1 << 1)
++#define STMMAC_PTP_HWTS_TX_EN (u32)(1 << 2)
++#define STMMAC_PTP_HWTS_RX_EN (u32)(1 << 3)
++
++#ifndef NSECS_PER_SEC
++#define NSECS_PER_SEC 1000000000ULL
++#endif
++
++/*
++ * Structure of STMMAC timer registers
++ *
++ * GMAC_TS_HWSEC GMAC_ST_SEC GMAC_ST_NSEC
++ * +--------------+ +--------------+ +---+---+------+
++ * STMMAC | 16 | | 32 | | 32 |
++ * +--------------+ +--------------+ +---+---+------+
++ *
++ * The counter for the STMMAC is 80 bits
++ * - HWSEC == overflow value for ST_SEC => 130 years to overflow (optional)
++ * - ST_SEC == seconds
++ * - ST_NSEC == nanoseconds
++ */
++
++/**
++ * stmmac_ptp_read - read raw cycle counter (to be used by time counter)
++ * @cc - the cyclecounter structure
++ *
++ * this function reads the cyclecounter registers and is called by the
++ * cyclecounter structure used to construct a ns counter from the
++ * arbitrary fixed point registers
++ */
++static cycle_t stmmac_ptp_read(const struct cyclecounter *ccnt)
++{
++ struct stmmac_priv *priv =
++ container_of(ccnt, struct stmmac_priv, ccnt);
++ cycle_t stamp = 0;
++
++ stamp = (u64)readl(priv->ioaddr + GMAC_ST_NSEC);
++ stamp |= (u64)readl(priv->ioaddr + GMAC_ST_SEC) << 32;
++
++ return stamp;
++}
++
++/**
++ * stmmac_ptp_adjfreq
++ * @ptp - the ptp clock structure
++ * @ppb - parts per billion adjustment from base
++ *
++ * adjust the frequency of the ptp cycle counter by the
++ * indicated ppb from the base frequency.
++ */
++static int stmmac_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
++{
++ return 0;
++}
++
++/**
++ * stmmac_ptp_adjtime
++ * @ptp - the ptp clock structure
++ * @delta - offset to adjust the cycle counter by
++ *
++ * adjust the timer by resetting the timecounter structure.
++ */
++static int stmmac_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ unsigned long flags;
++ u64 now;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++
++ now = timecounter_read(&priv->tcnt);
++ now += delta;
++
++ /* reset the timecounter */
++ timecounter_init(&priv->tcnt,
++ &priv->ccnt,
++ now);
++
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++ return 0;
++}
++
++/**
++ * stmmac_ptp_gettime
++ * @ptp - the ptp clock structure
++ * @ts - timespec structure to hold the current time value
++ *
++ * read the timecounter and return the correct value on ns,
++ * after converting it into a struct timespec.
++ */
++static int stmmac_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ u64 ns;
++ u32 remainder;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_read(&priv->tcnt);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ ts->tv_sec = div_u64_rem(ns, 1000000000ULL, &remainder);
++ ts->tv_nsec = remainder;
++
++ return 0;
++}
++
++/**
++ * stmmac_ptp_settime
++ * @ptp - the ptp clock structure
++ * @ts - the timespec containing the new time for the cycle counter
++ *
++ * reset the timecounter to use a new base value instead of the kernel
++ * wall timer value.
++ */
++static int stmmac_ptp_settime(struct ptp_clock_info *ptp,
++ const struct timespec *ts)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ u64 ns;
++ unsigned long flags;
++
++ ns = ts->tv_sec * 1000000000ULL;
++ ns += ts->tv_nsec;
++
++ /* reset the timecounter */
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ timecounter_init(&priv->tcnt, &priv->ccnt, ns);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ return 0;
++}
++
++/**
++ * stmmac_ptp_enable
++ * @ptp - the ptp clock structure
++ * @rq - the requested feature to change
++ * @on - whether to enable or disable the feature
++ *
++ * enable (or disable) ancillary features of the phc subsystem.
++ * our driver only supports the PPS feature on the X540
++ */
++static int stmmac_ptp_enable(struct ptp_clock_info *ptp,
++ struct ptp_clock_request *rq, int on)
++{
++ struct stmmac_priv *priv =
++ container_of(ptp, struct stmmac_priv, ptp_caps);
++ uint32_t reg = 0;
++
++ /**
++ * When enabling PPS functionality in STMMAC we need to unmask the
++ * interrupt mask reg and enable the TSTRIG bit in the timestamp control
++ * reg
++ */
++ if (rq->type == PTP_CLK_REQ_PPS) {
++ if (on){
++ priv->hwts |= STMMAC_PTP_PPS_ENABLED;
++
++ /* Enable TSTRIG */
++ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
++ reg |= GMAC_TS_CTRL_TSTRIG;
++ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ /* Unmask interrupt */
++ reg = readl(priv->ioaddr + GMAC_INT_MASK);
++ printk(KERN_INFO "%s[on] read interrupt mask 0x%08x\n", __func__, reg);
++ reg &= ~GMAC_INT_MASK_TSIM;
++ printk(KERN_INFO "%s[on] write interrupt mask 0x%08x\n", __func__, reg);
++ writel(reg, priv->ioaddr + GMAC_INT_MASK);
++ wmb();
++
++ } else {
++ /* Mask interrupt */
++ reg = readl(priv->ioaddr + GMAC_INT_MASK);
++ printk(KERN_INFO "%s[off] read interrupt mask 0x%08x\n", __func__, reg);
++ reg |= GMAC_INT_MASK_TSIM;
++ printk(KERN_INFO "%s[off] write interrupt mask 0x%08x\n", __func__, reg);
++ writel(reg, priv->ioaddr + GMAC_INT_MASK);
++ wmb();
++
++ /* Disable TSTRIG */
++ reg = readl(priv->ioaddr + GMAC_TS_CTRL);
++ reg &= ~GMAC_TS_CTRL_TSTRIG;
++ writel(reg, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ priv->hwts &=
++ ~STMMAC_PTP_PPS_ENABLED;
++ }
++ return 0;
++ }
++
++ return -ENOTSUPP;
++}
++
++/**
++ * stmmac_ptp_check_pps_event
++ * @priv - the private priv structure
++ *
++ * This function is called by the interrupt routine when checking for
++ * interrupts. It will check and handle a pps event.
++ */
++void stmmac_ptp_check_pps_event(struct stmmac_priv *priv)
++{
++ struct ptp_clock_event event;
++ event.type = PTP_CLOCK_PPS;
++
++ /* Make sure ptp clock is valid, and PPS event enabled */
++ if (!priv->ptp_clock ||
++ !(priv->hwts & STMMAC_PTP_PPS_ENABLED)){
++ return;
++ }
++
++ ptp_clock_event(priv->ptp_clock, &event);
++}
++
++#if 0
++/**
++ * stmmac_ptp_overflow_check - delayed work to detect SYSTIME overflow
++ * @work: structure containing information about this work task
++ *
++ * this work function is scheduled to continue reading the timecounter
++ * in order to prevent missing when the system time registers wrap
++ * around. This needs to be run approximately twice a minute when no
++ * PTP activity is occurring.
++ */
++void stmmac_ptp_overflow_check(struct stmmac_priv *priv)
++{
++ unsigned long elapsed_jiffies = priv->last_overflow_check - jiffies;
++ struct timespec ts;
++
++ if ((priv->hwts & STMMAC_PTP_OVERFLOW_CHECK_ENABLED) &&
++ (elapsed_jiffies >= STMMAC_OVERFLOW_PERIOD)) {
++ stmmac_ptp_gettime(&priv->ptp_caps, &ts);
++ priv->last_overflow_check = jiffies;
++ }
++}
++#endif
++
++/**
++ * stmmac_ptp_tx_hwtstamp - utility function which checks for TX time stamp
++ * @q_vector: structure containing interrupt and ring information
++ * @skb: particular skb to send timestamp with
++ *
++ * if the timestamp is valid, we convert it into the timecounter ns
++ * value, then store that result into the shhwtstamps structure which
++ * is passed up the network stack
++ */
++void stmmac_ptp_tx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb)
++{
++ /* Sanity check input */
++ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
++ return;
++ }
++
++ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
++ struct skb_shared_hwtstamps shhwtstamps;
++ u64 ns;
++ u64 regval;
++ unsigned long flags;
++
++ regval = (u64)pdma->ts_lo;
++ regval |= (u64)pdma->ts_hi << 32;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_cyc2time(&priv->tcnt, regval);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
++ shhwtstamps.hwtstamp = ns_to_ktime(ns);
++ skb_tstamp_tx(skb, &shhwtstamps);
++ }
++}
++
++/**
++ * stmmac_ptp_rx_hwtstamp - utility function which checks for RX time stamp
++ * @q_vector: structure containing interrupt and ring information
++ * @skb: particular skb to send timestamp with
++ *
++ * if the timestamp is valid, we convert it into the timecounter ns
++ * value, then store that result into the shhwtstamps structure which
++ * is passed up the network stack
++ */
++void stmmac_ptp_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *pdma,
++ struct sk_buff *skb)
++{
++ /* Sanity check input */
++ if (unlikely(priv == NULL || pdma == NULL || skb == NULL)){
++ return;
++ }
++
++ if(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP){
++ struct skb_shared_hwtstamps shhwtstamps;
++ u64 ns;
++ u64 regval;
++ unsigned long flags;
++
++ regval = (u64)pdma->ts_lo;
++ regval |= (u64)pdma->ts_hi << 32;
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++ ns = timecounter_cyc2time(&priv->tcnt, regval);
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++
++ memset(&shhwtstamps, 0, sizeof(shhwtstamps));
++ shhwtstamps.hwtstamp = ns_to_ktime(ns);
++ }
++}
++
++/**
++ * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping
++ * @priv: pointer to priv struct
++ * @ifreq: ioctl data
++ * @cmd: particular ioctl requested
++ *
++ * Outgoing time stamping can be enabled and disabled. Play nice and
++ * disable it when requested, although it shouldn't case any overhead
++ * when no packet needs it. At most one packet in the queue may be
++ * marked for time stamping, otherwise it would be impossible to tell
++ * for sure to which packet the hardware time stamp belongs.
++ *
++ * Incoming time stamping has to be configured via the hardware
++ * filters. Not all combinations are supported, in particular event
++ * type has to be specified. Matching the kind of event packet is
++ * not supported, with the exception of "all V2 events regardless of
++ * level 2 or 4".
++ */
++int stmmac_ptp_hwtstamp_ioctl(struct stmmac_priv *priv,
++ struct ifreq *ifr, int cmd)
++{
++ struct hwtstamp_config config;
++// struct stmmac_priv *priv = netdev_priv(netdev);
++ u32 tsctl = 0;
++
++ if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
++ return -EFAULT;
++
++ /* reserved for future extensions */
++ if (config.flags)
++ return -EINVAL;
++
++ /* Snapshot the reg - preserve Timestamp Interrupt Trigger Enable */
++ tsctl = readl(priv->ioaddr + GMAC_TS_CTRL) & GMAC_TS_CTRL_TSTRIG;
++
++ /* TX */
++ switch (config.tx_type) {
++ case HWTSTAMP_TX_OFF:
++ priv->hwts &= ~STMMAC_PTP_HWTS_TX_EN;
++ printk(KERN_INFO "%s set TX PTP en false\n", __func__);
++ break;
++ case HWTSTAMP_TX_ON:
++ priv->hwts |= STMMAC_PTP_HWTS_TX_EN;
++ printk(KERN_INFO "%s set TX PTP en true\n", __func__);
++ break;
++ default:
++ return -ERANGE;
++ }
++
++ /* RX */
++ priv->hwts |= STMMAC_PTP_HWTS_RX_EN;
++
++ switch (config.rx_filter) {
++
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
++ /*
++ * V1_L4 UDP any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
++ /*
++ * V1_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
++ /*
++ * V1_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=0, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSEVNTENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V1_L4_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
++ /*
++ * V2_L4 UDP any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
++ /*
++ * V2_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
++ /*
++ * V2_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1, IPV4=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSEVNTENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L4_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
++ /*
++ * V2_L2 Ethernet any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1,TSIPENA=1
++ * TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA | GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
++ /*
++ * V2_L2 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1, TSVER2ENA=1,TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
++ /*
++ * V2_L2 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
++ * TSIPENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_L2_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_EVENT:
++ /*
++ * V2_L2 Ethernet any event
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * SNAPTYPSEL=1, TSMSTRENA=x, TSEVNTENA=0, TSVER2ENA=1
++ * TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL1 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_EVENT \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
++ /*
++ * V2_L2_L4 Master
++ * Delay_Req
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=1, TSEVNTENA=1,
++ * TSVER2ENA=1,TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSMSTRENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSIPENA | GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_DELAY_REQ \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_PTP_V2_SYNC:
++ /*
++ * V2_L2_L4 Slave
++ * Sync
++ *
++ * SNAPTYPSEL=0, TSMSTRENA=0, TSEVNTENA=1, TSVER2ENA=1,
++ * TSIPENA=1, TSIPV4ENA=1
++ */
++ tsctl |= GMAC_TS_CTRL_SNTYPSEL0 | GMAC_TS_CTRL_TSVER2ENA;
++ tsctl |= GMAC_TS_CTRL_TSEVNTENA | GMAC_TS_CTRL_TSIPENA;
++ tsctl |= GMAC_TS_CTRL_TSIPV4ENA;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_PTP_V2_SYNC \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_ALL:
++ /*
++ * V2_L2_L4 Ethernet any event
++ *
++ * SYNC, Follow_Up, Delay_Req, Delay_Resp,
++ * Pdelay_Req, Pdelay_Resp, Pdelay_Resp_Follow_Up
++ *
++ * GMAC_TS_CTRL_TSENALL
++ */
++ tsctl |= GMAC_TS_CTRL_TSENALL;
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_ALL \n", __func__);
++ break;
++
++ case HWTSTAMP_FILTER_NONE:
++ printk(KERN_INFO "%s HWTSTAMP_FILTER_NONE \n", __func__);
++ priv->hwts &= ~STMMAC_PTP_HWTS_RX_EN;
++ break;
++
++ default:
++ printk(KERN_INFO "%s error ioctl rx type %d \n", __func__, config.rx_filter);
++ /* bad/unknown parameter */
++ return -ERANGE;
++ }
++
++ /* Set the TS CTRL reg */
++ tsctl |= GMAC_TS_CTRL_TSENA;
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ printk(KERN_INFO "%s sync ts_ctl @ value 0x%08x\n", __func__, tsctl);
++
++ return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
++ -EFAULT : 0;
++}
++
++
++#define DEFAULT_PTP_CLK 50
++
++/**
++ * stmmac_ptp_init_timestamp - initialise the PTP clock
++ * @priv - pointer to the priv structure
++ *
++ * This function initialises the PTP clock consistent with the method spelled
++ * out in the Snopsys documentation
++ */
++static void stmmac_ptp_init_timestamp(struct stmmac_priv *priv)
++{
++ unsigned long tsctl = GMAC_TS_CTRL_TSENA, flags = 0;
++ uint8_t ssinc = CONFIG_STMMAC_PTP_CLK_MHZ;
++
++ /* Enable TS */
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++
++ /* Write SSINC - number of nano seconds to increment on each clock */
++ if(ssinc == 0){
++ ssinc = DEFAULT_PTP_CLK;
++ }
++ ssinc = 1000/ssinc;
++ writel(ssinc, priv->ioaddr + GMAC_SS_INC);
++ wmb();
++
++ printk(KERN_INFO "%s setting PTP_CLK to 0x%02x\n", __func__, ssinc);
++
++ /* Reset system time registers to zero */
++ writel(0x00000000, priv->ioaddr + GMAC_ST_SEC);
++ writel(0x00000000, priv->ioaddr + GMAC_ST_NSEC);
++ wmb();
++
++ /* Set TSINT to latch values in ST_SEC and ST_NSEC */
++ tsctl |= GMAC_TS_CTRL_TSINT;
++ writel(tsctl, priv->ioaddr + GMAC_TS_CTRL);
++ wmb();
++ printk(KERN_INFO "%s tsctl == 0x%08lx (TSINIT | TSENA)\n", __func__, tsctl);
++
++ spin_lock_irqsave(&priv->tmreg_lock, flags);
++
++ /* Init timecounter */
++ memset(&priv->ccnt, 0, sizeof(priv->ccnt));
++ priv->ccnt.read = stmmac_ptp_read;
++ priv->ccnt.mask = CLOCKSOURCE_MASK(64);
++ priv->ccnt.mult = 1;
++ priv->ccnt.shift = 0;
++
++ /* reset the ns time counter */
++ timecounter_init(&priv->tcnt, &priv->ccnt,
++ ktime_to_ns(ktime_get_real()));
++
++ spin_unlock_irqrestore(&priv->tmreg_lock, flags);
++}
++
++/**
++ * stmmac_ptp_init
++ * @priv - the stmmac private priv structure
++ *
++ * This function performs the required steps for enabling ptp
++ * support. If ptp support has already been loaded it simply calls the
++ * cyclecounter init routine and exits.
++ */
++void stmmac_ptp_init(struct net_device *ndev, struct device * pdev)
++{
++ struct stmmac_priv *priv = netdev_priv(ndev);
++
++ /* Ensure the timestamp interrupt is masked */
++ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
++
++ /* Fill out PTP callback contents */
++ snprintf(priv->ptp_caps.name, 16, "%pm", ndev->dev_addr);
++ priv->ptp_caps.owner = THIS_MODULE;
++ priv->ptp_caps.max_adj = 0; /* Cannot be adjusted */
++ priv->ptp_caps.n_alarm = 0;
++ priv->ptp_caps.n_ext_ts = 0;
++ priv->ptp_caps.n_per_out = 0;
++ priv->ptp_caps.pps = 0;
++ priv->ptp_caps.adjfreq = stmmac_ptp_adjfreq;
++ priv->ptp_caps.adjtime = stmmac_ptp_adjtime;
++ priv->ptp_caps.gettime = stmmac_ptp_gettime;
++ priv->ptp_caps.settime = stmmac_ptp_settime;
++ priv->ptp_caps.enable = stmmac_ptp_enable;
++
++ spin_lock_init(&priv->tmreg_lock);
++
++ stmmac_ptp_init_timestamp(priv);
++
++ /* Init to default state */
++// priv->hwts = STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
++
++ priv->ptp_clock = ptp_clock_register(&priv->ptp_caps, pdev);
++ if (IS_ERR(priv->ptp_clock)) {
++ priv->ptp_clock = NULL;
++ printk(KERN_ERR "%s ptp_clock_reg failed!\n", __func__);
++ } else {
++ printk(KERN_INFO "%s ptp_clock_reg success!\n", __func__);
++ }
++
++ return;
++}
++
++/**
++ * stmmac_ptp_remove - disable ptp device and stop the overflow check
++ * @priv: pointer to priv struct
++ *
++ * this function stops the ptp support, and cancels the delayed work.
++ */
++void stmmac_ptp_remove(struct stmmac_priv *priv)
++{
++ /* Ensure the timestamp interrupt is masked */
++ writel(GMAC_INT_MASK_TSIM, priv->ioaddr + GMAC_INT_MASK);
++
++ /* stop the overflow check task */
++// priv->hwts &= ~STMMAC_PTP_OVERFLOW_CHECK_ENABLED;
++
++ if (priv->ptp_clock != NULL) {
++ ptp_clock_unregister(priv->ptp_clock);
++ priv->ptp_clock = NULL;
++ printk(KERN_INFO "%s removed ptp_clock\n", __func__);
++ }
++}
++
+diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
+index 044b532..dc92097 100644
+--- a/drivers/net/phy/mdio_bus.c
++++ b/drivers/net/phy/mdio_bus.c
+@@ -95,7 +95,7 @@ static struct class mdio_bus_class = {
+
+ #if IS_ENABLED(CONFIG_OF_MDIO)
+ /* Helper function for of_mdio_find_bus */
+-static int of_mdio_bus_match(struct device *dev, void *mdio_bus_np)
++static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np)
+ {
+ return dev->of_node == mdio_bus_np;
+ }
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index c86bae8..6def5f6 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -672,6 +672,10 @@ config INTEL_MFLD_THERMAL
+ Say Y here to enable thermal driver support for the Intel Medfield
+ platform.
+
++if INTEL_QUARK_X1000_SOC
++source "drivers/platform/x86/quark/Kconfig"
++endif
++
+ config INTEL_IPS
+ tristate "Intel Intelligent Power Sharing"
+ depends on ACPI
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index bf7e4f9..fce76ef 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
+ obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
+ obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
+ obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += quark/
+diff --git a/drivers/platform/x86/quark/Kconfig b/drivers/platform/x86/quark/Kconfig
+new file mode 100644
+index 0000000..5d47629
+--- /dev/null
++++ b/drivers/platform/x86/quark/Kconfig
+@@ -0,0 +1,75 @@
++config INTEL_CLN_ESRAM
++ bool "eSRAM - embedded SRAM driver for Intel Clanton platform"
++ depends on INTEL_QUARK_X1000_SOC && PM
++ select KALLSYMS
++ select CRC16
++ help
++ Say Y here to enable eSRAM overlay and software-initiated ECC
++ updates. eSRAM overlaying allows for code/data structures to be
++ mapped into eSRAM thus providing far faster access to code/data
++ than ordinary DRAM. Slower than cache RAM faster than DRAM.
++
++config INTEL_CLN_ECC_REFRESH_PERIOD
++ int "Choose eSRAM ECC coverage period"
++ depends on INTEL_CLN_ESRAM
++ default 24
++ help
++ Select the period over which *RAM ECC codes should be refreshed.
++ IA Core will periodically enable disabled eSRAM pages to ensure all of
++ disabled eSRAM pages are 'address walked' in this period. A logical
++ component within the silicon on Clanton will ensure DRAM (and
++ overlayed eSRAM) pages by extension are similarly updated over the
++ same period. This variable controlls how long a time this address
++ walking algorithm should take. For a noisy environment like a
++ sub-station or a satellite update frequently. For less noisy
++ environments this value should be lower. Default 24 hours is right for
++ most people. Set to zero to disable - this is NOT recommended. Max 48
++ hours.
++
++config INTEL_CLN_ECC_SCRUB
++ bool "Hardware ECC Scrub - /proc interface for Intel Clanton platform"
++ depends on INTEL_QUARK_X1000_SOC
++ help
++ Say Y here to enable support for accessing the hardware memory
++ ECC Scrubber via the /proc interface.
++
++config INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG
++ bool "Hardware ECC Scrub - use config settings to override scrub vals"
++ depends on INTEL_CLN_ECC_SCRUB
++ help
++ Say Y here to enable support to use config settings to override
++ BIOS configured scrub values
++
++config INTEL_CLN_HW_ECC_REFRESH_RATE
++ int "Choose DRAM ECC refresh rate"
++ depends on INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG
++ default 20
++ help
++ Range 0 - 255 mSec
++
++config INTEL_CLN_HW_ECC_REFRESH_SIZE
++ int "Choose DRAM ECC refresh size"
++ depends on INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG
++ default 512
++ help
++ Range 64-512 bytes, multiples of 32
++
++config INTEL_CLN_ECC_SCRUB_S3_CONFIG
++ bool "Hardware ECC Scrub - linux manages S3 entry/resume for scrub"
++ depends on INTEL_CLN_ECC_SCRUB
++ help
++ Say Y here to enable linux to manage S3 entry/resume for the
++ hardware memory ECC Scrubber.
++
++config INTEL_CLN_THERMAL
++ bool "Thermal driver for Intel Clanton platform"
++ depends on INTEL_QUARK_X1000_SOC
++ help
++ Say Y here to enable Clanton's Thermal driver plus the MSI's
++ that can be hooked from the thermal sub-system
++
++config INTEL_CLN_AUDIO_CTRL
++ tristate "Audio sub-system control driver for Intel Clanton platform"
++ depends on INTEL_QUARK_X1000_SOC
++ help
++ Say Y here to enable Clanton's audio control driver
+diff --git a/drivers/platform/x86/quark/Makefile b/drivers/platform/x86/quark/Makefile
+new file mode 100644
+index 0000000..00c4ce7
+--- /dev/null
++++ b/drivers/platform/x86/quark/Makefile
+@@ -0,0 +1,18 @@
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_board_data.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_layout_data.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_data.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_clanton_hill.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_clanton_peak.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_cross_hill.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_kips_bay.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_plat_galileo.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_sb.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr_kernel.o
++obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_esram.o
++obj-$(CONFIG_INTEL_QUARK_X1000_SOC) += intel_cln_imr_test.o
++obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_esram_test.o
++#obj-$(CONFIG_INTEL_CLN_ESRAM) += intel_cln_smep_test.o
++obj-$(CONFIG_INTEL_CLN_ECC_SCRUB) += intel_cln_ecc_scrub.o
++obj-$(CONFIG_INTEL_CLN_THERMAL) += intel_cln_thermal.o
++obj-$(CONFIG_INTEL_CLN_AUDIO_CTRL) += intel_cln_audio_ctrl.o
+diff --git a/drivers/platform/x86/quark/intel_cln_audio_ctrl.c b/drivers/platform/x86/quark/intel_cln_audio_ctrl.c
+new file mode 100644
+index 0000000..95bfe78
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_audio_ctrl.c
+@@ -0,0 +1,514 @@
++/*
++ * Intel Clanton platform audio control driver
++ *
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * The Intel Clanton Hill platform hardware design includes an audio subsystem
++ * with a number of interconnected audio interfaces. This driver enables
++ * applications to choose which audio connections to enable for various
++ * application use cases. The interconnections are selectable using GPIO output
++ * pins on the CPU. This driver is also responsible for configuring a Maxim
++ * 9867 audio codec, a component of this audio subsystem, connected to the CPU
++ * via I2C.
++ */
++
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/types.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/gpio.h>
++#include <linux/cdev.h>
++#include <linux/fs.h>
++#include <uapi/linux/ioctl.h>
++#include <linux/mutex.h>
++#include <linux/sysfs.h>
++
++#include "intel_cln_audio_ctrl.h"
++
++#define DRIVER_NAME "intel_cln_audio_ctrl"
++
++/*
++ * GPIO numbers to use for switching audio paths
++ */
++#define GPIO_AUDIO_S0 11
++#define GPIO_AUDIO_S1 12
++#define GPIO_AUDIO_S2 13
++
++#define GPIO_AUDIO_DEFAULT (INTEL_CLN_AUDIO_MODE_SPKR_MIC)
++
++/**
++ * struct intel_cln_audio_ctrl_data
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_cln_audio_ctrl_priv {
++
++ /* i2c device descriptor for read/write access to MAX9867 registers */
++ struct i2c_client *max9867_i2c;
++
++ /* Char dev to provide user-space ioctl interface for audio control */
++ struct cdev cdev;
++ dev_t cdev_no;
++ struct class *cl;
++
++ /* Mutex to protect against concurrent access to the ioctl() handler */
++ struct mutex lock;
++
++ /* Current GPIO switch value */
++ unsigned char gpio_val;
++};
++
++static int
++intel_cln_audio_ctrl_open(struct inode *inode, struct file *filp)
++{
++ struct intel_cln_audio_ctrl_priv *priv;
++
++ priv = container_of(inode->i_cdev,
++ struct intel_cln_audio_ctrl_priv,
++ cdev);
++ filp->private_data = priv;
++
++ return 0;
++}
++
++static int
++intel_cln_audio_ctrl_release(struct inode *inode, struct file *filp)
++{
++ return 0;
++}
++
++/*
++ * Logic truth table for AUDIO_S[0-3] outputs, illustrating which paths are
++ * connected between audio interfaces A, B, C. Each audio interface has one
++ * effective input (I) port and one effective output (O) port
++ *
++ * A = USB Codec (to Clanton CPU)
++ * B = Spkr/Mic (to car audio system)
++ * C = I2S Codec (to Telit HE910)
++ *
++ * PATH examples:
++ * AO-CO: A-Output connected to C-Output
++ * BI-AI: B-Input connected to A-Input
++ *
++ * NOTE: Assume a CI-AI connection is available in ALL cases (sometimes unused)
++ *
++ * S2 S1 S0 PATHS USE CASE
++ * -- -- -- ----------------- -------------------------------------------------
++ * 0 0 0 AO-CO BT Headset call
++ * 0 0 1 AO-BO Analog Driver Alerts (CI unused)
++ * 0 1 0 AO-CO,BI-AI XX Unused/invalid (BI *and* CI connected to AI)
++ * 0 1 1 AO-BO,BI-AI Archival Voice Record/Playback (or Driver Alerts)
++ * 1 0 0 AO-CO,BI-CO XX Unused/invalid (A0 *and* BI connected to CO)
++ * 1 0 1 AO-BO,BI-CO Analog hands-free call
++ * 1 1 0 AO-CO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
++ * 1 1 1 AO-BO,BI-AI,BI-CO XX Unused/invalid (BI connected to AI *and* CO)
++ *
++ *
++ * Mapping to IOCTLs (using more intuitive naming on the API):
++ *
++ * PATHS IOCTL
++ * --------------- -------------------------------------------------------------
++ * AO-CO INTEL_CLN_AUDIO_MODE_GSM_ONLY
++ * AO-BO INTEL_CLN_AUDIO_MODE_SPKR_ONLY
++ * AO-BO,BI-AI INTEL_CLN_AUDIO_MODE_SPKR_MIC
++ * AO-BO,BI-CO INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC
++ */
++
++static int
++intel_cln_audio_ctrl_gpio_update(struct intel_cln_audio_ctrl_priv *priv)
++{
++ int ret = 0;
++ struct gpio audio_sw_gpios[] = {
++ {
++ GPIO_AUDIO_S2,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s2"
++ },
++ {
++ GPIO_AUDIO_S1,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s1"
++ },
++ {
++ GPIO_AUDIO_S0,
++ GPIOF_OUT_INIT_LOW,
++ "audio_s0"
++ }
++ };
++
++ /*
++ * Update the Audio Switch GPIO outputs according to the user selection
++ */
++ ret = gpio_request_array(audio_sw_gpios,
++ ARRAY_SIZE(audio_sw_gpios));
++ if (ret) {
++ pr_err("%s: Failed to allocate audio control GPIO pins\n",
++ __func__);
++ return ret;
++ }
++
++ gpio_set_value(GPIO_AUDIO_S2, (priv->gpio_val >> 2) & 0x1);
++ gpio_set_value(GPIO_AUDIO_S1, (priv->gpio_val >> 1) & 0x1);
++ gpio_set_value(GPIO_AUDIO_S0, (priv->gpio_val >> 0) & 0x1);
++
++ gpio_free_array(audio_sw_gpios,
++ ARRAY_SIZE(audio_sw_gpios));
++
++ return 0;
++}
++
++static long
++intel_cln_audio_ctrl_ioctl(struct file *filp,
++ unsigned int cmd,
++ unsigned long arg)
++{
++ struct intel_cln_audio_ctrl_priv *priv = filp->private_data;
++ int ret = 0;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ switch (cmd) {
++ case INTEL_CLN_AUDIO_MODE_IOC_GSM_ONLY:
++ case INTEL_CLN_AUDIO_MODE_IOC_SPKR_ONLY:
++ case INTEL_CLN_AUDIO_MODE_IOC_SPKR_MIC:
++ case INTEL_CLN_AUDIO_MODE_IOC_GSM_SPKR_MIC:
++ break;
++ default:
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ priv->gpio_val = _IOC_NR(cmd) & 0x7;
++ ret = intel_cln_audio_ctrl_gpio_update(priv);
++exit:
++ mutex_unlock(&priv->lock);
++ return ret;
++}
++
++static const struct file_operations intel_cln_audio_ctrl_fops = {
++ .owner = THIS_MODULE,
++ .open = intel_cln_audio_ctrl_open,
++ .release = intel_cln_audio_ctrl_release,
++ .unlocked_ioctl = intel_cln_audio_ctrl_ioctl
++};
++
++static int
++intel_cln_audio_ctrl_chrdev_init(struct intel_cln_audio_ctrl_priv *priv)
++{
++ /* Register a character dev interface (with ioctls)
++ * to allow control of the audio subsystem switch
++ */
++ int ret;
++ struct device *dev;
++
++ ret = alloc_chrdev_region(&priv->cdev_no, 0, 1,
++ "intel_cln_audio_ctrl");
++ if (ret) {
++ pr_err("Failed to alloc chrdev: %d", ret);
++ return ret;
++ }
++
++ cdev_init(&priv->cdev, &intel_cln_audio_ctrl_fops);
++
++ ret = cdev_add(&priv->cdev, priv->cdev_no, 1);
++ if (ret) {
++ pr_err("Failed to add cdev: %d", ret);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return ret;
++ }
++
++ priv->cl = class_create(THIS_MODULE, "char");
++ if (IS_ERR(priv->cl)) {
++ pr_err("Failed to create device class: %ld",
++ PTR_ERR(priv->cl));
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return PTR_ERR(priv->cl);
++ }
++
++ dev = device_create(priv->cl, NULL, priv->cdev_no, NULL,
++ "intel_cln_audio_ctrl");
++ if (IS_ERR(dev)) {
++ pr_err("Failed to create device: %ld",
++ PTR_ERR(priv->cl));
++ class_destroy(priv->cl);
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++ return PTR_ERR(dev);
++ }
++
++ return 0;
++}
++
++static int
++intel_cln_audio_ctrl_chrdev_remove(struct intel_cln_audio_ctrl_priv *priv)
++{
++ device_destroy(priv->cl, priv->cdev_no);
++ class_destroy(priv->cl);
++ cdev_del(&priv->cdev);
++ unregister_chrdev_region(priv->cdev_no, 1);
++
++ return 0;
++}
++
++
++ssize_t intel_cln_audio_ctrl_sysfs_show_mode(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct intel_cln_audio_ctrl_priv *priv = dev_get_drvdata(dev);
++ int ret;
++ char *mode;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ switch (priv->gpio_val) {
++ case INTEL_CLN_AUDIO_MODE_GSM_ONLY:
++ mode = "gsm";
++ break;
++ case INTEL_CLN_AUDIO_MODE_SPKR_ONLY:
++ mode = "spkr";
++ break;
++ case INTEL_CLN_AUDIO_MODE_SPKR_MIC:
++ mode = "spkr_mic";
++ break;
++ case INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC:
++ mode = "gsm_spkr_mic";
++ break;
++ default:
++ ret = -EINVAL;
++ goto exit;
++ }
++
++ ret = scnprintf(buf, PAGE_SIZE, "%s\n", mode);
++
++exit:
++ mutex_unlock(&priv->lock);
++ return ret;
++}
++
++ssize_t intel_cln_audio_ctrl_sysfs_store_mode(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct intel_cln_audio_ctrl_priv *priv = dev_get_drvdata(dev);
++ char mode[16];
++ unsigned char gpio_val;
++ int ret = count;
++
++ sscanf(buf, "%15s", mode);
++
++ if (!strcmp(mode, "gsm"))
++ gpio_val = INTEL_CLN_AUDIO_MODE_GSM_ONLY;
++ else if (!strcmp(mode, "spkr"))
++ gpio_val = INTEL_CLN_AUDIO_MODE_SPKR_ONLY;
++ else if (!strcmp(mode, "spkr_mic"))
++ gpio_val = INTEL_CLN_AUDIO_MODE_SPKR_MIC;
++ else if (!strcmp(mode, "gsm_spkr_mic"))
++ gpio_val = INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC;
++ else
++ return -EINVAL;
++
++ ret = mutex_lock_interruptible(&priv->lock);
++ if (ret)
++ return ret;
++
++ priv->gpio_val = gpio_val;
++ ret = intel_cln_audio_ctrl_gpio_update(priv);
++ if (ret)
++ goto exit;
++
++ ret = count;
++
++exit:
++ mutex_unlock(&priv->lock);
++
++ return ret;
++}
++
++/* Sysfs attribute descriptor (for alternative user-space interface) */
++static DEVICE_ATTR(audio_switch_mode, S_IWUSR | S_IRUGO,
++ intel_cln_audio_ctrl_sysfs_show_mode,
++ intel_cln_audio_ctrl_sysfs_store_mode);
++
++/******************************************************************************
++ * Module hooks
++ ******************************************************************************/
++
++static int
++intel_cln_max9867_init(struct i2c_client *client)
++{
++ int ret;
++
++ /* MAX9867 register configuration, from Telit HE910 DVI app-note */
++
++ u8 reg_cfg_seq1[] = {
++ 0x04, /* Starting register address, followed by data */
++ 0x00, /* 0x04 Interrupt Enable */
++ 0x10, /* 0x05 System Clock */
++ 0x90, /* 0x06 Audio Clock High */
++ 0x00, /* 0x07 Audio Clock Low */
++ 0x10, /* 0x08 Interface 1a */
++ 0x0A, /* 0x09 Interface 1d */
++ 0x33, /* 0x0A Codec Filters */
++ 0x00, /* 0x0B DAC Gain/Sidetone */
++ 0x00, /* 0x0C DAC Level */
++ 0x33, /* 0x0D ADC Level */
++ 0x4C, /* 0x0E Left Line Input Level */
++ 0x4C, /* 0x0F Right Line Input Level */
++ 0x00, /* 0x10 Left Volume Control */
++ 0x00, /* 0x11 Right Volume Control */
++ 0x14, /* 0x12 Left Mic Gain */
++ 0x14, /* 0x13 Right Mic Gain */
++ /* Configuration */
++ 0xA0, /* 0x14 Input */
++ 0x00, /* 0x15 Microphone */
++ 0x65 /* 0x16 Mode */
++ };
++
++ u8 reg_cfg_seq2[] = {
++ 0x17, /* Starting register address, followed by data */
++ 0xEF /* 0x17 System Shutdown */
++ };
++
++ ret = i2c_master_send(client,
++ reg_cfg_seq1, sizeof(reg_cfg_seq1));
++ if (ret != sizeof(reg_cfg_seq1)) {
++ pr_err("Failed to write MAX9867 config registers (set 1/2)");
++ return -EIO;
++ }
++
++ ret = i2c_master_send(client,
++ reg_cfg_seq2, sizeof(reg_cfg_seq2));
++ if (ret != sizeof(reg_cfg_seq2)) {
++ pr_err("Failed to write MAX9867 config registers (set 2/2)");
++ return -EIO;
++ }
++
++ return 0;
++}
++
++static int
++intel_cln_max9867_get_chip_rev(struct i2c_client *client)
++{
++ struct i2c_msg msg[2];
++ u8 data[2];
++ int ret;
++
++ data[0] = 0xFF; /* Chip-revision register address = 0xFF */
++ msg[0].addr = client->addr;
++ msg[0].flags = 0;
++ msg[0].buf = &data[0];
++ msg[0].len = 1;
++
++ msg[1].addr = client->addr;
++ msg[1].flags = I2C_M_RD;
++ msg[1].buf = &data[1];
++ msg[1].len = 1;
++
++ ret = i2c_transfer(client->adapter, &msg[0], 2);
++ return (ret == 2) ? data[1] : -EIO;
++}
++
++static int intel_cln_max9867_i2c_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct intel_cln_audio_ctrl_priv *priv;
++ int ret;
++
++ priv = devm_kzalloc(&client->dev, sizeof(*priv),
++ GFP_KERNEL);
++ if (priv == NULL)
++ return -ENOMEM;
++
++ i2c_set_clientdata(client, priv);
++
++ priv->max9867_i2c = client;
++ mutex_init(&priv->lock);
++
++ ret = intel_cln_max9867_get_chip_rev(client);
++ if (ret >= 0)
++ pr_info("%s: Detected MAX9867 chip revision 0x%02X\n",
++ __func__, ret);
++ else {
++ pr_err("%s: Failed to read MAX9867 chip revision\n", __func__);
++ goto exit;
++ }
++
++ ret = intel_cln_max9867_init(client);
++ if (ret)
++ goto exit;
++
++ priv->gpio_val = GPIO_AUDIO_DEFAULT;
++ ret = intel_cln_audio_ctrl_gpio_update(priv);
++ if (ret)
++ goto exit;
++
++ /* Create a char dev interface, providing an ioctl config option */
++ ret = intel_cln_audio_ctrl_chrdev_init(priv);
++ if (ret)
++ goto exit;
++
++ /* Also create a sysfs interface, providing a cmd line config option */
++ ret = sysfs_create_file(&client->dev.kobj,
++ &dev_attr_audio_switch_mode.attr);
++
++exit:
++ return ret;
++}
++
++static int intel_cln_max9867_i2c_remove(struct i2c_client *client)
++{
++ struct intel_cln_audio_ctrl_priv *priv = i2c_get_clientdata(client);
++
++ intel_cln_audio_ctrl_chrdev_remove(priv);
++
++ sysfs_remove_file(&client->dev.kobj, &dev_attr_audio_switch_mode.attr);
++
++ return 0;
++}
++
++static const struct i2c_device_id intel_cln_max9867_i2c_id[] = {
++ {"intel-cln-max9867", 0},
++ {}
++};
++MODULE_DEVICE_TABLE(i2c, intel_cln_max9867_i2c_id);
++
++/* i2c codec control layer */
++static struct i2c_driver intel_cln_audio_ctrl_i2c_driver = {
++ .driver = {
++ .name = "intel_cln_audio_ctrl",
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_max9867_i2c_probe,
++ .remove = intel_cln_max9867_i2c_remove,
++ .id_table = intel_cln_max9867_i2c_id,
++};
++
++module_i2c_driver(intel_cln_audio_ctrl_i2c_driver);
++
++MODULE_AUTHOR("Dan O'Donovan <dan@emutex.com>");
++MODULE_DESCRIPTION("Intel Clanton platform audio control driver");
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/platform/x86/quark/intel_cln_audio_ctrl.h b/drivers/platform/x86/quark/intel_cln_audio_ctrl.h
+new file mode 100644
+index 0000000..b6c4692
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_audio_ctrl.h
+@@ -0,0 +1,45 @@
++/*
++ * Intel Clanton platform audio control driver
++ *
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ *
++ * See intel_cln_audio_ctrl.c for a detailed description
++ *
++ */
++
++#ifndef __INTEL_CLN_AUDIO_CTRL_H__
++#define __INTEL_CLN_AUDIO_CTRL_H__
++
++#include <linux/module.h>
++
++#define INTEL_CLN_AUDIO_MODE_GSM_ONLY 0x0
++#define INTEL_CLN_AUDIO_MODE_SPKR_ONLY 0x1
++#define INTEL_CLN_AUDIO_MODE_SPKR_MIC 0x3
++#define INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC 0x5
++
++#define INTEL_CLN_AUDIO_MODE_IOC_GSM_ONLY \
++ _IO('x', INTEL_CLN_AUDIO_MODE_GSM_ONLY)
++#define INTEL_CLN_AUDIO_MODE_IOC_SPKR_ONLY \
++ _IO('x', INTEL_CLN_AUDIO_MODE_SPKR_ONLY)
++#define INTEL_CLN_AUDIO_MODE_IOC_SPKR_MIC \
++ _IO('x', INTEL_CLN_AUDIO_MODE_SPKR_MIC)
++#define INTEL_CLN_AUDIO_MODE_IOC_GSM_SPKR_MIC \
++ _IO('x', INTEL_CLN_AUDIO_MODE_GSM_SPKR_MIC)
++
++#endif /* __INTEL_CLN_AUDIO_CTRL_H__ */
+diff --git a/drivers/platform/x86/quark/intel_cln_board_data.c b/drivers/platform/x86/quark/intel_cln_board_data.c
+new file mode 100644
+index 0000000..da226c7
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_board_data.c
+@@ -0,0 +1,207 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data accessor layer
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <asm/io.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++
++#define DRIVER_NAME "board_data"
++#define PFX "MFH: "
++#define SPIFLASH_BASEADDR 0xFFF00000
++#define MFH_OFFSET 0x00008000
++#define PLATFORM_DATA_OFFSET 0x00010000
++#define MTD_PART_OFFSET 0x00050000
++#define MTD_PART_LEN 0x00040000
++#define MFH_PADDING 0x1E8
++#define MFH_MAGIC 0x5F4D4648
++#define FLASH_SIZE 0x00400000
++
++/* MFH types supported @ version #1 */
++#define MFH_ITEM_FW_STAGE1 0x00000000
++#define MFH_ITEM_FW_STAGE1_SIGNED 0x00000001
++#define MFH_ITEM_FW_STAGE2 0x00000003
++#define MFH_ITEM_FW_STAGE2_SIGNED 0x00000004
++#define MFH_ITEM_FW_STAGE2_CONFIG 0x00000005
++#define MFH_ITEM_FW_STAGE2_CONFIG_SIGNED 0x00000006
++#define MFH_ITEM_FW_PARAMS 0x00000007
++#define MFH_ITEM_FW_RECOVERY 0x00000008
++#define MFH_ITEM_FW_RECOVERY_SIGNED 0x00000009
++#define MFH_ITEM_BOOTLOADER 0x0000000B
++#define MFH_ITEM_BOOTLOADER_SIGNED 0x0000000C
++#define MFH_ITEM_BOOTLOADER_CONFIG 0x0000000D
++#define MFH_ITEM_BOOTLOADER_CONFIG_SIGNED 0x0000000E
++#define MFH_ITEM_KERNEL 0x00000010
++#define MFH_ITEM_KERNEL_SIGNED 0x00000011
++#define MFH_ITEM_RAMDISK 0x00000012
++#define MFH_ITEM_RAMDISK_SIGNED 0x00000013
++#define MFH_ITEM_LOADABLE_PROGRAM 0x00000015
++#define MFH_ITEM_LOADABLE_PROGRAM_SIGNED 0x00000016
++#define MFH_ITEM_BUILD_INFO 0x00000018
++#define MFH_ITEM_VERSION 0x00000019
++
++struct intel_cln_mfh {
++ u32 id;
++ u32 ver;
++ u32 flags;
++ u32 next_block;
++ u32 item_count;
++ u32 boot_priority_list;
++ u8 padding[MFH_PADDING];
++};
++
++struct intel_cln_mfh_item {
++ u32 type;
++ u32 addr;
++ u32 len;
++ u32 res0;
++};
++
++static struct resource conf_res __initdata = {
++ .flags = IORESOURCE_MEM,
++ .start = 0,
++ .end = 0,
++};
++
++static struct resource plat_res __initdata = {
++ .flags = IORESOURCE_MEM,
++ .start = 0,
++ .end = 0,
++};
++
++static struct platform_device conf_pdev = {
++ .name = "cln-layout-conf",
++ .id = -1,
++ .resource = &conf_res,
++};
++
++struct kobject * board_data_kobj;
++EXPORT_SYMBOL_GPL(board_data_kobj);
++
++static bool mfh_plat_found = false;
++
++static long unsigned int flash_version_data;
++static ssize_t flash_version_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ return snprintf(buf, 12, "%#010lx\n", flash_version_data);
++}
++
++static struct kobj_attribute flash_version_attr =
++ __ATTR(flash_version, 0644, flash_version_show, NULL);
++
++extern int intel_cln_plat_probe(struct resource * pres);
++
++/**
++ * intel_cln_board_data_init
++ *
++ * Module entry point
++ */
++static int __init intel_cln_board_data_init(void)
++{
++ extern struct kobject * firmware_kobj;
++ struct intel_cln_mfh __iomem * mfh;
++ struct intel_cln_mfh_item __iomem * item;
++ struct platform_device * pdev;
++ u32 count;
++ void __iomem * spi_data;
++ int ret = 0;
++
++ spi_data = ioremap(SPIFLASH_BASEADDR, FLASH_SIZE);
++ if (!spi_data)
++ return -ENODEV;
++
++ /* get mfh and first item pointer */
++ mfh = spi_data + MFH_OFFSET;
++ if (mfh->id != MFH_MAGIC){
++ pr_err(PFX"Bad MFH magic want 0x%08x found 0x%08x @ 0x%p\n",
++ MFH_MAGIC, mfh->id, &mfh->id);
++ return -ENODEV;
++ }
++
++ pr_info(PFX"mfh @ 0x%p: id 0x%08lx ver 0x%08lx entries 0x%08lx\n",
++ mfh, (unsigned long)mfh->id, (unsigned long)mfh->ver,
++ (unsigned long)mfh->item_count);
++ item = (struct intel_cln_mfh_item __iomem *)
++ &mfh->padding [sizeof(u32) * mfh->boot_priority_list];
++
++ /* board_data_kobj subordinate of firmware @ /sys/firmware/board_data */
++ board_data_kobj = kobject_create_and_add("board_data", firmware_kobj);
++ if (!board_data_kobj) {
++ pr_err(PFX"kset create error\n");
++ return -ENODEV;
++ }
++
++ /* Register flash regions as seperate platform devices */
++ for (count = 0; count < mfh->item_count; count++, item++){
++ pdev = NULL;
++
++ switch (item->type){
++ case MFH_ITEM_BUILD_INFO:
++ conf_res.start = item->addr;
++ conf_res.end = item->addr + item->len;
++ pdev = &conf_pdev;
++ break;
++ case MFH_ITEM_VERSION:
++ flash_version_data = item->res0;
++ if(sysfs_create_file(board_data_kobj,
++ &flash_version_attr.attr)) {
++ pr_err("failed to create sysfs entry for flash version\n");
++ flash_version_data = 0;
++ }
++ break;
++ default:
++ break;
++ }
++
++ if (pdev != NULL)
++ platform_device_register(pdev);
++ }
++
++ /* This ought to be encoded in the MFH ! */
++ if (mfh_plat_found == false){
++ pr_err(PFX"Warning platform data MFH missing - using hardcoded "
++ "offsets\n");
++
++ /* Platform data */
++ plat_res.start = SPIFLASH_BASEADDR + PLATFORM_DATA_OFFSET;
++ count = *(uint32_t*)(spi_data + PLATFORM_DATA_OFFSET + sizeof(uint32_t));
++ plat_res.end = count;
++ ret = intel_cln_plat_probe(&plat_res);
++ }
++
++ iounmap(spi_data);
++ return ret;
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Intel Clanton SPI Data API");
++MODULE_LICENSE("Dual BSD/GPL");
++subsys_initcall(intel_cln_board_data_init);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_ecc_scrub.c b/drivers/platform/x86/quark/intel_cln_ecc_scrub.c
+new file mode 100644
+index 0000000..1fb46f6
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_ecc_scrub.c
+@@ -0,0 +1,668 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton DRAM ECC Scrub driver
++ *
++ * !!!!!!! Description
++ *
++ */
++#include <asm-generic/uaccess.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/proc_fs.h>
++
++#define DRIVER_NAME "intel-cln-ecc"
++#define INTEL_CLN_ECC_SCRUB_PROCDIR "driver/ecc_scrub"
++#define STATUS "status"
++#define CONTROL "control"
++#define INTERVAL "interval"
++#define ECC_BLOCK_SIZE "block_size"
++
++#define CONTROL_USAGE "ECC Scrub Control: invalid setting. "\
++ "Valid values are 1 or 0\n"
++#define CONTROL_SCRUB_ON_STR "1\n"
++#define CONTROL_SCRUB_OFF_STR "0\n"
++#define CONTROL_ON_STR "on\n"
++#define CONTROL_OFF_STR "off\n"
++
++#define INTERVAL_USAGE "ECC Scrub Interval: invalid setting. "\
++ "Valid range is 1 - 255\n"
++#define SIZE_USAGE "ECC Scrub Block Size: invalid setting. "\
++ "Valid range is 64 - 512\n"
++
++#define OVERRIDE_CONFIG_PARM_DESC "Clanton ECC Scrub - "\
++ "Override BIOS settings "\
++ "for Scrub Config"
++
++#define OVERRIDE_START_PARM_DESC "Clanton ECC Scrub - "\
++ "Override BIOS settings "\
++ "for Scrub Start address"
++
++#define OVERRIDE_END_PARM_DESC "Clanton ECC Scrub - "\
++ "Override BIOS settings "\
++ "for Scrub End address"
++
++#define OVERRIDE_NEXT_PARM_DESC "Clanton ECC Scrub - "\
++ "Override BIOS settings "\
++ "for Scrub Next address"
++
++#define MAX_SCRUB_BLOCK_SIZE 512
++#define MIN_SCRUB_BLOCK_SIZE 64
++#define MAX_SCRUB_REFRESH 255
++#define MIN_SCRUB_REFRESH 0
++
++#define NOT_OVERRIDDEN 0xfffffffful
++
++/* Shorten fn names to fit 80 char limit */
++#ifndef sb_read
++#define sb_read intel_cln_sb_read_reg
++#endif
++#ifndef sb_write
++#define sb_write intel_cln_sb_write_reg
++#endif
++
++/* Register ID */
++#define ECC_SCRUB_CONFIG_REG (0x50)
++#define ECC_SCRUB_START_MEM_REG (0x76)
++#define ECC_SCRUB_END_MEM_REG (0x77)
++#define ECC_SCRUB_NEXT_READ_REG (0x7C)
++
++
++/* Reg commands */
++#define THERMAL_CTRL_READ (0x10)
++#define THERMAL_CTRL_WRITE (0x11)
++#define THERMAL_RESUME_SCRUB (0xC2)
++#define THERMAL_PAUSE_SCRUB (0xC3)
++
++/**
++ * struct intel_cln_ecc_scrub_dev
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_cln_ecc_scrub_dev {
++
++ /* Linux kernel structures */
++ struct platform_device *pldev; /* Platform device */
++
++ /* Register copies */
++ u32 start_address;
++ u32 end_address;
++ u32 next_address;
++ u32 config;
++
++};
++
++static struct intel_cln_ecc_scrub_dev ecc_scrub_dev;
++
++static u32 ecc_scrub_config_override = NOT_OVERRIDDEN;
++static u32 ecc_scrub_start_override = NOT_OVERRIDDEN;
++static u32 ecc_scrub_end_override = NOT_OVERRIDDEN;
++static u32 ecc_scrub_next_override = NOT_OVERRIDDEN;
++
++/**
++ * intel_cln_ecc_scrub_stat_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates ecc_scrub state via /sys/device/platform/intel-cln-ecc/status
++ */
++static ssize_t
++intel_cln_ecc_scrub_stat_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ int len = 0, size = 0;
++ unsigned int count = PAGE_SIZE;
++ u32 reg_data = 0;
++ char *scrub_status = CONTROL_OFF_STR;
++
++ /* Display start of memory address */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_START_MEM_REG,
++ &reg_data, 1);
++ len += snprintf(buf + len, count - len,
++ "ecc scrub mem start\t\t\t: 0x%08x\n", reg_data);
++
++
++ /* Display end of memory address */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_END_MEM_REG,
++ &reg_data, 1);
++ len += snprintf(buf + len, count - len,
++ "ecc scrub mem end\t\t\t: 0x%08x\n", reg_data);
++
++ /* Display next address to be read */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_NEXT_READ_REG,
++ &reg_data, 1);
++ len += snprintf(buf + len, count - len,
++ "ecc scrub next read\t\t\t: 0x%08x\n", reg_data);
++
++ /* Display config settings */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++
++ /* Interval is the lsbyte of the config reg, so mask out just
++ * that byte in the data printed. */
++ len += snprintf(buf + len, count - len,
++ "ecc scrub interval\t\t\t: %d\n",
++ (reg_data & 0x000000ff));
++
++ /* Size is indicated in bits 12:8 of register in
++ * terms of 32 byte blocks. */
++ size = ((reg_data & 0x00001f00) >> 8)*32;
++ len += snprintf(buf + len, count - len,
++ "ecc scrub block_size\t\t\t: %d\n", size);
++
++ /* Status is indicated in bit 13 of register. */
++ if ((reg_data & 0x00002000) > 0)
++ scrub_status = CONTROL_ON_STR;
++
++ len += snprintf(buf + len, count - len,
++ "ecc scrub status\t\t\t: %s\n", scrub_status);
++ return len;
++}
++
++/**
++ * intel_cln_ecc_scrub_ctrl_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates ecc_scrub state via /sys/device/platform/intel-cln-ecc/control
++ */
++static ssize_t
++intel_cln_ecc_scrub_ctrl_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ unsigned int count = PAGE_SIZE;
++ u32 reg_data = 0;
++ char *on_or_off = CONTROL_SCRUB_OFF_STR;
++
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++
++ /* Status is indicated in bit 13 of register. */
++ if ((reg_data & 0x00002000) > 0)
++ /* interval > 0 assume scrubbing on */
++ on_or_off = CONTROL_SCRUB_ON_STR;
++
++ return snprintf(buf, count,"%s", on_or_off);
++}
++
++/**
++ * intel_cln_ecc_scrub_ctrl_store
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: input buffer
++ * @param size: size of input data
++ * @return number of bytes successfully written
++ *
++ * Function allows user-space to switch on/off scrubbing with a simple
++ * echo 1/0 > /sys/device/platform/intel-cln-ecc/control command
++ */
++static ssize_t
++intel_cln_ecc_scrub_ctrl_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ ssize_t ret = 0;
++
++ if (count <= 1)
++ return -EINVAL;
++
++ ret = -EINVAL;
++
++ /* Check for command starting with "scrub"
++ * and ending with "on" or "off" */
++
++ if (!strcmp(buf, CONTROL_SCRUB_ON_STR)) {
++ sb_write(SB_ID_THERMAL, THERMAL_RESUME_SCRUB,
++ 0, 0, 1);
++ ret = 0;
++ } else if (!strcmp(buf, CONTROL_SCRUB_OFF_STR)) {
++ sb_write(SB_ID_THERMAL, THERMAL_PAUSE_SCRUB, 0,
++ 0, 1);
++ ret = 0;
++ }
++
++
++ if (ret == 0)
++ ret = (ssize_t)count;
++
++ else if (ret == -EINVAL)
++ printk(CONTROL_USAGE);
++
++ return ret;
++}
++
++/**
++ * intel_cln_ecc_scrub_intrvl_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates ecc_scrub state via /sys/device/platform/intel-cln-ecc/interval
++ */
++static ssize_t
++intel_cln_ecc_scrub_intrvl_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ u32 reg_data = 0;
++
++ /* Interval is the lsbyte of the config reg,
++ * so mask out just that byte in the data printed. */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", (reg_data & 0x000000ff));
++}
++
++/**
++ * intel_cln_ecc_scrub_intrvl_store
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: input buffer
++ * @param size: size of input data
++ * @return number of bytes successfully written
++ *
++ * Function allows user-space to set scrub interval with a value of 1-255
++ * echo 1-255 > /sys/device/platform/intel-cln-ecc/interval type command
++ */
++static ssize_t
++intel_cln_ecc_scrub_intrvl_store(struct device *dev,
++ struct device_attribute *attr, const char *buf,
++ size_t count)
++{
++ ssize_t ret = 0;
++ unsigned long val = 0;
++ u32 reg_data = 0;
++ int ret_temp = 0;
++
++ if (count <= 1)
++ return -EINVAL;
++
++ ret = -EINVAL;
++
++ ret_temp = kstrtoul(buf, 10, &val);
++
++ if (ret_temp)
++ return ret_temp;
++
++ if (val > MIN_SCRUB_REFRESH && val <= MAX_SCRUB_REFRESH) {
++ /* Need to read-modify-write config register. */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ,
++ ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++
++ reg_data &= 0xffffff00; /* clear lsb. */
++ reg_data |= val; /* now set interval. */
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_CONFIG_REG,
++ reg_data, 1);
++ ret = 0;
++ } else {
++ printk(INTERVAL_USAGE);
++ }
++
++ if (ret == 0)
++ ret = (ssize_t)count;
++ return ret;
++}
++
++/**
++ * intel_cln_ecc_scrub_size_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates ecc_scrub state via /sys/device/platform/intel-cln-ecc/block_size
++ */
++static ssize_t
++intel_cln_ecc_scrub_size_show(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ int size = 0;
++ u32 reg_data = 0;
++
++ /* Size is indicated in bits 12:8 of config register
++ * multiply x32 to get num bytes). */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++ size = ((reg_data & 0x00001f00) >> 8)*32;
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", size);
++}
++
++/**
++ * intel_cln_ecc_scrub_size_store
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: input buffer
++ * @param size: size of input data
++ * @return number of bytes successfully written
++ *
++ * Function allows user-space to set scrub block size of 64-512 with a simple
++ * echo 64-512 > /sys/device/platform/intel-cln-ecc/block_size command
++ */
++static ssize_t
++intel_cln_ecc_scrub_size_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ ssize_t ret = 0;
++ unsigned long val = 0;
++ u32 reg_data = 0;
++ int ret_temp = 0;
++
++ if (count <= 1)
++ return -EINVAL;
++
++ ret = -EINVAL;
++ ret_temp = kstrtoul(buf, 10, &val);
++
++ if (ret_temp)
++ return ret_temp;
++
++ if (val >= MIN_SCRUB_BLOCK_SIZE && val <= MAX_SCRUB_BLOCK_SIZE){
++
++ /* Need to read-modify-write config register. */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ,
++ ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++
++ reg_data &= 0xfffffe0ff; /* clear bits 12:8 */
++ reg_data |= (val/32)<<8; /* now set size */
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_CONFIG_REG, reg_data, 1);
++ ret = 0;
++ } else {
++ printk(SIZE_USAGE);
++ }
++
++ if (ret == 0)
++ ret = (ssize_t)count;
++
++ return ret;
++}
++
++static struct device_attribute dev_attr_status = {
++ .attr = {
++ .name = "status",
++ .mode = 0444,
++ },
++ .show = intel_cln_ecc_scrub_stat_show,
++};
++
++static struct device_attribute dev_attr_control = {
++ .attr = {
++ .name = "control",
++ .mode = 0644,
++ },
++ .show = intel_cln_ecc_scrub_ctrl_show,
++ .store = intel_cln_ecc_scrub_ctrl_store,
++};
++
++static struct device_attribute dev_attr_intrvl = {
++ .attr = {
++ .name = "interval",
++ .mode = 0644,
++ },
++ .show = intel_cln_ecc_scrub_intrvl_show,
++ .store = intel_cln_ecc_scrub_intrvl_store,
++};
++
++static struct device_attribute dev_attr_block_size = {
++ .attr = {
++ .name = "block_size",
++ .mode = 0644,
++ },
++ .show = intel_cln_ecc_scrub_size_show,
++ .store = intel_cln_ecc_scrub_size_store,
++};
++
++static struct attribute *platform_attributes[] = {
++ &dev_attr_status.attr,
++ &dev_attr_control.attr,
++ &dev_attr_intrvl.attr,
++ &dev_attr_block_size.attr,
++ NULL,
++};
++
++static struct attribute_group ecc_attrib_group = {
++ .attrs = platform_attributes
++};
++
++/*****************************************************************************
++ * Module/PowerManagement hooks
++ *****************************************************************************/
++/**
++ * intel_cln_ecc_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ */
++static int intel_cln_ecc_scrub_probe(struct platform_device *pdev)
++{
++ int value_overridden = 0;
++
++#ifdef CONFIG_INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG
++ u32 scrubber_refresh = 0;
++ u32 scrubber_block_size = 0;
++ u32 config_settings = 0;
++#endif
++
++ memset(&ecc_scrub_dev, 0x00, sizeof(ecc_scrub_dev));
++
++ /* Update config settings, if directed so to do */
++ if (ecc_scrub_start_override != NOT_OVERRIDDEN) {
++ /* start of memory address */
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_START_MEM_REG, ecc_scrub_start_override, 1);
++
++ value_overridden = 1;
++ }
++ if (ecc_scrub_end_override != NOT_OVERRIDDEN) {
++ /* end of memory address */
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_END_MEM_REG, ecc_scrub_end_override, 1);
++
++ value_overridden = 1;
++ }
++ if (ecc_scrub_next_override != NOT_OVERRIDDEN) {
++ /* next address to be read */
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_NEXT_READ_REG, ecc_scrub_next_override, 1);
++
++ value_overridden = 1;
++ }
++ if (ecc_scrub_config_override != NOT_OVERRIDDEN) {
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_CONFIG_REG, ecc_scrub_config_override, 1);
++
++ value_overridden = 1;
++ }
++
++ /* Config Reg can be updated by either command line or kconfig setting
++ * in the case where we have both the command line takes precedence.*/
++
++ else {
++#ifdef CONFIG_INTEL_CLN_ECC_SCRUB_OVERRIDE_CONFIG
++ scrubber_refresh = CONFIG_INTEL_CLN_HW_ECC_REFRESH_RATE;
++ scrubber_block_size = CONFIG_INTEL_CLN_HW_ECC_REFRESH_SIZE;
++
++ if (scrubber_block_size > MAX_SCRUB_BLOCK_SIZE)
++ scrubber_block_size = MAX_SCRUB_BLOCK_SIZE;
++
++ else if (scrubber_block_size < MIN_SCRUB_BLOCK_SIZE)
++ scrubber_block_size = MIN_SCRUB_BLOCK_SIZE;
++
++ if (scrubber_refresh > MAX_SCRUB_REFRESH)
++ scrubber_refresh = MAX_SCRUB_REFRESH;
++
++
++ /* adjust block size to multiples of 32 -
++ * as that is what the register setting actually expects. */
++ config_settings = scrubber_block_size/32;
++ config_settings <<= 8;
++ config_settings += scrubber_refresh;
++
++ /* config settings */
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE,
++ ECC_SCRUB_CONFIG_REG, config_settings, 1);
++
++ value_overridden = 1;
++#endif
++ }
++
++ if (value_overridden)
++ sb_write(SB_ID_THERMAL, THERMAL_RESUME_SCRUB, 0, 0, 1);
++
++ return sysfs_create_group(&pdev->dev.kobj, &ecc_attrib_group);
++}
++
++/**
++ * intel_cln_ecc_scrub_suspend
++ *
++ * @param pdev: Platform device structure (unused)
++ * @return 0 success < 0 failure
++ *
++ */
++static int intel_cln_ecc_scrub_suspend(struct device *pdev)
++{
++#ifdef CONFIG_INTEL_CLN_ECC_SCRUB_S3_CONFIG
++ u32 reg_data = 0;
++
++ /* Store off the 4 registers associated with scrubbing. */
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_START_MEM_REG,
++ &reg_data, 1);
++ ecc_scrub_dev.start_address = reg_data;
++
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_END_MEM_REG,
++ &reg_data, 1);
++ ecc_scrub_dev.end_address = reg_data;
++
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_NEXT_READ_REG,
++ &reg_data, 1);
++ ecc_scrub_dev.next_address = reg_data;
++
++ sb_read(SB_ID_THERMAL, THERMAL_CTRL_READ, ECC_SCRUB_CONFIG_REG,
++ &reg_data, 1);
++ ecc_scrub_dev.config = reg_data;
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_ecc_scrub_resume
++ *
++ * @param pdev: Platform device structure (unused)
++ * @return 0 success < 0 failure
++ */
++static int intel_cln_ecc_scrub_resume(struct device *pdev)
++{
++#ifdef CONFIG_INTEL_CLN_ECC_SCRUB_S3_CONFIG
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE, ECC_SCRUB_START_MEM_REG,
++ ecc_scrub_dev.start_address, 1);
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE, ECC_SCRUB_END_MEM_REG,
++ ecc_scrub_dev.end_address, 1);
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE, ECC_SCRUB_NEXT_READ_REG,
++ ecc_scrub_dev.next_address, 1);
++
++ sb_write(SB_ID_THERMAL, THERMAL_CTRL_WRITE, ECC_SCRUB_CONFIG_REG,
++ ecc_scrub_dev.config, 1);
++
++ sb_write(SB_ID_THERMAL, THERMAL_RESUME_SCRUB, 0, 0, 1);
++
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_ecc_scrub_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_cln_ecc_scrub_remove(struct platform_device *pdev)
++{
++ return sysfs_create_group(&pdev->dev.kobj, &ecc_attrib_group);
++}
++
++/*
++ * Power management operations
++ */
++static const struct dev_pm_ops intel_cln_ecc_scrub_pm_ops = {
++ .suspend = intel_cln_ecc_scrub_suspend,
++ .resume = intel_cln_ecc_scrub_resume,
++};
++
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_ecc_scrub_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &intel_cln_ecc_scrub_pm_ops,
++ },
++ .probe = intel_cln_ecc_scrub_probe,
++ .remove = intel_cln_ecc_scrub_remove,
++};
++
++
++MODULE_AUTHOR("Derek Harnett <derek.harnett@intel.com>");
++MODULE_DESCRIPTION("Intel Clanton DRAM ECC-scrub driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++module_param(ecc_scrub_config_override, uint, 0644);
++MODULE_PARM_DESC(ecc_scrub_config_override, OVERRIDE_CONFIG_PARM_DESC);
++
++module_param(ecc_scrub_start_override, uint, 0644);
++MODULE_PARM_DESC(ecc_scrub_start_override, OVERRIDE_START_PARM_DESC);
++
++module_param(ecc_scrub_end_override, uint, 0644);
++MODULE_PARM_DESC(ecc_scrub_end_override, OVERRIDE_END_PARM_DESC);
++
++module_param(ecc_scrub_next_override, uint, 0644);
++MODULE_PARM_DESC(ecc_scrub_next_override, OVERRIDE_NEXT_PARM_DESC);
++
++module_platform_driver(intel_cln_ecc_scrub_driver);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_esram.c b/drivers/platform/x86/quark/intel_cln_esram.c
+new file mode 100644
+index 0000000..76d2024
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_esram.c
+@@ -0,0 +1,1144 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton eSRAM overlay driver
++ *
++ * eSRAM is an on-chip fast access SRAM.
++ *
++ * This driver provides the ability to map a kallsyms derived symbol of
++ * arbitrary length or a struct page entitiy.
++ * A sysfs interface is provided to allow map of kernel structures, without
++ * having to use the API from your code directly.
++ *
++ * Example:
++ * echo idt_table > /sys/devices/intel-cln-esram.0/map
++ *
++ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
++ * eSRAM requires 4k physically aligned addresses to work - so a struct page
++ * fits neatly into this.
++ *
++ * intel_cln_esram_map_sym(ohci_irq);
++ * intel_cln_esram_map_page(virt_to_page(ohci_irq), "ohci_irq");
++ * Are equivalent - with the exception that map_sym() can detect if a mapping
++ * crosses a page-boundary, whereas map_page just maps one page. Generally use
++ * map_sym() for code and map_page() for data
++ *
++ * To populte eSRAM we must copy data to a temporary buffer, overlay and
++ * then copy data back to the eSRAM region.
++ *
++ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
++ * to S0 we must repopulate eSRAM
++ * Unmap code is included for reference however the cache coherency of unmap is
++ * not guaranteed so the functionality is not exported by this code
++ *
++ */
++#include <asm/cacheflush.h>
++#include <asm/desc.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/special_insns.h>
++#include <asm-generic/uaccess.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/kallsyms.h>
++#include <linux/list.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/seq_file.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/timer.h>
++
++#include "intel_cln_esram.h"
++
++#define DRIVER_NAME "intel-cln-esram"
++
++/* Shorten fn names to fit 80 char limit */
++#ifndef sb_read
++#define sb_read intel_cln_sb_read_reg
++#endif
++#ifndef sb_write
++#define sb_write intel_cln_sb_write_reg
++#endif
++
++/* Define size of pages, ECC scrub demark etc */
++#define MAX_PAGE_RETRIES (100)
++#define MS_PER_HOUR (3600000UL)
++#define ESRAM_PAGE_COUNT INTEL_CLN_ESRAM_PAGE_COUNT
++#define ESRAM_PAGE_MASK (0xFFFFF000)
++#define ESRAM_PAGE_SIZE INTEL_CLN_ESRAM_PAGE_SIZE
++#define ESRAM_TOTAL_SIZE (ESRAM_PAGE_COUNT * ESRAM_PAGE_SIZE)
++#define ECC_MAX_REFRESH_PERIOD (48)
++#define ECC_DEFAULT_REFRESH_PERIOD (24)
++#define ECC_DRAM_READSIZE (512) /* bytes per DRAM ECC */
++#define ECC_ESRAM_READSIZE ESRAM_PAGE_SIZE /* bytes per SRAM ECC */
++
++/* Register ID */
++#define ESRAM_PGPOOL_REG (0x80) /* PGPOOL */
++#define ESRAM_CTRL_REG (0x81) /* ESRAMCTRL */
++#define ESRAM_PGBLOCK_REG (0x82) /* Global page ctrl */
++#define ESCRM_ECCCERR_REG (0x83) /* Correctable ECC */
++#define ESRAM_ECCUCERR_REG (0x84) /* Uncorrectable ECC */
++
++/* Reg commands */
++#define ESRAM_CTRL_READ (0x10) /* Config reg */
++#define ESRAM_CTRL_WRITE (0x11) /* Config reg */
++#define ESRAM_PAGE_READ (0x12) /* Page config read */
++#define ESRAM_PAGE_WRITE (0x13) /* Page config write */
++
++/* ESRAMPGPOOL reg 0x80 - r/w opcodes 0x10/0x11 */
++#define ESRAM_PGPOOL_FLUSHING(x) ((x>>18)&0x1FF)
++#define ESRAM_PGPOOL_PGBUSY(x) ((x>>9)&0x1FF)
++
++/* ESRAMCTRL reg 0x81 - r/w opcodes 0x10/0x11 */
++#define ESRAM_CTRL_FLUSHPRI(x) ((x>>25)&0x03) /* DRAM flush priority */
++#define ESRAM_CTRL_SIZE(x) ((x>>16)&0xFF) /* # of 4k pages */
++#define ESRAM_CTRL_ECCTHRESH(x) ((x>>8)&0xFF) /* ECC threshold */
++#define ESRAM_CTRL_THRESHMSG_EN (0x00000080) /* ECC notification */
++#define ESRAM_CTRL_ISAVAIL (0x00000010) /* ESRAM on die ? */
++#define ESRAM_CTRL_BLOCK_MODE (0x00000008) /* Block mode enable */
++#define ESRAM_CTRL_GLOBAL_LOCK (0x00000004) /* Global lock status */
++#define ESRAM_CTRL_FLUSHDISABLE (0x00000002) /* Global flush/dis */
++#define ESRAM_CTRL_SECDEC (0x00000001) /* ECC enable bit */
++
++/* PGBLOCK reg 0x82 - opcode 0x10/0x11 */
++#define ESRAM_PGBLOCK_FLUSHEN (0x80000000) /* Block flush enable */
++#define ESRAM_PGBLOCK_PGFLUSH (0x40000000) /* Flush the block */
++#define ESRAM_PGBLOCK_DISABLE (0x20000000) /* Block mode disable */
++#define ESRAM_PGBLOCK_ENABLE (0x10000000) /* Block mode enable */
++#define ESRAM_PGBLOCK_LOCK (0x08000000) /* Block mode lock en */
++#define ESRAM_PGBLOCK_INIT (0x04000000) /* Block init in prog */
++#define ESRAM_PGBLOCK_BUSY (0x01000000) /* Block is enabled */
++#define ESRAM_PGBLOCK_SYSADDR(x) (x&0x000000FF)
++
++/* ESRAMPGCTRL - opcode 0x12/0x13 */
++#define ESRAM_PAGE_FLUSH_PAGE_EN (0x80000000) /* S3 autoflush */
++#define ESRAM_PAGE_FLUSH (0x40000000) /* Flush page to DRAM */
++#define ESRAM_PAGE_DISABLE (0x20000000) /* page disable bit */
++#define ESRAM_PAGE_EN (0x10000000) /* Page enable */
++#define ESRAM_PAGE_LOCK (0x08000000) /* Page lock en */
++#define ESRAM_PAGE_INITIALISING (0x04000000) /* Init in progress */
++#define ESRAM_PAGE_BUSY (0x01000000) /* Page busy */
++#define ESRAM_PAGE_MAP_SHIFT (12) /* Shift away 12 LSBs */
++
++/* Extra */
++#define ESRAM_MAP_OP (0x01)
++#define ESRAM_UNMAP_OP (0x00)
++
++/**
++ * struct esram_refname
++ *
++ * Structure to hold a linked list of names
++ */
++struct esram_refname {
++ char name[KSYM_SYMBOL_LEN]; /* Name of mapping */
++ struct list_head list;
++};
++
++/**
++ * struct esram_page
++ *
++ * Represents an eSRAM page in our linked list
++ */
++struct esram_page {
++
++ struct list_head list; /* List entry descriptor */
++ struct list_head name_list; /* Linked list for name references */
++ u32 id; /* Page ID */
++ u32 phys_addr; /* Physial address of page */
++ u32 refcount; /* Reference count */
++ u32 vaddr; /* Virtual address of page */
++
++};
++
++/**
++ * struct intel_cln_esram_dev
++ *
++ * Structre to represent module state/data/etc
++ */
++struct intel_cln_esram_dev{
++
++ /* Linux kernel structures */
++ struct list_head page_used; /* Used pages */
++ struct list_head page_free; /* Free pages */
++ spinlock_t slock; /* Spinlock */
++ struct platform_device *pldev; /* Platform device */
++
++ /* Actual data */
++ struct esram_page * pages;
++ u8 cbuf[ESRAM_PAGE_SIZE];
++
++ /* Stats */
++ u32 page_count; /* As reported by silicon */
++ u32 page_disable_retries; /* Aggreate count on disable */
++ u32 page_enable_retries; /* Aggregate spin count page enable */
++ u32 page_free_ct; /* Free pages for mapping code section */
++};
++
++static struct intel_cln_esram_dev esram_dev;
++
++/*
++ * Kallsyms does not provide data addresses. To map important structures such as
++ * the idt and gdt, we need to frig the lookup with the below. Other entities
++ * can similarly be added. Note we map a page from the given address - anything
++ * larger will require additional code to handle
++ */
++struct esram_symex {
++ char * name;
++ void * vaddr;
++ u32 size;
++};
++
++static struct esram_symex esram_symex[] =
++{
++ {
++ .name = "idt_table",
++ .vaddr = &idt_table,
++ .size = ESRAM_PAGE_SIZE,
++ },
++ {
++ .name = "gdt_page",
++ .vaddr = &gdt_page,
++ .size = ESRAM_PAGE_SIZE,
++ },
++};
++
++/**
++ * intel_cln_esram_stat_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates eSRAM state via /sys/device/intel-cln-esram.0/stat
++ */
++static ssize_t intel_cln_esram_stat_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++
++{
++ struct esram_page * epage = NULL;
++ int len = 0;
++ unsigned int count = PAGE_SIZE, size;
++ u32 pgpool = 0, ctrl = 0, pgblock = 0;
++ char * enabled = "enabled";
++ char * disabled = "disabled";
++
++ /* Display page-pool relevant data */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGPOOL_REG, &pgpool, 1);
++ size = snprintf(buf, count,
++ "esram-pgpool\t\t\t: 0x%08x\n"
++ "esram-pgpool.free\t\t: %u\n"
++ "esram-pgpool.flushing\t\t: %u\n",
++ pgpool, ESRAM_PGPOOL_PGBUSY(pgpool)+1,
++ ESRAM_PGPOOL_FLUSHING(pgpool) + 1);
++ len += size;
++ count -= size;
++
++ /* Display ctrl reg - most of this is of interest */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ size = snprintf(buf + len, count - len,
++ "esram-ctrl\t\t\t: 0x%08x\n"
++ "esram-ctrl.ecc\t\t\t: %s\n"
++ "esram-ctrl.ecc-theshold\t\t: %u\n"
++ "esram-ctrl.pages\t\t: %u\n"
++ "esram-ctrl.dram-flush-priorityi\t: %u\n",
++ ctrl, (ctrl & ESRAM_CTRL_SECDEC) ? enabled : disabled,
++ ESRAM_CTRL_ECCTHRESH(ctrl), ESRAM_CTRL_SIZE(ctrl)+1,
++ ESRAM_CTRL_FLUSHPRI(ctrl));
++ len += size;
++ count -= size;
++
++ /* Display block ctrl/stat - we should be !block mode */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &pgblock, 1);
++ size = snprintf(buf + len, count - len, "esram-block\t\t\t: 0x%08x\n",
++ pgblock);
++ len += size;
++ count -= size;
++
++ /* Print ECC status regs */
++
++ /* Print per-page info */
++ size = snprintf(buf + len, count - len,
++ "free page\t\t\t: %u\nused page\t\t\t: %u\n"
++ "refresh \t\t\t: %ums\npage enable retries\t\t: %u\n"
++ "page disable retries\t: %u\n",
++ esram_dev.page_free_ct,
++ esram_dev.page_count-esram_dev.page_free_ct,
++ 0,
++ esram_dev.page_enable_retries,
++ esram_dev.page_disable_retries);
++ len += size;
++ count -= size;
++
++ spin_lock(&esram_dev.slock);
++ if(!list_empty(&esram_dev.page_free)){
++
++ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
++ size = snprintf(buf + len, count - len,
++ "ecc next page \t\t\t: %u\n",epage->id);
++ len += size;
++ count -= size;
++
++
++ }
++ spin_unlock(&esram_dev.slock);
++
++ /* Return len indicate eof */
++ return len;
++}
++
++/**
++ * intel_cln_esram_map_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Read back eSRAM mapped entries
++ */
++static ssize_t
++intel_cln_esram_map_show(struct device *dev,struct device_attribute *attr,
++ char *buf)
++{
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++ int len = 0, size = 0;
++ unsigned int count = PAGE_SIZE;
++
++ spin_lock(&esram_dev.slock);
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ /* Print references */
++ list_for_each_entry(refname, &epage->name_list, list){
++ size = snprintf(buf + len, count - len,
++ "%s ", refname->name);
++ len += size;
++ count -= size;
++ }
++ /* Print data */
++ size += snprintf(buf + len, count - len,
++ "\n\tPage virt 0x%08x phys 0x%08x\n"
++ "\tRefcount %u\n",
++ epage->vaddr, epage->phys_addr,
++ epage->refcount);
++ len += size;
++ count -= size;
++ }
++ spin_unlock(&esram_dev.slock);
++
++ /* Return len indicate eof */
++ return len;
++}
++
++/**
++ * intel_cln_esram_map_store
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: input buffer
++ * @param size: size of input data
++ * @return number of bytes successfully written
++ *
++ * Function allows user-space to switch mappings on/off with a simple
++ * echo idt_table > /sys/devices/intel-cln-esram.0/map type command
++ */
++static ssize_t
++intel_cln_esram_map_store(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t size)
++{
++ ssize_t ret = 0;
++ char * sbuf = NULL;
++ unsigned long vaddr = 0, i = 0;
++ unsigned int count = PAGE_SIZE;
++
++ if(count <= 1){
++ return -EINVAL;
++ }
++
++ /* Get input */
++ sbuf = (char*)buf;
++
++ /* Fixup entity to scrub spaces */
++ while(sbuf < (buf + count)){
++ if(*sbuf == ' ' || *sbuf == '\r' || *sbuf =='\n'){
++ *sbuf = 0;
++ break;
++ }
++ sbuf++;
++ }
++
++ /* Check to see if we are being asked to map a non-kallsyms addr */
++ for(i = 0; i < sizeof(esram_symex)/sizeof(struct esram_symex); i++){
++ if(strcmp(buf, esram_symex[i].name) == 0){
++ ret = intel_cln_esram_map_range(
++ esram_symex[i].vaddr,
++ esram_symex[i].size,
++ esram_symex[i].name);
++ goto done;
++ }
++ }
++
++ /* This path relies on kallsyms to provide name/address data */
++ vaddr = kallsyms_lookup_name(buf);
++ if(vaddr == 0)
++ goto done;
++
++ ret = intel_cln_esram_map_symbol((void*)vaddr);
++done:
++ if(ret == 0)
++ ret = (ssize_t)count;
++ return ret;
++}
++
++static struct device_attribute dev_attr_stats = {
++ .attr = {
++ .name = "stats",
++ .mode = 0444,
++ },
++ .show = intel_cln_esram_stat_show,
++};
++
++static struct device_attribute dev_attr_map = {
++ .attr = {
++ .name = "map",
++ .mode = 0644,
++ },
++ .show = intel_cln_esram_map_show,
++ .store = intel_cln_esram_map_store,
++};
++
++static struct attribute *platform_attributes[] = {
++ &dev_attr_stats.attr,
++ &dev_attr_map.attr,
++ NULL,
++};
++
++static struct attribute_group esram_attrib_group = {
++ .attrs = platform_attributes
++};
++
++/******************************************************************************
++ * eSRAM Core
++ ******************************************************************************/
++
++/**
++ * intel_cln_esram_page_busy
++ *
++ * @param epage: Pointer to the page descriptor
++ * @return boolean indicating whether or not a page is enabled
++ */
++static int intel_cln_esram_page_busy(struct esram_page * epage, u8 lock)
++{
++ u32 reg = 0;
++
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, lock);
++ return (reg&(ESRAM_PAGE_BUSY | ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE));
++}
++
++/**
++ * intel_cln_esram_fault
++ *
++ * Dump eSRAM registers and kernel panic
++ * Nothing else to do at this point
++ */
++void intel_cln_esram_fault(struct esram_page * epage, u32 lineno)
++{
++ u32 reg = 0, next = 0, prev = 0, prev_reg = 0;
++ u32 next_reg = 0, block = 0, ctrl = 0;
++
++ pr_err("eSRAM: fault @ %s:%d\n", __FILE__, lineno);
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, epage->id, &reg, 1);
++ pr_err("read page %d state 0x%08x\n", epage->id, reg);
++ if(epage->id == 0){
++ next = 1; prev = 127;
++ }else if(epage->id == 127){
++ next = 0; prev = 126;
++ }else{
++ next = epage->id+1;
++ prev = epage->id-1;
++ }
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, next, &next_reg, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, prev, &prev_reg, 1);
++
++ /* Get state */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
++
++ pr_err("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
++ pr_err("Prev page %d state 0x%08x Next page %d state 0x%08x\n"
++ , next, next_reg, prev, prev_reg);
++ BUG();
++}
++
++
++/**
++ * intel_cln_esram_page_enable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ * @param lock: Indicates whether to attain sb spinlock or not
++ *
++ * Enable an eSRAM page spinning for page to become ready.
++ */
++static void intel_cln_esram_page_enable(struct esram_page *epage, u8 lock)
++{
++ u32 ret = 0;
++
++ /* Fault if we try to enable a disabled page */
++ if(intel_cln_esram_page_busy(epage, lock)){
++ intel_cln_esram_fault(epage, __LINE__);
++ }
++
++ /* Program page mapping */
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_FLUSH_PAGE_EN | ESRAM_PAGE_EN |
++ (epage->phys_addr>>ESRAM_PAGE_MAP_SHIFT), lock);
++ do {
++ /* Poll until page busy bit becomes true */
++ ret = intel_cln_esram_page_busy(epage, lock);
++
++ /* This branch should rarely if ever be true */
++ if(unlikely(ret == 0)){
++ esram_dev.page_enable_retries++;
++ }
++
++ }while(ret == 0);
++}
++
++/**
++ * intel_cln_esram_page_disable_sync
++ *
++ * @param epage: pointer to eSRAM page descriptor
++ *
++ * This function spins waiting for disable bit to clear, useful right after a
++ * disable/disable-flush command. Interrupts are enabled here, sleeping is OK
++ */
++static void intel_cln_esram_page_disable_sync(struct esram_page * epage)
++{
++ u32 ret = 0, retries = 0;
++ do {
++ /* Poll for busy bit clear */
++ ret = intel_cln_esram_page_busy(epage, 1);
++
++ /* This branch should rarely if ever be true */
++ if(unlikely(ret)){
++ esram_dev.page_disable_retries++;
++ retries++;
++ }
++
++ if(retries == MAX_PAGE_RETRIES){
++ intel_cln_esram_fault(epage, __LINE__);
++ }
++ }while(ret);
++}
++
++/**
++ * intel_cln_esram_page_disable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ *
++ * Disable the eSRAM page no flush. Interrupts are enabled here, sleeping is OK
++ */
++static void intel_cln_esram_page_disable(struct esram_page *epage)
++{
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_DISABLE, 1);
++ intel_cln_esram_page_disable_sync(epage);
++}
++
++/**
++ * intel_cln_esram_page_flush_disable
++ *
++ * @param epage: struct esram_page carries data to program to register
++ *
++ * Disable the eSRAM page - with flush. Note the architecture will block access
++ * to the overlayed region until the flush has completed => irqs may be switched
++ * on during this operation.
++ */
++static void intel_cln_esram_page_flush_disable(struct esram_page *epage)
++{
++
++
++ /* Do flush */
++ sb_write(SB_ID_ESRAM, ESRAM_PAGE_WRITE, epage->id,
++ ESRAM_PAGE_FLUSH | ESRAM_PAGE_DISABLE, 1);
++
++ intel_cln_esram_page_disable_sync(epage);
++}
++
++#if 0
++/**
++ * intel_cln_esram_flush_disable_all
++ *
++ * Flushes and disables all enabled eSRAM pages
++ */
++static void intel_cln_esram_page_flush_disable_all(void)
++{
++ struct esram_page * epage = NULL;
++
++ spin_lock(&esram_dev.slock);
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ intel_cln_esram_page_flush_disable(epage);
++ }
++ spin_unlock(&esram_dev.slock);
++}
++#endif
++
++/**
++ * intel_cln_esram_page_populate_atomic
++ *
++ * @param epage: Pointer to eSRAM page desciptor.
++ * @return 0 placeholder, later versions may return error
++ *
++ * Function takes the mappings given in epage and uses the values to populate
++ * an eSRAM page. The copy/enable/copy routine must be done atomically, since we
++ * may be doing a memcpy() of an ISR for example.
++ * For this reason we wrapper this entire call into a callback provided by
++ * side-band, which does a spin_lock_irqsave calls this function and then does
++ * a spin_lock_irqrestore - thus guaranteeing atomicity of the below code and
++ * respect for the locking strategy of the side-band driver
++ */
++static int intel_cln_esram_page_populate_atomic(struct esram_page * epage)
++{
++ unsigned long crz;
++
++ /* Copy away */
++ memcpy(&esram_dev.cbuf, (void*)epage->vaddr, ESRAM_PAGE_SIZE);
++
++ /* If CR0.WP is true - flip it HSD # 4930660 */
++ crz = read_cr0();
++ if (crz & X86_CR0_WP){
++ write_cr0(crz & (~X86_CR0_WP));
++ }
++
++ /* Disable NMI */
++ outb(0x80, 0x70);
++
++ /* Enable page mapping */
++ intel_cln_esram_page_enable(epage, 0);
++
++ /* Copy back - populating memory overlay */
++ memcpy((void*)epage->vaddr, &esram_dev.cbuf, ESRAM_PAGE_SIZE);
++
++ /* Re-enable NMI */
++ outb(0x00, 0x70);
++
++ /* Restore CR0.WP if appropriate HSD # 4930660 */
++ if (crz & X86_CR0_WP){
++ write_cr0(crz);
++ }
++ return 0;
++}
++
++/**
++ * intel_cln_esram_page_populate
++ *
++ * @param epage: Pointer to eSRAM page desciptor.
++ * @return 0 on success < 0 on failure
++ *
++ * Populates the page. set_memory_rw/set_memory_ro require local irqs enabled.
++ * intel_cln_esram_page_populate_atomic - needs irqs switched off since memory
++ * can be inconsistent during the populate operation. Depopulate operations are
++ * architecturally guaranteed
++ */
++static int intel_cln_esram_page_populate(struct esram_page * epage)
++{
++ int flip_rw = 0, level = 0, ret = 0;
++ pte_t * pte = epage != NULL ? lookup_address(epage->vaddr, &level):NULL;
++
++ if(unlikely(pte == NULL)){
++ return -EINVAL;
++ }
++
++ /* Determine if we need to set writable */
++ flip_rw = !(pte_write(*pte));
++
++ /* Ensure memory is r/w - do so before spin_lock_irqsave */
++ if(flip_rw){
++ ret = set_memory_rw(epage->vaddr, 1);
++ if (ret != 0){
++ pr_err("%s error during set_memory_rw = %d\n",
++ __func__, ret);
++ return ret;
++ }
++ }
++
++ /* Force ECC update @ disable only */
++ intel_cln_esram_page_enable(epage, 1);
++ intel_cln_esram_page_disable(epage);
++
++ /* Enable and populate eSRAM page using callback in sb with irqs off */
++ ret |= intel_cln_sb_runfn_lock(
++ (int (*)(void*))intel_cln_esram_page_populate_atomic,(void*)epage);
++
++ /* If we set memory writable - restore previous state */
++ if(flip_rw){
++ ret |= set_memory_ro(epage->vaddr, 1);
++ if (ret != 0){
++ pr_err("%s error during set_memory_ro = %d\n",
++ __func__, ret);
++ return ret;
++ }
++ }
++
++ return ret;
++}
++/**
++ * intel_cln_esram_page_addref
++ *
++ * @param epage: eSRAM page descriptor
++ * @param name: Name of reference to add
++ * @return zero on success negative on error
++ *
++ */
++static int intel_cln_esram_page_addref(struct esram_page * epage, char * name)
++{
++ struct esram_refname * refname = NULL;
++ if(unlikely(epage == NULL || name == NULL)){
++ return -EINVAL;
++ }
++
++ refname = kzalloc(sizeof(struct esram_refname), GFP_KERNEL);
++ if(unlikely(refname == NULL)){
++ return -ENOMEM;
++ }
++
++ /* Add to list */
++ strncpy(refname->name, name, sizeof(refname->name));
++ list_add(&refname->list, &epage->name_list);
++
++ /* Bump reference count */
++ epage->refcount++;
++ return 0;
++}
++
++
++/**
++ * __intel_cln_esram_map_page
++ *
++ * @param page: Page to map
++ * @param name: Name of the mapping
++ * @return 0 success < 0 failure
++ *
++ * Overlay a vritual address rangne eeds to be aligned to a 4k address.
++ * Since multiple items can live in a 4k range, it is possible when calling
++ * into map_page() that a previous mapping will have already covered some or all
++ * of the mapping we want. This is not an error case, if the map function finds
++ * it is being asked to map a 4k range already mapped it returns 0, to indicate
++ * the mapping has suceeded i.e. it's already been mapped. This is logical if
++ * you think about it. In contrast being asked to unmap a region not mapped is
++ * clearly an error...
++ *
++ */
++static int __intel_cln_esram_map_page(u32 vaddr, char * name)
++{
++ int ret = 0;
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++
++ if(unlikely(name == NULL)){
++ return -EINVAL;
++ }
++
++ if(unlikely(esram_dev.page_free_ct == 0)){
++ return -ENOMEM;
++ }
++
++ /* Verify if we have already mapped */
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ if(epage->vaddr == vaddr){
++
++ /* Page already mapped */
++ list_for_each_entry(refname, &epage->name_list, list){
++ if(strcmp(refname->name, name)==0){
++ /* Page mapped at this name */
++ return -EINVAL;
++ }
++ }
++ /* New symbol in previous mapping */
++ return intel_cln_esram_page_addref(epage, name);
++ }
++ }
++
++ /* Enumerate eSRAM page structure */
++ epage = list_first_entry(&esram_dev.page_free, struct esram_page, list);
++ epage->phys_addr = virt_to_phys((void*)vaddr);
++ epage->vaddr = vaddr;
++ ret = intel_cln_esram_page_addref(epage, name);
++ if(unlikely(ret < 0)){
++ return ret;
++ }
++
++ /* Populate page */
++ ret = intel_cln_esram_page_populate(epage);
++
++ /* Move to used list */
++ list_move(&epage->list, &esram_dev.page_used);
++ esram_dev.page_free_ct--;
++
++ return ret;
++}
++
++/**
++ * __intel_cln_esram_unmap_page
++ *
++ * @param page: Page to unmap
++ * @param name: Name of the mapping
++ * @return 0 success < 0 failure
++ *
++ * Unmap a previously mapped virutal address range.
++ * Must be 4k aligned
++ *
++ */
++static int __intel_cln_esram_unmap_page(u32 vaddr, char * name)
++{
++ u8 found = 0;
++ struct esram_page * epage = NULL;
++ struct esram_refname * refname = NULL;
++
++ /* Find physical address */
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ if(epage->vaddr == vaddr){
++ found = 1;
++ break;
++ }
++ }
++
++ /* Bail out on error */
++ if(found == 0){
++ pr_err("0x%08x not mapped\n", vaddr);
++ return -EINVAL;
++ }
++
++ /* Determine reference to delete */
++ found = 0;
++ list_for_each_entry(refname, &epage->name_list, list){
++ if(strcmp(refname->name,name)==0){
++ found = 1;
++ break;
++ }
++ }
++ if(unlikely(found == 0)){
++ pr_err("No mapping %s!\n", name);
++ return -EINVAL;
++ }
++
++ /* Remove entry decrement reference count */
++ list_del(&refname->list);
++ kfree(refname);
++ if(--epage->refcount > 0){
++ return 0;
++ }
++
++ /* Flush and disable page */
++ intel_cln_esram_page_flush_disable(epage);
++
++ /* Move to free list tail - scrub entries come from head */
++ list_move_tail(&epage->list, &esram_dev.page_free);
++ esram_dev.page_free_ct++;
++
++ return 0;
++}
++
++/**
++ *
++ * __intel_cln_esram_page_op
++ *
++ * @param vaddr: Virtual address of symbol
++ * @param size: Size/length of symbol
++ * @param name: Name of mapping
++ * @param map: Boolean indicates whether to map or unmap the page
++ * @return 0 success < 0 failure
++ *
++ * This function maps/unmaps a pages/pages given at the given vaddr. If
++ * the extent of the symbol @ vaddr crosses a page boundary, then we map
++ * multiple pages. Other stuff inside the page, gets a performance boost 'for
++ * free'. Any other data in the page that crosses the physical page boundary
++ * will be partially mapped.
++ */
++static int __intel_cln_esram_page_op(u32 vaddr, u32 size, char *name, u8 map)
++{
++ unsigned long offset = 0, page_offset = 0;
++ u32 pages = size/ESRAM_PAGE_SIZE + ((size%ESRAM_PAGE_SIZE) ? 1 : 0);
++ int ret = 0;
++
++ /* Compare required pages to available pages */
++ if(map == ESRAM_MAP_OP){
++ if(pages > esram_dev.page_free_ct)
++ return -ENOMEM;
++ }else{
++ if(pages > esram_dev.page_count - esram_dev.page_free_ct)
++ return -ENOMEM;
++ }
++
++ /* Align to 4k and iterate the mappings */
++ vaddr = vaddr&ESRAM_PAGE_MASK;
++ while(size > 0){
++
++ /* Map the page */
++ spin_lock(&esram_dev.slock);
++ if(map == ESRAM_MAP_OP){
++ ret = __intel_cln_esram_map_page(vaddr, name);
++
++ }else{
++ ret = __intel_cln_esram_unmap_page(vaddr, name);
++ }
++ spin_unlock(&esram_dev.slock);
++ if(unlikely(ret != 0)){
++ break;
++ }
++
++ /* Calc appropriate offsets */
++ page_offset = offset_in_page(vaddr);
++ if(page_offset + size > ESRAM_PAGE_SIZE){
++
++ offset = ESRAM_PAGE_SIZE - page_offset;
++ size -= offset;
++ vaddr += ESRAM_PAGE_SIZE;
++
++ }else{
++ size = 0;
++ }
++ }
++
++ return ret;
++}
++
++/******************************************************************************
++ * eSRAM API
++ ******************************************************************************/
++
++/**
++ * intel_cln_esram_map_range
++ *
++ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
++ * @param size: Size to map from
++ * @param mapname: Mapping name
++ * @return 0 success < 0 failure
++ *
++ * Map 4k increments at given address to eSRAM.
++ */
++int intel_cln_esram_map_range(void * vaddr, u32 size, char * mapname)
++{
++ if(size == 0 || mapname == NULL || vaddr == NULL){
++ return -EINVAL;
++ }
++ return __intel_cln_esram_page_op((u32)vaddr, size, mapname, ESRAM_MAP_OP);
++}
++EXPORT_SYMBOL(intel_cln_esram_map_range);
++
++/**
++ * intel_cln_esram_map_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
++ * kernel text section symbol (kernel or loaded module)
++ *
++ * We get the size of the symbol from kallsyms. We guarantee to map the entire
++ * size of the symbol - plus whatever padding is necessary to get alignment to
++ * eSRAM_PAGE_SIZE
++ * Other stuff inside the mapped pages will get a performance boost 'for free'.
++ * If this free boost is not what you want then
++ *
++ * 1. Align to 4k
++ * 2. Pad to 4k
++ * 3. Call intel_cln_esram_map_range()
++ */
++int intel_cln_esram_map_symbol(void * vaddr)
++{
++ long unsigned int size = 0, offset = 0;
++ char symname[KSYM_SYMBOL_LEN];
++
++ kallsyms_lookup_size_offset((long unsigned int)vaddr, &size, &offset);
++ if(size == 0){
++ return -EINVAL;
++ }
++ sprint_symbol(symname, (u32)vaddr);
++
++ return __intel_cln_esram_page_op((u32)vaddr, size, symname, 1);
++}
++EXPORT_SYMBOL(intel_cln_esram_map_symbol);
++
++/******************************************************************************
++ * Module/PowerManagement hooks
++ ******************************************************************************/
++
++/**
++ * intel_cln_esram_suspend
++ *
++ * @param pdev: Platform device structure (unused)
++ * @param pm: Power managment descriptor
++ * @return 0 success < 0 failure
++ *
++ * For each enabled page - flush to DRAM and disable eSRAM page.
++ * For each 4k region the architecture guarantees atomicity of flush/disable.
++ * Hence any memory transactions to the affected region will stall until
++ * flush/disable completes - hence interrupts are left on.
++ */
++static int intel_cln_esram_suspend(struct device * pdev)
++{
++ /* Flush and disable of eSRAM pages is carried out automatically */
++ return 0;
++}
++
++/**
++ * intel_cln_esram_resume
++ *
++ * @param pm: Power management descriptor
++ * @return 0 success < 0 failure
++ *
++ * Runs after resume_noirq. Switches pages back to ro, if appropriate. We do
++ * this here since interrupts will be on, as required by the function
++ * set_memory_ro. If it were possible to set memory ro in resume_noirq we would
++ * do it there instead
++ */
++static int intel_cln_esram_resume(struct device * pdev)
++{
++ struct esram_page * epage = NULL;
++ int ret = 0;
++
++ list_for_each_entry(epage, &esram_dev.page_used, list){
++ ret |= intel_cln_esram_page_populate(epage);
++ }
++
++ return ret;
++}
++
++
++/**
++ * intel_cln_esram_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This driver manages eSRAM on a per-page basis. Therefore if we find block
++ * mode is enabled, or any global, block-level or page-level locks are in place
++ * at module initialisation time - we bail out.
++ */
++static int intel_cln_esram_probe(struct platform_device * pdev)
++{
++ int ret = 0;
++ u32 block = 0, ctrl = 0, i = 0, pgstat = 0;
++
++ memset(&esram_dev, 0x00, sizeof(esram_dev));
++ INIT_LIST_HEAD(&esram_dev.page_used);
++ INIT_LIST_HEAD(&esram_dev.page_free);
++ spin_lock_init(&esram_dev.slock);
++ esram_dev.page_free_ct = 0;
++
++ /* Ensure block mode disabled */
++ block = ESRAM_PGBLOCK_DISABLE;
++ sb_write(SB_ID_ESRAM, ESRAM_CTRL_WRITE, ESRAM_PGBLOCK_REG, block, 1);
++
++ /* Get state */
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_CTRL_REG, &ctrl, 1);
++ sb_read(SB_ID_ESRAM, ESRAM_CTRL_READ, ESRAM_PGBLOCK_REG, &block, 1);
++
++ /* Verify state is good to go */
++ if (ctrl & ESRAM_CTRL_GLOBAL_LOCK){
++ pr_err ("eSRAM: global lock @ 0x%08x\n", ctrl);
++ return -ENODEV;
++ }
++
++ if (block & (ESRAM_PGBLOCK_LOCK | ESRAM_PGBLOCK_ENABLE)){
++ pr_err ("eSRAM: lock @ 0x%08x\n", block);
++ return -ENODEV;
++ }
++ pr_info("eSRAM: CTRL 0x%08x block 0x%08x\n", ctrl, block);
++
++ /* Calculate # of pages silicon supports */
++ esram_dev.page_count = ESRAM_CTRL_SIZE(ctrl) + 1;
++ esram_dev.page_free_ct = esram_dev.page_count;
++ pr_info("eSRAM: pages %d\n", esram_dev.page_free_ct);
++
++ if(esram_dev.page_free_ct <= 1){
++ pr_err("Too few pages reported by eSRAM sub-system\n");
++ return -ENOMEM;
++ }
++
++ /* Allocate an appropriate number of pages */
++ esram_dev.pages = kzalloc(esram_dev.page_count *
++ sizeof(struct esram_page), GFP_KERNEL);
++ if (esram_dev.pages == NULL){
++ return -ENOMEM;
++ }
++
++ /* Initialise list of free pages, explicitely disable as we go */
++ for(i = 0; i < esram_dev.page_count; i++){
++ INIT_LIST_HEAD(&esram_dev.pages[i].name_list);
++ esram_dev.pages[i].id = i;
++
++ /* Read & verify page state */
++ sb_read(SB_ID_ESRAM, ESRAM_PAGE_READ, i, &pgstat, 1);
++ if(pgstat & (ESRAM_PAGE_BUSY | ESRAM_PAGE_LOCK)){
++ pr_err("eSRAM: page %d state 0x%08x err\n", i, pgstat);
++ ret = -ENODEV;
++ goto err;
++ }
++
++ list_add(&esram_dev.pages[i].list, &esram_dev.page_free);
++ }
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &esram_attrib_group);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ kfree(esram_dev.pages);
++ return ret;
++}
++
++/*
++ * Power management operations
++ */
++static const struct dev_pm_ops intel_cln_esram_pm_ops = {
++ .suspend = intel_cln_esram_suspend,
++ .resume = intel_cln_esram_resume,
++};
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_esram_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ .pm = &intel_cln_esram_pm_ops,
++ },
++ .probe = intel_cln_esram_probe,
++};
++
++module_platform_driver(intel_cln_esram_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Clanton eSRAM overlay/ECC-scrub driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff --git a/drivers/platform/x86/quark/intel_cln_esram.h b/drivers/platform/x86/quark/intel_cln_esram.h
+new file mode 100644
+index 0000000..af6156a
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_esram.h
+@@ -0,0 +1,107 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton eSRAM overlay driver
++ *
++ * eSRAM is an on-chip fast access SRAM.
++ *
++ * This driver provides the ability to map a kallsyms derived symbol of
++ * arbitrary length or a struct page entitiy.
++ * A proc interface is provided to allow map/unmap of kernel structures, without
++ * having to use the API from your code directly.
++ *
++ * Example:
++ * echo ehci_irq on > /proc/driver/esram/map
++ * echo ehci_irq off > /proc/driver/esram/map
++ *
++ * An API is provided to allow for mapping of a) kernel symbols or b) pages.
++ * eSRAM requires 4k physically aligned addresses to work - so a struct page
++ * fits neatly into this.
++ *
++ * To populte eSRAM we must copy data to a temporary buffer, overlay and
++ * then copy data back to the eSRAM region.
++ *
++ * When entering S3 - we must save eSRAM state to DRAM, and similarly on restore
++ * to S0 we must repopulate eSRAM
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
++ */
++#ifndef __INTEL_CLN_ESRAM_H__
++#define __INTEL_CLN_ESRAM_H__
++
++#include <linux/module.h>
++
++/* Basic size of an eSRAM page */
++#define INTEL_CLN_ESRAM_PAGE_SIZE (0x1000)
++#define INTEL_CLN_ESRAM_PAGE_COUNT (0x80)
++/**
++ * intel_cln_esram_map_range
++ *
++ * @param vaddr: Virtual address to start mapping (must be 4k aligned)
++ * @param size: Size to map from
++ * @param mapname: Mapping name
++ * @return 0 success < 0 failure
++ *
++ * Map 4k increments at given address to eSRAM.
++ */
++int intel_cln_esram_map_range(void * vaddr, u32 size, char * mapname);
++
++/**
++ * intel_cln_esram_unmap_range
++ *
++ * @param vaddr: The virtual address to unmap
++ * @return 0 success < 0 failure
++ *
++ * Logical corollary of esram_map_page
++ */
++int intel_cln_esram_unmap_range(void * vaddr, u32 size, char * mapname);
++
++/**
++ * intel_cln_esram_map_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Maps a series of 4k chunks starting at vaddr&0xFFFFF000. vaddr shall be a
++ * kernel text section symbol (kernel or loaded module)
++ *
++ * We get the size of the symbol from kallsyms. We guarantee to map the entire
++ * size of the symbol - plus whatever padding is necessary to get alignment to
++ * eSRAM_PAGE_SIZE
++ * Other stuff inside the mapped pages will get a performance boost 'for free'.
++ * If this free boost is not what you want then
++ * 1. Align to 4k
++ * 2. Pad to 4k
++ * 3. Call intel_cln_esram_map_range()
++ */
++int intel_cln_esram_map_symbol(void * vaddr);
++
++/**
++ * intel_cln_esram_unmap_symbol
++ *
++ * @param vaddr: Virtual address of the symbol
++ * @return 0 success < 0 failure
++ *
++ * Logical corollary to intel_cln_esram_map_symbol
++ * Undoes any mapping of pages starting at sym for sym's size
++ */
++int intel_cln_esram_unmap_symbol(void * vaddr);
++
++#endif /* __INTEL_CLN_ESRAM_H__ */
+diff --git a/drivers/platform/x86/quark/intel_cln_esram_test.c b/drivers/platform/x86/quark/intel_cln_esram_test.c
+new file mode 100644
+index 0000000..3d0573d
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_esram_test.c
+@@ -0,0 +1,602 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/**
++ * intel_cln_esram_test.c
++ *
++ * Simple test module to provide test cases for ITS integration
++ *
++ */
++#include <linux/cdev.h>
++#include <linux/crc32.h>
++#include <linux/crc32c.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/kallsyms.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++
++#include "intel_cln_esram.h"
++#include "intel_cln_esram_test.h"
++
++#define DRIVER_NAME "intel_cln_esram_test"
++
++/**
++ * struct intel_cln_esram_dev
++ *
++ * Structre to represent module state/data/etc
++ */
++struct intel_cln_esram_test_dev{
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++ char * pdata;
++ u32 size;
++};
++
++static struct intel_cln_esram_test_dev esram_test_dev;
++static struct class *esram_test_class;
++static DEFINE_MUTEX(esram_test_mutex);
++static int esram_test_major;
++static char * name = "testmap";
++
++/******************************************************************************
++ * eSRAM BIST
++ ******************************************************************************/
++
++static int crc_cache = 0;
++
++unsigned long long tsc_delta(unsigned long long first, unsigned long long end)
++{
++ if (first < end)
++ return end - first;
++ else
++ return (ULLONG_MAX - first) + end;
++}
++
++
++/**
++ * intel_cln_crctest
++ *
++ * Do a CRC32 of the specified region. Return the time taken in jiffies
++ */
++static unsigned long long intel_cln_crctest(char * pdata, u32 crcsize)
++{
++ unsigned long long j1 = 0, j2 = 0;
++
++ rdtscll(j1);
++
++ /* Flush LMT cache to introduce cache miss to our test */
++ __asm__ __volatile__("wbinvd\n");
++ crc32(0, pdata, crcsize);
++
++ rdtscll(j2);
++
++ return tsc_delta(j1, j2);
++}
++
++#ifdef __DEBUG__
++#define bist_err(x){\
++ pr_err("eSRAM bist err line %d errno %d\n", (__LINE__-2), x);\
++ return x;\
++}
++#else
++#define bist_err(x){\
++ return x;\
++}
++#endif
++/**
++ * intel_cln_esram_perpage_overlay
++ *
++ * Maps to integration test spec ID CLN.F.SW.APP.eSRAM.0
++ */
++int intel_cln_esram_test_perpage_overlay(void)
++{
++
++ int ret = 0;
++ u32 idx = 0, size = INTEL_CLN_ESRAM_PAGE_SIZE;
++
++ /* Set a known state */
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ *((u32*)&esram_test_dev.pdata[idx]) = idx;
++ }
++
++
++ /* Basic test of full range of memory */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
++ pr_err("Entry %d is 0x%08x require 0x%08x",
++ idx, esram_test_dev.pdata[idx], idx);
++ bist_err(-EIO);
++ }
++ }
++
++#if 0
++ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_esram_test_pageref_count
++ *
++ * Ensure page reference couting works as expected
++ */
++int intel_cln_esram_test_pagref_count(void)
++{
++ u32 size = INTEL_CLN_ESRAM_PAGE_SIZE;
++ int ret = 0;
++
++ return 0;
++ /* Map a page */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Map a second time - and verify mapping fails */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ bist_err(-EFAULT);
++ }
++
++#if 0
++ /* Unmap - OK */
++ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Verify second unmap operation fails */
++ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ bist_err(-EFAULT);
++ }
++#endif
++ return 0;
++}
++
++extern uint32_t get_crc32table_le(void);
++
++/**
++ * intel_cln_esram_test_contig_perfmetric
++ *
++ * Do a CRC16 for a contigous area of memory
++ * Map contigous area and get a CRC16
++ *
++ * Ensure overlayed data takes less time than regular unoverlayed DRAM
++ */
++int intel_cln_esram_test_contig_perfmetric(void)
++{
++ u32 crcsize = 0x60000;
++ unsigned long long crc32_fullmap = 0, crc32_fullunmap = 0;
++ uint32_t crc32table_le = kallsyms_lookup_name("crc32table_le");
++ int ret = 0;
++
++ if (crc32table_le == 0){
++ pr_err("%s unable to fine symbol crc32table_le\n", __func__);
++ return -ENODEV;
++ }
++
++ /* Get raw data metric */
++ crc_cache = 1;
++ crc32_fullunmap = intel_cln_crctest(esram_test_dev.pdata, crcsize);
++
++ /* Map CRC16 symbol (algorithm) + code (data) */
++ ret = intel_cln_esram_map_symbol(crc32_le);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_cln_esram_map_symbol((void*)crc32table_le);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Map test data */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, crcsize, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ /* Get metric */
++ crc_cache = 1;
++ crc32_fullmap = intel_cln_crctest(esram_test_dev.pdata, crcsize);
++#if 0
++ /* Tidy up */
++ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, crcsize, name);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_cln_esram_unmap_range(((void*)crc32_table),
++ sizeof(crc32_table), name);
++ if(ret){
++ bist_err(ret);
++ }
++ ret = intel_cln_esram_unmap_symbol(crc32);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ pr_info("%s did crctest - mapped - in %llu ticks\n", __func__, crc32_fullmap);
++ pr_info("%s mapped count %llu unmapped %llu\n",
++ __func__, crc32_fullmap, crc32_fullunmap);
++ return crc32_fullmap < crc32_fullunmap;
++}
++
++/**
++ * intel_cln_esram_test_kernel_codemap
++ *
++ * Maps some kernel code - a data section and then calls the code contained
++ * therein. Proves out the running overlayed eSRAM works
++ */
++int intel_cln_esram_test_kernel_codemap(void)
++{
++#if 0
++ int ret = intel_cln_esram_map_symbol(msleep);
++ if(ret){
++ printk(KERN_ERR "%s map symbol msleep fail\n", __FUNCTION__);
++ bist_err(ret);
++ }
++
++ /* run the mapped code */
++ msleep(1);
++
++ /* unmap */
++ ret = intel_cln_esram_unmap_symbol(msleep);
++ if(ret){
++ printk(KERN_ERR "%s unmap symbol msleep fail\n", __FUNCTION__);
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_esram_test_kernel_datamap
++ *
++ * Tests mapping/unmapping of a kernel data structure
++ */
++int intel_cln_esram_test_kernel_datamap(void)
++{
++#if 0
++ unsigned long jtag = 0;
++ unsigned long ctrl = 0;
++
++ /* Map the interrupt descriptor table */
++ int ret = intel_cln_esram_map_range(idt_table, INTEL_CLN_ESRAM_PAGE_SIZE, name);
++ if(ret){
++ bist_err(ret);
++ }
++
++ jtag = jiffies;
++ /* Wait for jiffies to tick or timeout to occur (failure) */
++ while(jtag == jiffies){
++ ctrl++;
++ }
++
++ /* unmap */
++ ret = intel_cln_esram_unmap_range(idt_table, INTEL_CLN_ESRAM_PAGE_SIZE, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_esram_test_sub_unsub
++ *
++ * Subscribe and unsubscribe 100% of available eSRAM
++ */
++int intel_cln_esram_test_sub_unsub(void)
++{
++ int ret = 0;
++ u32 idx = 0, size = INTEL_CLN_ESRAM_PAGE_SIZE * INTEL_CLN_ESRAM_PAGE_COUNT;
++
++ /* Set a known state */
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ *((u32*)&esram_test_dev.pdata[idx]) = idx;
++ }
++
++ /* Basic test of full range of memory */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++ for(idx = 0; idx < size; idx += sizeof(u32)){
++ if(*((u32*)&esram_test_dev.pdata[idx]) != idx){
++ pr_err("Entry %d is 0x%08x require 0x%08x",
++ idx, esram_test_dev.pdata[idx], idx);
++ bist_err(-EIO);
++ }
++ }
++#if 0
++ ret = intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
++ if(ret){
++ bist_err(ret);
++ }
++#endif
++ return 0;
++}
++
++/**
++ * intel_cln_esram_test_over_sub
++ *
++ * Test oversubscription of eSRAM
++ */
++int intel_cln_esram_test_over_sub(void)
++{
++ int ret = 0;
++ u32 size = INTEL_CLN_ESRAM_PAGE_SIZE * (INTEL_CLN_ESRAM_PAGE_COUNT + 1);
++
++ /* Over subscribe should fail */
++ ret = intel_cln_esram_map_range(esram_test_dev.pdata, size, name);
++ if(ret == 0){
++ //intel_cln_esram_unmap_range(esram_test_dev.pdata, size, name);
++ bist_err(-EFAULT);
++ }
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long esram_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ cmd -= CLN_ESRAM_IOCTL_BASE;
++ switch (cmd) {
++ case CLN_F_SW_APP_ESRAM_0:
++ /* Per page overlay */
++ ret = intel_cln_esram_test_perpage_overlay();
++ break;
++
++ case CLN_F_SW_APP_ESRAM_1:
++ /* Verify page reference counting */
++ ret = intel_cln_esram_test_pagref_count();
++ break;
++
++ case CLN_F_SW_APP_ESRAM_2:
++ /* Performance metric or overlay contig RAM */
++ ret = intel_cln_esram_test_contig_perfmetric();
++ if (ret == 1)
++ ret = 0;
++ break;
++
++ case CLN_F_SW_APP_ESRAM_3:
++ /* Verify mapping of kernel code section */
++ /* Covered by test #2 */
++ ret = 0; //intel_cln_esram_test_kernel_codemap();
++ break;
++
++ case CLN_F_SW_APP_ESRAM_4:
++ /* Verify mapping of kernel data section (IDT) */
++ /* Covered by test #2 */
++ ret = 0; //intel_cln_esram_test_kernel_datamap();
++ break;
++
++ case CLN_F_SW_APP_ESRAM_5:
++ /* Complete subscribe/unsubscribe eSRAM */
++ ret = intel_cln_esram_test_sub_unsub();
++ break;
++
++ case CLN_F_SW_APP_ESRAM_6:
++ /* Over subscribe eSRAM */
++ ret = intel_cln_esram_test_over_sub();
++ break;
++
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int esram_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&esram_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&esram_test_dev.open_lock)) {
++ mutex_unlock(&esram_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (esram_test_dev.opened) {
++ mutex_unlock(&esram_test_dev.open_lock);
++ mutex_unlock(&esram_test_mutex);
++ return -EINVAL;
++ }
++
++ esram_test_dev.opened++;
++ mutex_unlock(&esram_test_dev.open_lock);
++ mutex_unlock(&esram_test_mutex);
++
++ return 0;
++}
++
++static int esram_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&esram_test_dev.open_lock);
++ esram_test_dev.opened = 0;
++ mutex_unlock(&esram_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations esram_test_file_ops = {
++ .open = esram_test_open,
++ .release = esram_test_release,
++ .unlocked_ioctl = esram_test_ioctl,
++ .llseek = no_llseek,
++};
++
++
++/**
++ * intel_cln_esram_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This driver manages eSRAM on a per-page basis. Therefore if we find block
++ * mode is enabled, or any global, block-level or page-level locks are in place
++ * at module initialisation time - we bail out.
++ */
++static int intel_cln_esram_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ esram_test_dev.size = INTEL_CLN_ESRAM_PAGE_COUNT * INTEL_CLN_ESRAM_PAGE_SIZE;
++
++ /* Get memory */
++ esram_test_dev.pdata = kzalloc(esram_test_dev.size, GFP_KERNEL);
++ if(unlikely(esram_test_dev.pdata == NULL)){
++ pr_err("Can't allocate %d bytes\n", esram_test_dev.size);
++ return -ENOMEM;
++ }
++
++ mutex_init(&esram_test_dev.open_lock);
++ cdev_init(&esram_test_dev.cdev, &esram_test_file_ops);
++ esram_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&esram_test_dev.cdev, MKDEV(esram_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ kfree(esram_test_dev.pdata);
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(esram_test_class, NULL,
++ MKDEV(esram_test_major, minor), NULL,
++ "esramtest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ kfree(esram_test_dev.pdata);
++ return -EINVAL;
++ }
++ printk(KERN_INFO "%s/%s/%s complete OK !!\n", __FUNCTION__, __DATE__,__TIME__);
++ return 0;
++
++}
++
++/**
++ * intel_cln_esram_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_cln_esram_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(esram_test_dev.cdev.dev);
++
++ device_destroy(esram_test_class, MKDEV(esram_test_major, minor));
++ cdev_del(&esram_test_dev.cdev);
++ kfree(esram_test_dev.pdata);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_esram_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_cln_esram_test_remove,
++};
++
++/**
++ * intel_cln_esram_init
++ *
++ * @return 0 success < 0 failure
++ *
++ * Module entry point
++ */
++static int __init intel_cln_esram_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ esram_test_class = class_create(THIS_MODULE,"cln_esram_test");
++ if (IS_ERR(esram_test_class)) {
++ retval = PTR_ERR(esram_test_class);
++ printk(KERN_ERR "esram_test: can't register earam_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "esram_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ esram_test_major = MAJOR(dev);
++
++ memset(&esram_test_dev, 0x00, sizeof(esram_test_dev));
++ esram_test_dev.pldev = platform_create_bundle(
++ &intel_cln_esram_test_driver, intel_cln_esram_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(esram_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(esram_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(esram_test_class);
++err:
++ return retval;
++}
++
++/**
++ * intel_cln_esram_exit
++ *
++ * Module exit
++ */
++static void __exit intel_cln_esram_test_exit(void)
++{
++ platform_device_unregister(esram_test_dev.pldev);
++ platform_driver_unregister(&intel_cln_esram_test_driver);
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Clanton eSRAM ITS driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++module_init(intel_cln_esram_test_init);
++module_exit(intel_cln_esram_test_exit);
+diff --git a/drivers/platform/x86/quark/intel_cln_esram_test.h b/drivers/platform/x86/quark/intel_cln_esram_test.h
+new file mode 100644
+index 0000000..98e4546
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_esram_test.h
+@@ -0,0 +1,43 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/**
++ * intel_cln_esram_test.h
++ *
++ * Define integers for ioctl operation
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>
++ */
++
++#ifndef __INTEL_CLN_ESRAM_TEST_H__
++#define __INTEL_CLN_ESRAM_TEST_H__
++
++#define CLN_ESRAM_IOCTL_BASE 255
++#define CLN_F_SW_APP_ESRAM_0 0x00000000
++#define CLN_F_SW_APP_ESRAM_1 0x00000001
++#define CLN_F_SW_APP_ESRAM_2 0x00000002
++#define CLN_F_SW_APP_ESRAM_3 0x00000003
++#define CLN_F_SW_APP_ESRAM_4 0x00000004
++#define CLN_F_SW_APP_ESRAM_5 0x00000005
++#define CLN_F_SW_APP_ESRAM_6 0x00000006
++#define CLN_F_SW_APP_ESRAM_7 0x00000007
++#define CLN_F_SW_APP_ESRAM_8 0x00000008
++
++#endif /* __INTEL_CLN_ESRAM_TEST_H__ */
++
+diff --git a/drivers/platform/x86/quark/intel_cln_imr.c b/drivers/platform/x86/quark/intel_cln_imr.c
+new file mode 100644
+index 0000000..b8259a6
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_imr.c
+@@ -0,0 +1,584 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
++ *
++ * A total number of 8 IMRs have implemented by Clanton SoC,
++ * Some IMRs might be already occupied by BIOS or Linux during
++ * booting time.
++ *
++ * A user can cat /sys/devices/platform/intel-cln-imr/status for current IMR
++ * status
++ *
++ * To allocate an IMR addresses must be alinged to 1k
++ *
++ * The IMR alloc API will locate the next available IMR slot set up
++ * with input memory region, then apply the input access right masks
++ *
++ * The IMR can be freed with the pre-allocated memory addresses.
++ */
++
++#include <asm-generic/uaccess.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/proc_fs.h>
++
++#include "intel_cln_imr.h"
++#include <asm/imr.h>
++
++#define DRIVER_NAME "intel-cln-imr"
++
++#define IMR_READ_MASK 0x1
++#define IMR_MAX_ID 7
++
++#ifndef phys_to_virt
++#define phys_to_virt __va
++#endif
++
++/* IMR HW register address structre */
++struct cln_imr_reg_t {
++ u8 imr_xl; /* high address register */
++ u8 imr_xh; /* low address register */
++ u8 imr_rm; /* read mask register */
++ u8 imr_wm; /* write mask register */
++} cln_imr_reg_t;
++
++/**
++ * struct cln_imr_addr_t
++ *
++ * IMR memory address structure
++ */
++struct cln_imr_addr_t {
++ u32 addr_low; /* low boundary memroy address */
++ u32 addr_high; /* high boundary memory address */
++ u32 read_mask; /* read access right mask */
++ u32 write_mask; /* write access right mask */
++} cln_imr_addr_t;
++
++/**
++ * struct cln_imr_pack
++ *
++ * local IMR pack structure
++ */
++struct cln_imr_pack {
++ bool occupied; /* IMR occupied */
++ bool locked; /* IMR lock */
++ struct cln_imr_reg_t reg; /* predefined imr register address */
++ struct cln_imr_addr_t addr; /* IMR address region structure */
++ unsigned char info[MAX_INFO_SIZE]; /* IMR info */
++} cln_imr_pack;
++
++
++/* Predefined HW register address */
++static struct cln_imr_reg_t imr_reg_value[] = {
++ { IMR0L, IMR0H, IMR0RM, IMR0WM },
++ { IMR1L, IMR1H, IMR1RM, IMR1WM },
++ { IMR2L, IMR2H, IMR2RM, IMR2WM },
++ { IMR3L, IMR3H, IMR3RM, IMR3WM },
++ { IMR4L, IMR4H, IMR4RM, IMR4WM },
++ { IMR5L, IMR5H, IMR5RM, IMR5WM },
++ { IMR6L, IMR6H, IMR6RM, IMR6WM },
++ { IMR7L, IMR7H, IMR7RM, IMR7WM }
++};
++
++static struct platform_device *pdev;
++
++/**
++ * module parameter
++ * IMR slot should repersant the available IMR region from
++ * linux boot and BIOS.
++ *
++ * For example: imr_bit_mask = 0x10111001
++ * occupied IMR: 0, 3, 4, 5, 7
++ * un-occupied IMR: 1, 2, 6
++ */
++static int imr_bit_mask = 0xFF;
++module_param(imr_bit_mask, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(imr_bit_mask, "IMR bit mask");
++
++/**
++ * module parameter
++ * if IMR lock is a nozero value, all unlocked
++ * imrs will be locked regardless the usage.
++ */
++static int imr_lock = 0;
++module_param(imr_lock, int, S_IRUGO|S_IWUSR);
++MODULE_PARM_DESC(imr_lock, "switch to lock unused IMR");
++
++/* local IMR data structure */
++struct cln_imr_pack local_imr[IMR_MAXID];
++
++/**
++ * intel_cln_imr_read_reg
++ *
++ * @param reg: register address
++ * @return nothing
++ *
++ * return register value from input address.
++ */
++static inline uint32_t intel_cln_imr_read_reg(uint8_t reg)
++{
++ uint32_t temp = 0;
++
++ intel_cln_sb_read_reg(SB_ID_ESRAM, CFG_READ_OPCODE, reg, &temp, 0);
++ return temp;
++}
++
++/**
++ * intel_clm_imr_latch_data
++ *
++ * @return nothing
++ *
++ * Populate IMR data structure from HW.
++ */
++static inline void intel_clm_imr_latch_data(void)
++{
++ int i = 0;
++
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ local_imr[i].addr.addr_low =
++ intel_cln_imr_read_reg(imr_reg_value[i].imr_xl);
++ local_imr[i].addr.addr_high =
++ intel_cln_imr_read_reg(imr_reg_value[i].imr_xh);
++ local_imr[i].addr.read_mask =
++ intel_cln_imr_read_reg(imr_reg_value[i].imr_rm);
++ local_imr[i].addr.write_mask =
++ intel_cln_imr_read_reg(imr_reg_value[i].imr_wm);
++
++ if (local_imr[i].addr.addr_low & IMR_LOCK_BIT)
++ local_imr[i].locked = true;
++
++ if (local_imr[i].addr.read_mask > 0 &&
++ local_imr[i].addr.read_mask < IMR_READ_ENABLE_ALL){
++ local_imr[i].occupied = true;
++ } else {
++ local_imr[i].occupied = false;
++ memcpy(local_imr[i].info, "NOT USED", MAX_INFO_SIZE);
++ }
++ }
++}
++
++/**
++ * prepare_input_addr
++ *
++ * @param addr: input physical memory address
++ * @return formated memory address
++ *
++ * 1. verify input memory address alignment
++ * 2. apply IMR_REG_MASK to match the format required by HW
++ */
++static inline uint32_t prepare_input_addr(uint32_t addr)
++{
++ if (addr & (IMR_MEM_ALIGN - 1))
++ return 0;
++
++ addr = (addr >> 8) & IMR_REG_MASK;
++ return addr;
++}
++
++/**
++ * intel_cln_imr_find_free_entry
++ *
++ * @return the next free imr slot
++ */
++static int intel_cln_imr_find_free_entry(void)
++{
++ int i = 0;
++
++ intel_clm_imr_latch_data();
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ if ((!local_imr[i].occupied) && (!local_imr[i].locked))
++ return i;
++ }
++
++ pr_err("%s: No more free IMR available.\n", __func__);
++ return -ENOMEM;
++}
++
++/**
++ * intel_cln_imr_add_entry
++ *
++ * @param id: imr slot id
++ * @param hi: hi memory address
++ * @param lo: lo memory address
++ * @param read: read access mask
++ * @param write: write access mask
++ * @return nothing
++ *
++ * Setup an IMR entry
++ */
++static void intel_cln_imr_add_entry(int id, uint32_t hi,
++ uint32_t lo, uint32_t read, uint32_t write, bool lock)
++{
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, lo, 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xh, hi, 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_rm, read, 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_wm, write, 0);
++ if (lock) {
++ lo |= IMR_LOCK_BIT;
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, lo, 0);
++ }
++}
++
++/**
++ * get_phy_addr
++ * @return phy address value
++ *
++ * convert register format to physical address format.
++ */
++static uint32_t get_phy_addr(uint32_t reg_value)
++{
++ reg_value = ((reg_value & IMR_REG_MASK) << 8);
++ return reg_value;
++}
++
++
++
++/**
++ * intel_cln_imr_init_mask
++ *
++ * @param mask: module parameter
++ * @return nothing
++ *
++ * prepare local IMR data structure from input module parameter.
++ */
++static void intel_cln_imr_init_mask(int mask)
++{
++ int i = 0;
++
++ BUG_ON((mask > 255 || mask < 0));
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ local_imr[i].addr.addr_low =
++ intel_cln_imr_read_reg(imr_reg_value[i].imr_xl);
++
++ /* mask bit 1 means imr occupied*/
++ if (((mask>>i) & IMR_READ_MASK) == 0) {
++ if (!(local_imr[i].addr.addr_low & IMR_LOCK_BIT))
++ intel_cln_remove_imr_entry(i);
++ }
++ }
++}
++
++/**
++ * intel_cln_remove_imr_entry
++ *
++ * @param id: imr slot id
++ * @return nothing
++ *
++ * remove imr slot based on input id
++ */
++void intel_cln_remove_imr_entry(int id)
++{
++ if (id >= IMR_MAXID || local_imr[id].locked)
++ return;
++
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_rm, IMR_READ_ENABLE_ALL,
++ 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_wm, IMR_WRITE_ENABLE_ALL,
++ 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xl, IMR_BASE_ADDR, 0);
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ imr_reg_value[id].imr_xh, IMR_BASE_ADDR, 0);
++
++ intel_clm_imr_latch_data();
++
++}
++EXPORT_SYMBOL(intel_cln_remove_imr_entry);
++
++/**
++ * intel_cln_imr_alloc
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ * @param read: IMR read mask value
++ * @param write: IMR write mask value
++ * @return nothing
++ *
++ * setup the next available IMR with customized read and write masks
++ */
++int intel_cln_imr_alloc(uint32_t high, uint32_t low, uint32_t read,
++ uint32_t write, unsigned char *info, bool lock)
++{
++ int id = 0;
++
++ if (info == NULL)
++ return -EINVAL;
++
++ if ((low & IMR_LOCK_BIT) || (read == 0 || write == 0)) {
++ pr_err("%s: Invalid acces mode\n", __func__);
++ return -EINVAL;
++ }
++
++ /* Calculate aligned addresses and validate range */
++ high = prepare_input_addr(high);
++ low = prepare_input_addr(low);
++
++ /* Find a free entry */
++ id = intel_cln_imr_find_free_entry();
++ if (id < 0)
++ return -ENOMEM;
++
++ /* Add entry - locking as necessary */
++ intel_cln_imr_add_entry(id, high, low, (read & IMR_READ_ENABLE_ALL),
++ write, lock);
++
++ /* Name the new entry */
++ memcpy(local_imr[id].info, info, MAX_INFO_SIZE);
++
++ /* Update local data structures */
++ intel_clm_imr_latch_data();
++
++ pr_info("IMR alloc id %d 0x%08x - 0x%08x %s\n", id, low, high,
++ lock ? "locked" : "unlocked");
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_imr_alloc);
++
++/**
++ * intel_cln_imr_free
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ * @return nothing
++ *
++ * remove the imr based on input memory region
++ */
++int intel_cln_imr_free(uint32_t high, uint32_t low)
++{
++ int i = 0;
++
++ if (low > high) {
++ pr_err("%s: Invalid input address values.\n", __func__);
++ return -EINVAL;
++ }
++
++ high = prepare_input_addr(high);
++ if (!high) {
++ pr_err("%s: Invalid input memory address.\n", __func__);
++ return -EINVAL;
++ }
++
++ low = prepare_input_addr(low);
++ if (!low) {
++ pr_err("%s: Invalid input memory address.\n", __func__);
++ return -EINVAL;
++ }
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ if (local_imr[i].occupied
++ && (local_imr[i].addr.addr_low == low)
++ && (local_imr[i].addr.addr_high == high)
++ && (!local_imr[i].locked)) {
++ intel_cln_remove_imr_entry(i);
++ return 0;
++ }
++ }
++
++ return -EINVAL;
++}
++EXPORT_SYMBOL(intel_cln_imr_free);
++
++/**
++ * intel_cln_imr_init_data
++ *
++ * @return nothing
++ * initialize local_imr data structure
++ */
++static void intel_cln_imr_init_data(void)
++{
++ int i = 0;
++ char * res_str = "System Reserved Region";
++ int len = strlen(res_str);
++
++ intel_clm_imr_latch_data();
++
++ for (i = 0; i < IMR_MAXID; i++) {
++ local_imr[i].reg = imr_reg_value[i];
++ memcpy(local_imr[i].info, res_str, len);
++ }
++}
++
++/**
++ * intel_cln_imr_lockall
++ *
++ * @param mask: module parameter
++ * @return nothing
++ *
++ * lock up all un-locked IMRs
++ */
++int intel_cln_imr_lockall(void)
++{
++ int i = 0;
++ uint32_t temp_addr;
++
++ /* Enumerate IMR data structures */
++ intel_cln_imr_init_data();
++ intel_cln_imr_init_mask(imr_bit_mask);
++
++ /* Cycle through IMRs locking whichever are unlocked */
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ temp_addr = local_imr[i].addr.addr_low;
++ if (!(temp_addr & IMR_LOCK_BIT)) {
++
++ DBG("%s: locking IMR %d\n", __func__, i);
++ temp_addr |= IMR_LOCK_BIT;
++ intel_cln_sb_write_reg(SB_ID_ESRAM, CFG_WRITE_OPCODE,
++ local_imr[i].reg.imr_xl,
++ temp_addr, 0);
++ }
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_imr_lockall);
++
++/**
++ * intel_cln_imr_stat_show
++ *
++ * @param dev: pointer to device
++ * @param attr: attribute pointer
++ * @param buf: output buffer
++ * @return number of bytes successfully read
++ *
++ * Populates IMR state via /sys/device/intel-cln-imr/stat
++ */
++static int intel_cln_imr_stat_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ int len = 0;
++ int i = 0;
++ int size, count = PAGE_SIZE;
++ uint32_t hi_phy_addr, lo_phy_addr;
++
++ for (i = 0; i < IMR_MAXID; i++) {
++
++ /* read back the actual input physical memory address */
++ hi_phy_addr = get_phy_addr(local_imr[i].addr.addr_high);
++ lo_phy_addr = get_phy_addr(local_imr[i].addr.addr_low);
++
++ /* the IMR always protect extra 1k memory size above the input
++ * high reg value
++ */
++ size = ((hi_phy_addr - lo_phy_addr) / IMR_MEM_ALIGN) + 1;
++
++ size = snprintf(buf+len, count,
++ "imr - id : %d\n"
++ "info : %s\n"
++ "occupied : %s\n"
++ "locked : %s\n"
++ "size : %d kb\n"
++ "hi addr (phy): 0x%08x\n"
++ "lo addr (phy): 0x%08x\n"
++ "hi addr (vir): 0x%08x\n"
++ "lo addr (vir): 0x%08x\n"
++ "read mask : 0x%08x\n"
++ "write mask : 0x%08x\n\n",
++ i,
++ local_imr[i].info,
++ local_imr[i].occupied ? "yes" : "no",
++ local_imr[i].locked ? "yes" : "no",
++ size,
++ hi_phy_addr,
++ lo_phy_addr,
++ (uint32_t)phys_to_virt(hi_phy_addr),
++ (uint32_t)phys_to_virt(lo_phy_addr),
++ local_imr[i].addr.read_mask,
++ local_imr[i].addr.write_mask);
++ len += size;
++ count -= size;
++ }
++ return len;
++}
++
++static struct device_attribute dev_attr_stats = {
++ .attr = {
++ .name = "stat",
++ .mode = 0444, },
++ .show = intel_cln_imr_stat_show,
++};
++
++static struct attribute *platform_attributes[] = {
++ &dev_attr_stats.attr,
++ NULL,
++};
++
++static struct attribute_group imr_attrib_group = {
++ .attrs = platform_attributes
++};
++
++/**
++ * intel_cln_imr_init
++ *
++ * @return 0 success < 0 failue
++ *
++ * module entry point
++ */
++int __init intel_cln_imr_init(void)
++{
++ int ret;
++
++ pdev = platform_device_alloc(DRIVER_NAME, -1);
++ if (!pdev)
++ return -ENOMEM;
++
++ ret = platform_device_add(pdev);
++ if (ret)
++ goto fail_platform;
++
++ /* initialise local imr data structure */
++ intel_cln_imr_init_data();
++
++ ret = sysfs_create_group(&pdev->dev.kobj, &imr_attrib_group);
++ if (ret)
++ goto fail_platform;
++
++ if(intel_cln_imr_runt_setparams() == 0 && imr_lock == 1){
++ intel_cln_imr_lockall();
++ }
++
++ return 0;
++
++fail_platform:
++ platform_device_del(pdev);
++ return ret;
++}
++EXPORT_SYMBOL(intel_cln_imr_init);
++
++MODULE_DESCRIPTION("Intel Clanton SOC IMR API ");
++MODULE_AUTHOR("Intel Corporation");
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff --git a/drivers/platform/x86/quark/intel_cln_imr.h b/drivers/platform/x86/quark/intel_cln_imr.h
+new file mode 100644
+index 0000000..3861d60
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_imr.h
+@@ -0,0 +1,155 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
++ *
++ * A total number of 8 IMRs have implemented by Clanton SoC,
++ * some IMRs might be already occupied by BIOS or Linux booting time.
++ *
++ * Input addresses parameter required the actual Physical address.
++ *
++ * The IMR alloc API will locate the next available IMR slot set up
++ * with input memory region, and apply with the default access right
++ * (CPU & CPU_snoop enable).
++ *
++ * The alloc_mask API takes input read & write masks values to set up
++ * IMR with customized access right.
++ *
++ * User can free IMR with pre-alloc specified addresses.
++ */
++
++#ifndef __INTEL_CLN_IMR_H__
++#define __INTEL_CLN_IMR_H__
++
++#include <linux/intel_cln_sb.h>
++#include "asm/io.h"
++
++#define CFG_READ_OPCODE 0x10 /* BUnit Control Read */
++#define CFG_WRITE_OPCODE 0x11 /* BUnit control write */
++
++/* DRAM IMR register addresses */
++#define IMR0L 0x40
++#define IMR0H 0x41
++#define IMR0RM 0x42
++#define IMR0WM 0x43
++#define IMR1L 0x44
++#define IMR1H 0x45
++#define IMR1RM 0x46
++#define IMR1WM 0x47
++#define IMR2L 0x48
++#define IMR2H 0x49
++#define IMR2RM 0x4A
++#define IMR2WM 0x4B
++#define IMR3L 0x4C
++#define IMR3H 0x4D
++#define IMR3RM 0x4E
++#define IMR3WM 0x4F
++#define IMR4L 0x50
++#define IMR4H 0x51
++#define IMR4RM 0x52
++#define IMR4WM 0x53
++#define IMR5L 0x54
++#define IMR5H 0x55
++#define IMR5RM 0x56
++#define IMR5WM 0x57
++#define IMR6L 0x58
++#define IMR6H 0x59
++#define IMR6RM 0x5A
++#define IMR6WM 0x5B
++#define IMR7L 0x5C
++#define IMR7H 0x5D
++#define IMR7RM 0x5E
++#define IMR7WM 0x5F
++
++#define IMR_LOCK_BIT 0x80000000
++#define IMR_WRITE_ENABLE_ALL 0xFFFFFFFF
++#define IMR_READ_ENABLE_ALL 0xBFFFFFFF
++#define IMR_REG_MASK 0xFFFFFC
++
++#define IMR_ESRAM_FLUSH_INIT 0x80000000 /* esram flush */
++#define IMR_SNOOP_ENABLE 0x40000000 /* core snoops */
++#define IMR_PUNIT_ENABLE 0x20000000
++#define IMR_SMM_ENABLE 0x02 /* core SMM access */
++#define IMR_NON_SMM_ENABLE 0x01 /* core non-SMM access */
++#define IMR_BASE_ADDR 0x00
++#define IMR_MEM_ALIGN 0x400
++
++#define MAX_INFO_SIZE 64
++#define IMR_MAXID 8
++
++/* snoop + Non SMM write mask */
++#define IMR_DEFAULT_MASK (IMR_SNOOP_ENABLE \
++ + IMR_ESRAM_FLUSH_INIT \
++ + IMR_NON_SMM_ENABLE)
++
++/* debug printk */
++#ifdef DEBUG
++#define DBG(args...) pr_info(args)
++#else
++#define DBG(args...)
++#endif
++
++extern unsigned long _text;
++extern unsigned long __init_begin;
++
++/**
++ * intel_cln_imr_alloc
++ *
++ * @param high: the end of physical memory address
++ * @param low: the start of physical memory address
++ * @param read: IMR read mask value
++ * @param write: IMR write maks value
++ * @param info: imr information
++ * @param lock: imr lock
++ *
++ * Setup imr with customised read/ write masks
++ */
++int intel_cln_imr_alloc(u32 high, u32 low, u32 read, u32 write,
++ unsigned char *info, bool lock);
++
++/**
++ * intel_cln_imr_free
++ *
++ * @param high: high boundary of memory address
++ * @param low: low boundary of memorry address
++ *
++ * remove the imr based on input memory region
++ */
++int intel_cln_imr_free(u32 high, u32 low);
++
++/**
++ * intel_cln_remove_imr_entry
++ *
++ * @param id: internal imr data struct id
++ *
++ * Remove imr based on input imr data structure id
++ */
++void intel_cln_remove_imr_entry(int id);
++
++/**
++ * intel_cln_imr_init
++ *
++ * Initialise IMRs
++ */
++int intel_cln_imr_init(void);
++
++#endif
+diff --git a/drivers/platform/x86/quark/intel_cln_imr_kernel.c b/drivers/platform/x86/quark/intel_cln_imr_kernel.c
+new file mode 100644
+index 0000000..51e8676
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_imr_kernel.c
+@@ -0,0 +1,139 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton IMR driver
++ *
++ * IMR stand for Insolate Memory Region, supported by Clanton SoC.
++ *
++ * The IMR id 3 is pre-defined as the use for kernel data protection
++ *
++ * The early imr protects entire memory (from the beginning of kernel text
++ * section to the top of memory) during linux boot time. In the linux run
++ * time, the protection need to resize down to memory region that only
++ * contains: kernel text, read only data, and initialized data section.
++ *
++ */
++#include <linux/errno.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/platform_data/clanton.h>
++#include <linux/printk.h>
++#include "intel_cln_imr.h"
++
++/* pre-defined imr id for uncompressed kernel */
++#define IMR_KERNEL_ID 3
++
++/**
++ * addr_hw_ready
++ *
++ * shift input address value to match HW required 1k aligned format
++ */
++static inline uint32_t addr_hw_ready(uint32_t addr)
++{
++ /* memory alignment */
++ addr &= (~((1 << 10) - 1));
++
++ /* prepare input addr in HW required format */
++ addr = (addr >> 8) & IMR_REG_MASK;
++ return addr;
++}
++
++/**
++ * void intel_cln_imr_runt_kerndata_setup
++ *
++ * Setup imr for kernel text, read only data section
++ *
++ * The read only data (rodata) section placed between text and initialized data
++ * section by kernel.
++ */
++static void intel_cln_imr_runt_kerndata_setup(void)
++{
++ uint32_t hi;
++ uint32_t lo;
++
++ hi = (uint32_t)virt_to_phys(&__init_begin);
++ lo = (uint32_t)virt_to_phys(&_text);
++
++ /* Set a locked IMR around the kernel .text section */
++ if (intel_cln_imr_alloc((hi - IMR_MEM_ALIGN), lo,
++ IMR_DEFAULT_MASK, IMR_DEFAULT_MASK,
++ "KERNEL RUNTIME DATA", 1)) {
++ pr_err("IMR: Set up runtime kernel data imr faild!\n");
++ return;
++ }
++}
++
++/**
++ * intel_cln_imr_teardown_unlocked
++ *
++ * Remove any unlocked IMR
++ *
++ */
++static void intel_cln_imr_teardown_unlocked(void)
++{
++ int i = 0;
++ for (i = 0; i < IMR_MAXID; i++)
++ intel_cln_remove_imr_entry(i);
++}
++
++/**
++ * intel_cln_imr_runt_setparams
++ *
++ * set imr range for text, read only, initialised data in linux run time
++ */
++int intel_cln_imr_runt_setparams(void)
++{
++ /* Setup an IMR around the kernel .text area */
++ intel_cln_imr_runt_kerndata_setup();
++
++ /* Remove any other unlocked IMR */
++ intel_cln_imr_teardown_unlocked();
++
++ return 0;
++}
++EXPORT_SYMBOL(intel_cln_imr_runt_setparams);
++
++/**
++ * intel_cln_imr_runt_init
++ *
++ * module entry point
++ */
++static int __init intel_cln_imr_runt_init(void)
++{
++ return 0;
++}
++
++/**
++ * intel_cln_imr_runt_exit
++ *
++ * Module exit
++ */
++static void __exit intel_cln_imr_runt_exit(void)
++{
++ /* do nothing */
++}
++
++MODULE_DESCRIPTION("Intel Clanton SOC IMR API ");
++MODULE_AUTHOR("Intel Corporation");
++MODULE_LICENSE("Dual BSD/GPL");
++
++subsys_initcall(intel_cln_imr_runt_init);
++module_exit(intel_cln_imr_runt_exit);
+diff --git a/drivers/platform/x86/quark/intel_cln_imr_test.c b/drivers/platform/x86/quark/intel_cln_imr_test.c
+new file mode 100644
+index 0000000..2d98507
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_imr_test.c
+@@ -0,0 +1,357 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton IMR Test module
++ *
++ */
++
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++#include "intel_cln_imr.h"
++
++#define DRIVER_NAME "intel_cln_imr_test"
++
++/**
++ * XXX intel_cln_sb.h needs to be updated with SB_ID_PUNIT and change
++ * propagated. This is a workaround to make it look less ugly. */
++#define SB_ID_PUNIT SB_ID_THERMAL
++
++/* Memory-mapped SPI Flash address */
++#define ILB_SPIFLASH_BASEADDR 0xFF800000
++/* PUnit DMA block transfer size, in bytes */
++#define SPI_DMA_BLOCK_SIZE 512
++
++/**************************** Exported to LISA *******************************/
++
++/*
++ * Internally-used ioctl code. At the moment it is not reserved by any mainline
++ * driver.
++ */
++#define IMR_TEST_IOCTL_CODE 0xE1
++
++/*
++ * Integers for ioctl operation.
++ */
++#define IOCTL_CLN_SANITY_CHECK_PUNIT_DMA _IO(IMR_TEST_IOCTL_CODE, 0x00)
++#define IOCTL_CLN_IMR_1 _IO(IMR_TEST_IOCTL_CODE, 0x01)
++
++/*****************************************************************************/
++
++/**
++ * struct intel_cln_imr_dev
++ *
++ * Structure to represent module state/data/etc
++ */
++struct intel_cln_imr_test_dev {
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++};
++
++static struct intel_cln_imr_test_dev imr_test_dev;
++static struct class *imr_test_class;
++static DEFINE_MUTEX(imr_test_mutex);
++static int imr_test_major;
++
++/* PUnit DMA registers over side-band */
++#define PUNIT_SPI_DMA_COUNT_REG 0x60
++#define PUNIT_SPI_DMA_DEST_REG 0x61
++#define PUNIT_SPI_DMA_SRC_REG 0x62
++
++/**
++ * ilb_spi_dma_read
++ *
++ * @param src: physical address in Legacy SPI Flash
++ * @param dst: physical address of destination
++ * @param dma_block_count: number of 512B SPI Flash blocks to be transferred
++ *
++ * Read-access iLB SPI via PUnit DMA engine.
++ *
++ */
++static void ilb_spi_dma_read(u32 *src, u32 *dst, u32 dma_block_count)
++{
++ pr_info("%s: src=%p, dst=%p, count=%u\n", __func__, src, dst,
++ dma_block_count);
++
++ /* Setup source and destination addresses. */
++ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_SRC_REG, (u32) src, 0);
++ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_DEST_REG, (u32) dst, 0);
++
++ pr_info("%s: starting transaction\n", __func__);
++
++ /*
++ * Setup the number of block to be copied over. Transaction will start
++ * as soon as the register is filled with value.
++ */
++ intel_cln_sb_write_reg(SB_ID_PUNIT, CFG_WRITE_OPCODE,
++ PUNIT_SPI_DMA_COUNT_REG, dma_block_count, 0);
++
++ /* Poll for completion. */
++ while (dma_block_count > 0) {
++ intel_cln_sb_read_reg(SB_ID_PUNIT, CFG_READ_OPCODE,
++ PUNIT_SPI_DMA_COUNT_REG, &dma_block_count, 0);
++ }
++
++ pr_info("%s: transaction completed\n", __func__);
++}
++
++/**
++ * punit_dma_sanity_check
++ *
++ * @return 0 if success, 1 if failure
++ *
++ * Perform a basic sanity check for PUnit DMA engine. Copy over a 512B SPI
++ * Flash block.
++ */
++static int punit_dma_sanity_check(void)
++{
++ int err = 0;
++ u32 *buffer = NULL;
++ u32 buf_ph_addr = 0;
++
++ /* Allocate 512B buffer for 1 SPI Flash block */
++ buffer = kzalloc(SPI_DMA_BLOCK_SIZE, GFP_KERNEL);
++ if (!buffer) {
++ err = -ENOMEM;
++ goto end;
++ }
++
++ /* DMA first SPI Flash block into buffer */
++ buf_ph_addr = (u32)virt_to_phys(buffer);
++ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)buf_ph_addr, 1);
++
++ kfree(buffer);
++end:
++ return err;
++}
++
++/**
++ * imr_violate_kernel_punit_dma
++ *
++ * @return always 0
++ *
++ * PUnit-DMA access to the Uncompressed Kernel IMR.
++ * This is based on set_imr_kernel_data() in intel_cln_imr.c. Find the physical
++ * address of .text section and copy a 512B chunk of legacy SPI via PuUnit DMA.
++ *
++ */
++static int imr_violate_kernel_punit_dma(void)
++{
++ extern unsigned long _text;
++ u32 kernel_text = (u32)virt_to_phys(&_text);
++
++ /* We expect this to trigger an IMR violation reset */
++ ilb_spi_dma_read((u32 *)ILB_SPIFLASH_BASEADDR, (u32 *)kernel_text, 1);
++
++ /*
++ * If we're still alive, we have a serious bug:
++ * - we didn't appropriately target the IMR?
++ * - if we have, weren't we prevented from accessing?
++ * - if we weren't prevented, it's unlikely we're alive with a dirty
++ * text section
++ */
++ pr_err("%s: BUG: still running after DMAing into kernel text!?\n",
++ __func__);
++
++ return 0;
++}
++
++/*
++ * File ops
++ */
++static long imr_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int ret = -EINVAL;
++
++ switch (cmd) {
++ case IOCTL_CLN_SANITY_CHECK_PUNIT_DMA:
++ /* Check PUnit DMA actually works */
++ ret = punit_dma_sanity_check();
++ break;
++ case IOCTL_CLN_IMR_1:
++ /* Kernel IMR violation: PUnit DMA access */
++ ret = imr_violate_kernel_punit_dma();
++ break;
++ default:
++ break;
++ }
++
++ return ret;
++}
++
++static int imr_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&imr_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&imr_test_dev.open_lock)) {
++ mutex_unlock(&imr_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (imr_test_dev.opened) {
++ mutex_unlock(&imr_test_dev.open_lock);
++ mutex_unlock(&imr_test_mutex);
++ return -EINVAL;
++ }
++
++ imr_test_dev.opened++;
++ mutex_unlock(&imr_test_dev.open_lock);
++ mutex_unlock(&imr_test_mutex);
++ return 0;
++}
++
++static int imr_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&imr_test_dev.open_lock);
++ imr_test_dev.opened = 0;
++ mutex_unlock(&imr_test_dev.open_lock);
++
++ return 0;
++}
++
++static const struct file_operations imr_test_file_ops = {
++ .open = imr_test_open,
++ .release = imr_test_release,
++ .unlocked_ioctl = imr_test_ioctl,
++ .llseek = no_llseek,
++};
++
++/**
++ * intel_cln_imr_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ */
++static int intel_cln_imr_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ mutex_init(&imr_test_dev.open_lock);
++ cdev_init(&imr_test_dev.cdev, &imr_test_file_ops);
++ imr_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&imr_test_dev.cdev, MKDEV(imr_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(imr_test_class, NULL,
++ MKDEV(imr_test_major, minor), NULL,
++ "imrtest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ return -EINVAL;
++ }
++
++ return 0;
++
++}
++
++static int intel_cln_imr_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(imr_test_dev.cdev.dev);
++
++ device_destroy(imr_test_class, MKDEV(imr_test_major, minor));
++ cdev_del(&imr_test_dev.cdev);
++
++ class_destroy(imr_test_class);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_imr_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_cln_imr_test_remove,
++};
++
++/**
++ * intel_cln_imr_test_init
++ *
++ * Load module.
++ */
++static int __init intel_cln_imr_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ imr_test_class = class_create(THIS_MODULE,"cln_imr_test");
++ if (IS_ERR(imr_test_class)) {
++ retval = PTR_ERR(imr_test_class);
++ printk(KERN_ERR "imr_test: can't register imr_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "imr_test");
++ if (retval) {
++ printk(KERN_ERR "earam_test: can't register character device\n");
++ goto err_class;
++ }
++ imr_test_major = MAJOR(dev);
++
++ memset(&imr_test_dev, 0x00, sizeof(imr_test_dev));
++ imr_test_dev.pldev = platform_create_bundle(
++ &intel_cln_imr_test_driver, intel_cln_imr_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(imr_test_dev.pldev)){
++ printk(KERN_ERR "platform_create_bundle fail!\n");
++ retval = PTR_ERR(imr_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(imr_test_class);
++err:
++ return retval;
++}
++
++static void __exit intel_cln_imr_test_exit(void)
++{
++ platform_device_unregister(imr_test_dev.pldev);
++ platform_driver_unregister(&intel_cln_imr_test_driver);
++}
++
++module_init(intel_cln_imr_test_init);
++module_exit(intel_cln_imr_test_exit);
++
++MODULE_AUTHOR("Josef Ahmad <josef.ahmad@intel.com>");
++MODULE_DESCRIPTION("Clanton IMR test module");
++MODULE_LICENSE("Dual BSD/GPL");
++
+diff --git a/drivers/platform/x86/quark/intel_cln_layout_data.c b/drivers/platform/x86/quark/intel_cln_layout_data.c
+new file mode 100644
+index 0000000..124bccf
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_layout_data.c
+@@ -0,0 +1,100 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <asm/io.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++
++#define DRIVER_NAME "cln-layout-conf"
++static char __iomem * layout_conf_data;
++static int len;
++
++static ssize_t layout_conf_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ ssize_t plen = len+1;
++ if( plen > PAGE_SIZE )
++ plen = PAGE_SIZE;
++ memcpy(buf, layout_conf_data, plen);
++ return plen;
++}
++
++static struct kobj_attribute layout_conf_attr =
++ __ATTR(layout_conf, 0644, layout_conf_show, NULL);
++
++static int intel_cln_layout_data_probe(struct platform_device *pdev)
++{
++ extern struct kobject * board_data_kobj;
++ int ret = 0;
++
++ layout_conf_data = ioremap(pdev->resource->start,
++ resource_size(pdev->resource));
++ if (!layout_conf_data)
++ return -ENODEV;
++
++ len = resource_size(pdev->resource);
++ ret = sysfs_create_file(board_data_kobj, &layout_conf_attr.attr);
++ if (ret != 0){
++ pr_err("failed to create sysfs entry for layout config\n");
++ iounmap(layout_conf_data);
++ layout_conf_data = NULL;
++ }
++
++ return ret;
++}
++
++static int intel_cln_layout_data_remove(struct platform_device *pdev)
++{
++ extern struct kobject * board_data_kobj;
++
++ if (layout_conf_data){
++ sysfs_remove_file(board_data_kobj, &layout_conf_attr.attr);
++ iounmap(layout_conf_data);
++
++ }
++ return 0;
++}
++
++static struct platform_driver cln_layout_data_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_layout_data_probe,
++ .remove = intel_cln_layout_data_remove,
++};
++
++module_platform_driver(cln_layout_data_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Intel Clanton SPI Data API");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c b/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c
+new file mode 100644
+index 0000000..90da1c8
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_clanton_hill.c
+@@ -0,0 +1,197 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "cln-plat-clanton-hill"
++#define GPIO_RESTRICT_NAME "cln-gpio-restrict-nc"
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++#define AD7298_MAX_EXT_VIN_EXT_BATT 30000
++#define AD7298_MAX_EXT_VIN_INT_BATT 9200
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN_EXT_BATT, AD7298_MAX_EXT_VIN_INT_BATT }
++};
++
++/******************************************************************************
++ * Intel Clanton SPI Controller Data
++ ******************************************************************************/
++static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
++ .gpio_cs = 8,
++};
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_0_cs_0,
++ },
++};
++
++/******************************************************************************
++ * ST Microelectronics LIS331DLH I2C Device Platform Data
++ ******************************************************************************/
++#include <linux/platform_data/lis331dlh_intel_cln.h>
++
++/* GPIO interrupt pins connected to the LIS331DLH */
++#define ST_ACCEL_INT1_GPIO 15
++#define ST_ACCEL_INT2_GPIO 4
++
++static struct lis331dlh_intel_cln_platform_data lis331dlh_i2c_platform_data = {
++ .irq1_pin = ST_ACCEL_INT1_GPIO,
++};
++
++static struct gpio reserved_gpios[] = {
++ {
++ ST_ACCEL_INT1_GPIO,
++ GPIOF_IN,
++ "st_accel_i2c-int1"
++ },
++ {
++ ST_ACCEL_INT2_GPIO,
++ GPIOF_IN,
++ "st_accel_i2c-int2"
++ },
++};
++
++static struct i2c_board_info i2c_onboard_devs[] = {
++ {
++ I2C_BOARD_INFO("intel-cln-max9867", 0x18),
++ },
++ {
++ I2C_BOARD_INFO("lis331dlh_cln", 0x19),
++ .platform_data = &lis331dlh_i2c_platform_data,
++ },
++};
++
++/**
++ * intel_cln_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Clanton Hill platform
++ */
++static int intel_cln_spi_add_onboard_devs(void)
++{
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++/**
++ * intel_cln_i2c_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard I2C device(s) present on the Clanton Hill platform
++ */
++static int intel_cln_i2c_add_onboard_devs(void)
++{
++ return i2c_register_board_info(0, i2c_onboard_devs,
++ ARRAY_SIZE(i2c_onboard_devs));
++}
++
++
++/**
++ * intel_cln_gpio_restrict_probe
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
++{
++ int ret = gpio_request_array(reserved_gpios,
++ ARRAY_SIZE(reserved_gpios));
++ if (ret == 0)
++ ret = intel_cln_spi_add_onboard_devs();
++
++ return ret;
++}
++
++static struct platform_driver gpio_restrict_pdriver = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_gpio_restrict_probe,
++};
++
++static int intel_cln_plat_clanton_hill_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = intel_cln_i2c_add_onboard_devs();
++ if (ret == 0)
++ ret = platform_driver_register(&gpio_restrict_pdriver);
++
++ return ret;
++}
++
++static int intel_cln_plat_clanton_hill_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver cln_clanton_hill_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_clanton_hill_probe,
++ .remove = intel_cln_plat_clanton_hill_remove,
++};
++
++module_platform_driver(cln_clanton_hill_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Clanton Hill BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c b/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c
+new file mode 100644
+index 0000000..27ca0ea
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_clanton_peak.c
+@@ -0,0 +1,92 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "cln-plat-clanton-peak"
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .max_speed_hz = 50000000,
++ .bus_num = 0,
++ },
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ },
++};
++
++
++/**
++ * intel_cln_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Clanton Peak platform
++ */
++static int intel_cln_spi_add_onboard_devs(void)
++{
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++static int intel_cln_plat_clanton_peak_probe(struct platform_device *pdev)
++{
++ return intel_cln_spi_add_onboard_devs();
++}
++
++static int intel_cln_plat_clanton_peak_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver clanton_peak_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_clanton_peak_probe,
++ .remove = intel_cln_plat_clanton_peak_remove,
++};
++
++module_platform_driver(clanton_peak_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Clanton Peak BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c b/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c
+new file mode 100644
+index 0000000..b79ce01
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_cross_hill.c
+@@ -0,0 +1,387 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "cln-plat-cross-hill"
++#define GPIO_RESTRICT_NAME_NC "cln-gpio-restrict-nc"
++#define GPIO_RESTRICT_NAME_SC "cln-gpio-restrict-sc"
++
++/*
++ * GPIO numbers to use for reading 4-bit Blackburn Peak SPI daughterboard ID
++ */
++#define SPI_BPEAK_RESET_GPIO 4
++#define SPI_BPEAK_ID0_GPIO 3
++#define SPI_BPEAK_ID1_GPIO 2
++#define SPI_BPEAK_ID2_GPIO 15
++#define SPI_BPEAK_ID3_GPIO 14
++
++static int nc_gpio_reg;
++static int sc_gpio_reg;
++
++static int cross_hill_probe;
++
++/*
++ * Blackburn Peak SPI daughterboard ID values
++ */
++enum {
++ CLN_SPI_BPEAK_ID_ZB_TI = 0xA,
++ CLN_SPI_BPEAK_ID_ZB_DIGI,
++ CLN_SPI_BPEAK_ID_ZB_INFR_NXP,
++ CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL,
++ CLN_SPI_BPEAK_ID_ADC_MAXIM,
++ CLN_SPI_BPEAK_ID_NONE
++};
++
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++/******************************************************************************
++ * Intel Clanton SPI Controller Data
++ ******************************************************************************/
++static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
++ .gpio_cs = 8,
++};
++
++static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_0 = {
++ .gpio_cs = 10,
++};
++
++static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_1 = {
++ .gpio_cs = 11,
++};
++
++static struct spi_board_info spi_generic_devs[] = {
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 50000000,
++ .platform_data = NULL,
++ .mode = SPI_MODE_0,
++ .bus_num = 1,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_1_cs_0,
++ },
++
++ {
++ .modalias = "spidev",
++ .max_speed_hz = 50000000,
++ .platform_data = NULL,
++ .mode = SPI_MODE_0,
++ .bus_num = 1,
++ .chip_select = 1,
++ .controller_data = &cln_ffrd_spi_1_cs_1,
++ },
++
++};
++
++static struct spi_board_info spi_energy_adc_devs[] = {
++ {
++ .modalias = "max78m6610_lmu",
++ .max_speed_hz = 2000000,
++ .platform_data = NULL,
++ .mode = SPI_MODE_3,
++ .bus_num = 1,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_1_cs_0,
++ },
++};
++
++
++
++/**
++ * intel_cln_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Cross Hill platform
++ */
++static int intel_cln_spi_add_onboard_devs(void)
++{
++ struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_0_cs_0,
++ },
++ };
++
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++
++/**
++ * intel_cln_spi_get_bpeak_id
++ *
++ * @param bpeak_id: The Blackburn Peak SPI ID obtained from the daughterboard
++ * @return 0 on success or standard errnos on failure
++ *
++ * Reads an ID from GPIO-connected pins on Blackburn peak SPI daughterboard
++ */
++static int intel_cln_spi_get_bpeak_id(u8 *bpeak_id)
++{
++ int ret = 0;
++ struct gpio spi_bpeak_id_gpios[] = {
++ {
++ SPI_BPEAK_RESET_GPIO,
++ GPIOF_OUT_INIT_HIGH,
++ "spi_bpeak_reset"
++ },
++ {
++ SPI_BPEAK_ID0_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id0"
++ },
++ {
++ SPI_BPEAK_ID1_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id1"
++ },
++ {
++ SPI_BPEAK_ID2_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id2"
++ },
++ {
++ SPI_BPEAK_ID3_GPIO,
++ GPIOF_IN,
++ "spi_bpeak_id3"
++ }
++ };
++
++ /*
++ * Read a 4-bit ID value from ID GPIO inputs, which are only valid
++ * while a RESET GPIO output is asserted (active-low)
++ */
++ ret = gpio_request_array(spi_bpeak_id_gpios,
++ ARRAY_SIZE(spi_bpeak_id_gpios));
++ if (ret) {
++ pr_err("%s: Failed to allocate Blackburn Peak ID GPIO pins\n",
++ __func__);
++ return ret;
++ }
++
++ gpio_set_value(SPI_BPEAK_RESET_GPIO, 0);
++ *bpeak_id =
++ (gpio_get_value(SPI_BPEAK_ID3_GPIO) ? 1 << 3 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID2_GPIO) ? 1 << 2 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID1_GPIO) ? 1 << 1 : 0) |
++ (gpio_get_value(SPI_BPEAK_ID0_GPIO) ? 1 : 0);
++ gpio_set_value(SPI_BPEAK_RESET_GPIO, 1);
++
++ gpio_free_array(spi_bpeak_id_gpios,
++ ARRAY_SIZE(spi_bpeak_id_gpios));
++
++ return 0;
++}
++
++/**
++ * intel_cln_spi_add_bpeak_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers SPI device(s) indicated by the ID value obtained from a
++ * Blackburn Peak SPI daughterboard
++ */
++static int intel_cln_spi_add_bpeak_devs(void)
++{
++ u8 spi_bpeak_id = 0;
++ int ret = 0;
++
++ ret = intel_cln_spi_get_bpeak_id(&spi_bpeak_id);
++ if (ret) {
++ pr_err("%s: failed to obtain Blackburn Peak ID\n",
++ __func__);
++ return ret;
++ }
++
++ switch (spi_bpeak_id) {
++
++ case CLN_SPI_BPEAK_ID_NONE:
++ break;
++
++ case CLN_SPI_BPEAK_ID_ADC_MAXIM:
++ {
++ return spi_register_board_info(spi_energy_adc_devs,
++ ARRAY_SIZE(spi_energy_adc_devs));
++ }
++ case CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL:
++ {
++ pr_debug("CLN_SPI_BPEAK_ID_ZB_EXEGIN_ATMEL.\n");
++ return spi_register_board_info(spi_generic_devs,
++ ARRAY_SIZE(spi_generic_devs));
++ }
++ case CLN_SPI_BPEAK_ID_ZB_DIGI:
++ {
++ pr_debug("CLN_SPI_BPEAK_ID_ZB_DIGI load.\n");
++ return spi_register_board_info(spi_generic_devs,
++ ARRAY_SIZE(spi_generic_devs));
++
++ }
++ default:
++ pr_err("%s: Unsupported Blackburn Peak SPI ID %u\n",
++ __func__, spi_bpeak_id);
++ ret = -EINVAL;
++ }
++
++ return ret;
++}
++
++/** intel_cln_spi_devs_addon
++ *
++ * addon spi device when gpio support in place
++ */
++static int intel_cln_spi_devs_addon(void)
++{
++ int ret = 0;
++
++ if (cross_hill_probe != 1) {
++
++ ret = intel_cln_spi_add_onboard_devs();
++ if (ret)
++ return ret;
++
++ ret = intel_cln_spi_add_bpeak_devs();
++
++ cross_hill_probe = 1;
++ }
++
++ return ret;
++}
++
++/**
++ * intel_cln_gpio_restrict_probe_nc
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_cln_gpio_restrict_probe_nc(struct platform_device *pdev)
++{
++ int ret;
++ nc_gpio_reg = 1;
++
++ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
++ ret = intel_cln_spi_devs_addon();
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++/**
++ * intel_cln_gpio_restrict_probe_sc
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_cln_gpio_restrict_probe_sc(struct platform_device *pdev)
++{
++ int ret;
++ sc_gpio_reg = 1;
++
++ if (nc_gpio_reg == 1 && sc_gpio_reg == 1) {
++ ret = intel_cln_spi_devs_addon();
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++
++static struct platform_driver gpio_restrict_pdriver_nc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_NC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_gpio_restrict_probe_nc,
++};
++
++static struct platform_driver gpio_restrict_pdriver_sc = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME_SC,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_gpio_restrict_probe_sc,
++};
++
++static int intel_cln_plat_cross_hill_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = platform_driver_register(&gpio_restrict_pdriver_nc);
++ if (ret)
++ return ret;
++
++ return platform_driver_register(&gpio_restrict_pdriver_sc);
++}
++
++static int intel_cln_plat_cross_hill_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver cln_cross_hill_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_cross_hill_probe,
++ .remove = intel_cln_plat_cross_hill_remove,
++};
++
++module_platform_driver(cln_cross_hill_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Cross Hill BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_data.c b/drivers/platform/x86/quark/intel_cln_plat_data.c
+new file mode 100644
+index 0000000..059fcee
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_data.c
+@@ -0,0 +1,455 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <asm/io.h>
++#include <linux/crc32.h>
++#include <linux/crc32c.h>
++#include <linux/errno.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/platform_data/clanton.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++
++#define PREFIX "CLN-PLT: "
++#define PLAT_MAGIC 0x54414450 /* PDAT */
++#define DESC_LEN 0x0A
++#define MAC_STRLEN 20
++#define MAC_LEN 6
++
++struct cln_plat_dat_hdr {
++ uint32_t magic;
++ uint32_t length;
++ uint32_t crc32;
++};
++
++struct cln_plat_data {
++ uint16_t plat_id;
++ uint16_t length;
++ uint8_t desc[DESC_LEN];
++ uint16_t version;
++};
++
++struct cln_bsp_reg {
++ struct platform_device pdev;
++ cln_plat_id_t id;
++};
++
++static struct cln_bsp_reg bsp_data [] = {
++ {
++ .pdev.name = "cln-plat-clanton-peak",
++ .pdev.id = -1,
++ .id = CLANTON_PEAK,
++ },
++ {
++ .pdev.name = "cln-plat-kips-bay",
++ .pdev.id = -1,
++ .id = KIPS_BAY,
++ },
++ {
++ .pdev.name = "cln-plat-cross-hill",
++ .pdev.id = -1,
++ .id = CROSS_HILL,
++ },
++ {
++ .pdev.name = "cln-plat-clanton-hill",
++ .pdev.id = -1,
++ .id = CLANTON_HILL,
++ },
++ {
++ .pdev.name = "cln-plat-galileo",
++ .pdev.id = -1,
++ .id = IZMIR,
++ },
++
++};
++
++/**
++ * struct cln_plat_data_list
++ *
++ * Structure to hold a linked list of platform data refs
++ */
++struct cln_plat_data_list {
++ char name[DESC_LEN+1];
++ struct cln_plat_data * plat_data;
++ struct kobj_attribute plat_attr;
++ struct list_head list;
++};
++
++static char __iomem * plat_data;
++static char * plat_bin_name = "pdat_bin";
++static unsigned int plat_bin_size;
++static struct cln_plat_dat_hdr * plat_hdr;
++static struct list_head entry_list;
++
++/**
++ * intel_cln_plat_sysfs_show_bin
++ *
++ * Generic show routine for any of the sysfs entries of this module
++ */
++static ssize_t intel_cln_plat_sysfs_show_bin(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ ssize_t plen = plat_bin_size;
++ if( plen > PAGE_SIZE )
++ plen = PAGE_SIZE;
++
++ memcpy(buf, plat_data, plen);
++ return plen;
++}
++
++/**
++ * intel_cln_plat_sysfs_show
++ *
++ * Generic show routine for any of the sysfs entries of this module
++ */
++static ssize_t intel_cln_plat_sysfs_show(struct kobject *kobj,
++ struct kobj_attribute *attr, char *buf)
++{
++ unsigned char * data;
++ char fmt[0x20];
++ struct cln_plat_data_list * plat_item_list;
++ ssize_t plen = 0;
++
++ list_for_each_entry(plat_item_list, &entry_list, list){
++ if ( attr == &plat_item_list->plat_attr ){
++
++ /* Derive length */
++ plen = plat_item_list->plat_data->length;
++ if (unlikely(plen > PAGE_SIZE))
++ plen = PAGE_SIZE;
++
++ /* Hook data */
++ data =(char*)(plat_item_list->plat_data);
++ data += +sizeof(struct cln_plat_data);
++
++ /* Enumrate return */
++ switch (plat_item_list->plat_data->plat_id){
++ case PLAT_DATA_ID:
++ case PLAT_DATA_SN:
++ snprintf(fmt, sizeof(fmt), "0x%%0%dx\n",
++ plen*2);
++ return sprintf(buf, fmt, *(int16_t*)data);
++ case PLAT_DATA_MAC0:
++ case PLAT_DATA_MAC1:
++ if (unlikely(plen != MAC_LEN)){
++ return sprintf(buf, "invalid mac\n");
++ }
++ return snprintf(buf, MAC_STRLEN,
++ "%02x:%02x:%02x:%02x:%02x:%02x\n",
++ data[0], data[1], data[2], data[3],
++ data[4], data[5]);
++ default:
++ /* Treat as string data */
++ return snprintf(buf, plen, "%s", data);
++ }
++ }
++ }
++ return 0;
++}
++
++/**
++ * intel_cln_plat_cleanup
++ *
++ * Generic cleanup code for the platform data interface
++ *
++ */
++static void intel_cln_plat_cleanup (void)
++{
++ extern struct kobject * board_data_kobj;
++ struct cln_plat_data_list * plat_item_list;
++
++ if (plat_data != NULL){
++ iounmap(plat_data);
++ plat_data = NULL;
++ }
++
++ list_for_each_entry(plat_item_list, &entry_list, list){
++ sysfs_remove_file(board_data_kobj,
++ &plat_item_list->plat_attr.attr);
++ kfree(plat_item_list);
++ }
++}
++
++/**
++ * intel_cln_plat_get_desc_len
++ *
++ * @param desc: Pointer to desc string
++ * @return len on success < 0 failure
++ *
++ * Function called to get a bounds checked desc field from platfrom data
++ *
++ */
++static int intel_cln_plat_get_desc_len (char * desc)
++{
++ int len = 0;
++ if (desc == NULL){
++ return -EINVAL;
++ }
++
++ for(; *desc != '\0' && len < DESC_LEN; desc++, len++);
++ return len;
++}
++
++/**
++ * intel_cln_get_id
++ *
++ * @return platform id on success or < CLANTON_PLAT_UNDEFINED on error
++ *
++ * Function called to get platform id
++ *
++ */
++cln_plat_id_t intel_cln_plat_get_id(void)
++{
++ unsigned char * data;
++ struct cln_plat_data_list * plat_item_list;
++
++ if (plat_data == NULL)
++ return CLANTON_PLAT_UNDEFINED;
++
++ list_for_each_entry(plat_item_list, &entry_list, list){
++
++ /* Enumrate return */
++ if(plat_item_list->plat_data->plat_id == PLAT_DATA_ID){
++
++ /* Hook data */
++ data =(char*)(plat_item_list->plat_data);
++ data += +sizeof(struct cln_plat_data);
++
++ /* Return payload */
++ return *(int16_t*)data;
++ }
++ }
++ return CLANTON_PLAT_UNDEFINED;
++}
++EXPORT_SYMBOL(intel_cln_plat_get_id);
++
++/**
++ * intel_cln_plat_get_mac
++ *
++ * @param id: Index of MAC address to find
++ * @param mac: Output parameter for mac address
++ *
++ * @return 0 success < 0 failure
++ *
++ * Function called to remove the platfrom device from kernel space
++ *
++ */
++int intel_cln_plat_get_mac(plat_dataid_t id, char * mac)
++{
++ unsigned char * data;
++ unsigned int plen = 0;
++ struct cln_plat_data_list * plat_item_list;
++
++ if ((id != PLAT_DATA_MAC0 && id != PLAT_DATA_MAC1) || mac == NULL){
++ pr_err("invalid input id %d mac %p\n", id, mac);
++ return -EINVAL;
++ }
++
++ list_for_each_entry(plat_item_list, &entry_list, list){
++ if(plat_item_list->plat_data->plat_id == id){
++
++ /* Derive length */
++ plen = plat_item_list->plat_data->length;
++ if (unlikely(plen != MAC_LEN)){
++ pr_err("%s mac len invalid!\n", __func__);
++ return -ENODEV;
++ }
++
++ /* Hook data */
++ data =(char*)(plat_item_list->plat_data);
++ data += +sizeof(struct cln_plat_data);
++
++ /* Good to go */
++ memcpy(mac, data, MAC_LEN);
++ return 0;
++ }
++ }
++ return -ENODEV;
++}
++EXPORT_SYMBOL(intel_cln_plat_get_mac);
++
++
++/**
++ * intel_cln_plat_probe
++ *
++ * @param pdev: Pointer to platform device
++ * @return 0 success < 0 failure
++ *
++ * Function called to probe platform device "cln-plat"
++ *
++ */
++int intel_cln_plat_probe(struct resource * pres)
++{
++ char __iomem * end_addr = NULL;
++ char __iomem * data = NULL;
++ cln_plat_id_t id = CLANTON_PLAT_UNDEFINED;
++ extern struct kobject * board_data_kobj;
++ struct cln_plat_data * plat_item = NULL;
++ struct cln_plat_data_list * plat_item_list = NULL;
++ u32 crc = 0;
++ int ret = 0, i = 0;
++
++ INIT_LIST_HEAD(&entry_list);
++ plat_hdr = ioremap(pres->start, resource_size(pres));
++ end_addr = (char*)plat_hdr + resource_size(pres);
++ plat_data = (char*)plat_hdr;
++ if (!plat_hdr)
++ return -ENODEV;
++
++ /* Verify header magic */
++ if (plat_hdr->magic != PLAT_MAGIC){
++ pr_err(PREFIX"Expected magic 0x%08x read 0x%08lx\n",
++ PLAT_MAGIC, (unsigned long)plat_hdr->magic);
++ }
++
++ /* Validate length is sane */
++ if ((char*)plat_hdr + plat_hdr->length > end_addr ||
++ plat_hdr->length < sizeof(struct cln_plat_data)){
++ pr_err(PREFIX"Invalid length 0x%08lx\n",
++ (unsigned long)plat_hdr->length);
++ return -ENODEV;
++ }
++
++ /* Point to real end addr */
++ end_addr = (char*)plat_hdr +
++ sizeof(struct cln_plat_dat_hdr) + plat_hdr->length;
++ plat_bin_size = end_addr - plat_data;
++
++ /* Get pointer to start of data */
++ plat_item = (struct cln_plat_data*)(plat_hdr+1);
++ data = ((char*)(plat_item)+sizeof(struct cln_plat_data));
++
++ /* Validate CRC32 */
++ crc = ~crc32(0xFFFFFFFF, plat_item, plat_hdr->length);
++ if (crc != plat_hdr->crc32){
++ pr_err(PREFIX"CRC 0x%08x header indicates 0x%08x - fatal!\n",
++ crc, plat_hdr->crc32);
++ return -EFAULT;
++ }
++
++ /* /sys/firmware/board_data/plat_bin - dump entire platform binary */
++ plat_item_list = kzalloc(sizeof(struct cln_plat_data_list),
++ GFP_KERNEL);
++ if (unlikely(plat_item_list == NULL)) {
++ pr_err("kzalloc fail !\n");
++ intel_cln_plat_cleanup();
++ return -ENOMEM;
++ }
++ sysfs_attr_init(&plat_item_list->plat_attr.attr);
++ plat_item_list->plat_attr.attr.name = plat_bin_name;
++ plat_item_list->plat_attr.attr.mode = 0644;
++ plat_item_list->plat_attr.show = intel_cln_plat_sysfs_show_bin;
++
++ ret = sysfs_create_file(board_data_kobj,
++ &plat_item_list->plat_attr.attr);
++ if (unlikely(ret != 0)){
++ intel_cln_plat_cleanup();
++ pr_err("failed to create sysfs entry\n");
++ return ret;
++ }
++
++ /* Add to list */
++ list_add(&plat_item_list->list, &entry_list);
++
++ /* Iterate through each entry - add sysfs entry as appropriate */
++ while ( (char*)plat_item < end_addr){
++
++ /* Bounds check */
++ if (data + plat_item->length > end_addr){
++ pr_err(PREFIX"Data 0x%p over-runs max-addr 0x%p\n",
++ data, end_addr);
++ break;
++ }
++
++ /* Extract data */
++ switch(plat_item->plat_id){
++ case PLAT_DATA_ID:
++ id = *((uint16_t*)data);
++ pr_info(PREFIX"Clanton Platform ID = %d\n", id);
++ break;
++ case PLAT_DATA_SN:
++ case PLAT_DATA_MAC0:
++ case PLAT_DATA_MAC1:
++ break;
++ default:
++ /* Unknown identifier */
++ break;
++ }
++
++ plat_item_list = kzalloc(sizeof(struct cln_plat_data_list),
++ GFP_KERNEL);
++ if (unlikely(plat_item_list == NULL)) {
++ pr_err("kzalloc fail !\n");
++ intel_cln_plat_cleanup();
++ return -ENOMEM;
++ }
++
++ /* Get name of entity */
++ i = intel_cln_plat_get_desc_len(plat_item->desc);
++ if (i <= 0){
++ pr_err("desc len is %d!\n", i);
++ intel_cln_plat_cleanup();
++ return i;
++ }
++
++ memcpy(plat_item_list->name, plat_item->desc, i);
++ plat_item_list->plat_data = plat_item;
++
++ sysfs_attr_init(&plat_item_list->plat_attr.attr);
++ plat_item_list->plat_attr.attr.name = plat_item_list->name;
++ plat_item_list->plat_attr.attr.mode = 0644;
++ plat_item_list->plat_attr.show = intel_cln_plat_sysfs_show;
++
++ ret = sysfs_create_file(board_data_kobj,
++ &plat_item_list->plat_attr.attr);
++ if (unlikely(ret != 0)){
++ intel_cln_plat_cleanup();
++ pr_err("failed to create sysfs entry\n");
++ return ret;
++ }
++
++ /* Add to list */
++ list_add(&plat_item_list->list, &entry_list);
++
++ /* Next */
++ plat_item = (struct cln_plat_data*)
++ (((char*)plat_item) + plat_item->length + sizeof(struct cln_plat_data));
++ data = ((char*)(plat_item) + sizeof(struct cln_plat_data));
++ }
++
++ /* Register BSP enabling platform code */
++ for (i = 0; i < sizeof(bsp_data)/sizeof(struct cln_bsp_reg); i++){
++ if (bsp_data[i].id == id){
++ platform_device_register(&bsp_data[i].pdev);
++ }
++ }
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_cln_plat_probe);
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_galileo.c b/drivers/platform/x86/quark/intel_cln_plat_galileo.c
+new file mode 100644
+index 0000000..48ce294
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_galileo.c
+@@ -0,0 +1,264 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/i2c.h>
++#include <linux/i2c/at24.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/mtd/partitions.h>
++#include <linux/mtd/physmap.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/flash.h>
++#include <linux/i2c/at24.h>
++
++#define DRIVER_NAME "cln-plat-galileo"
++#define GPIO_RESTRICT_NAME "cln-gpio-restrict-sc"
++#define LPC_SCH_SPINAME "spi-lpc-sch"
++
++#define CLN_SPI_MAX_CLK_DEFAULT 5000000
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++static struct at24_platform_data at24_platform_data = {
++ .byte_len = (11 * 1024),
++ .page_size = 1,
++ .flags = AT24_FLAG_ADDR16,
++};
++
++/******************************************************************************
++ * Intel Izmir i2c clients
++ ******************************************************************************/
++static struct i2c_board_info __initdata galileo_i2c_board_info[] = {
++ {
++ /* Note following address may change at driver load time */
++ I2C_BOARD_INFO("cy8c9540a", 0x20),
++ },
++ {
++ I2C_BOARD_INFO("at24", 0x50),
++ .platform_data = &at24_platform_data,
++ },
++};
++
++/******************************************************************************
++ * Intel Clanton SPI Controller Data
++ ******************************************************************************/
++static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
++ .gpio_cs = 8,
++};
++
++static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_0 = {
++ .gpio_cs = 10,
++};
++
++#define LPC_SCH_SPI_BUS_ID 0x03
++
++static struct platform_device lpc_sch_spi = {
++ .name = "spi-lpc-sch-drv",
++ .id = LPC_SCH_SPI_BUS_ID,
++};
++
++/* TODO: extract this data from layout.conf encoded in flash */
++struct mtd_partition ilb_partitions [] = {
++ {
++ .name = "grub",
++ .size = 4096,
++ .offset = 0,
++ },
++ {
++ .name = "grub.conf",
++ .size = 0xA00,
++ .offset = 0x50500,
++ },
++ {
++ .name = "layout.conf",
++ .size = 4096,
++ .offset = 0x708000,
++ },
++ {
++ .name = "sketch",
++ .size = 0x40000,
++ .offset = 0x750000,
++ },
++ {
++ .name = "raw",
++ .size = 8192000,
++ .offset = 0,
++
++ },
++};
++
++static struct flash_platform_data ilb_flash = {
++ .type = "s25fl064k",
++ .parts = ilb_partitions,
++ .nr_parts = ARRAY_SIZE(ilb_partitions),
++};
++
++static struct spi_board_info spi_onboard_devs[] = {
++ {
++ .modalias = "m25p80",
++ .platform_data = &ilb_flash,
++ .bus_num = LPC_SCH_SPI_BUS_ID,
++ .chip_select = 0,
++ },
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = CLN_SPI_MAX_CLK_DEFAULT,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_0_cs_0,
++ },
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_1_cs_0,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ },
++};
++
++/**
++ * intel_cln_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Izmir platform
++ */
++static int intel_cln_spi_add_onboard_devs(void)
++{
++
++ return spi_register_board_info(spi_onboard_devs,
++ ARRAY_SIZE(spi_onboard_devs));
++}
++
++
++/**
++ * intel_cln_gpio_restrict_probe
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ ret = intel_cln_spi_add_onboard_devs();
++
++ return ret;
++}
++
++static struct platform_driver gpio_restrict_pdriver = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_gpio_restrict_probe,
++};
++
++/* LPC SPI */
++static int intel_cln_plat_galileo_lpcspi_probe(struct platform_device *pdev)
++{
++ lpc_sch_spi.resource = pdev->resource;
++ return platform_device_register(&lpc_sch_spi);
++}
++
++static struct platform_driver intel_cln_plat_galileo_lpcspi_pdriver = {
++ .driver = {
++ .name = LPC_SCH_SPINAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_galileo_lpcspi_probe,
++};
++
++static int intel_cln_plat_galileo_probe(struct platform_device *pdev)
++{
++ int ret = 0;
++
++ /* i2c */
++ ret = i2c_register_board_info(0, galileo_i2c_board_info,
++ ARRAY_SIZE(galileo_i2c_board_info));
++ if (ret) {
++ goto end;
++ }
++
++ /* gpio */
++ ret = platform_driver_register(&gpio_restrict_pdriver);
++ if (ret)
++ goto end;
++
++#if 0
++ /* legacy SPI - TBD */
++ ret = platform_driver_register(&intel_cln_plat_galileo_lpcspi_pdriver);
++ if (ret)
++ goto end;
++#endif
++end:
++ return ret;
++}
++
++static int intel_cln_plat_galileo_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver cln_galileo_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_galileo_probe,
++ .remove = intel_cln_plat_galileo_remove,
++};
++
++module_platform_driver(cln_galileo_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Galileo BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c b/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c
+new file mode 100644
+index 0000000..1f3deb2
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_plat_kips_bay.c
+@@ -0,0 +1,176 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Legacy Platform Data Layout.conf accessor
++ *
++ * Simple Legacy SPI flash access layer
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2013
++ */
++
++#include <linux/errno.h>
++#include <linux/gpio.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spi/pxa2xx_spi.h>
++#include <linux/spi/spi.h>
++
++#define DRIVER_NAME "cln-plat-kips-bay"
++#define GPIO_RESTRICT_NAME "cln-gpio-restrict-sc"
++
++static int gpio_cs = 1;
++
++module_param(gpio_cs, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(gpio_cs, "Enable GPIO chip-select for SPI channel 1");
++
++
++/******************************************************************************
++ * Analog Devices AD7298 SPI Device Platform Data
++ ******************************************************************************/
++#include "linux/platform_data/ad7298.h"
++
++/* Maximum input voltage allowed for each ADC input, in milliVolts */
++#define AD7298_MAX_EXT_VIN 5000
++
++static const struct ad7298_platform_data ad7298_platform_data = {
++ .ext_ref = false,
++ .ext_vin_max = { AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN,
++ AD7298_MAX_EXT_VIN, AD7298_MAX_EXT_VIN }
++};
++
++/******************************************************************************
++ * Intel Clanton SPI Controller Data
++ ******************************************************************************/
++static struct pxa2xx_spi_chip cln_ffrd_spi_0_cs_0 = {
++ .gpio_cs = 8,
++};
++
++static struct pxa2xx_spi_chip cln_ffrd_spi_1_cs_0 = {
++ .gpio_cs = 10,
++};
++
++static struct spi_board_info spi0_onboard_devs[] = {
++ {
++ .modalias = "ad7298",
++ .max_speed_hz = 5000000,
++ .platform_data = &ad7298_platform_data,
++ .mode = SPI_MODE_2,
++ .bus_num = 0,
++ .chip_select = 0,
++ .controller_data = &cln_ffrd_spi_0_cs_0,
++ }
++};
++
++static struct spi_board_info spi1_onboard_devs_gpiocs[] = {
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .controller_data = NULL,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ .controller_data = &cln_ffrd_spi_1_cs_0,
++ },
++};
++
++static struct spi_board_info spi1_onboard_devs[] = {
++ {
++ .modalias = "spidev",
++ .chip_select = 0,
++ .controller_data = NULL,
++ .max_speed_hz = 50000000,
++ .bus_num = 1,
++ },
++};
++
++/**
++ * intel_cln_spi_add_onboard_devs
++ *
++ * @return 0 on success or standard errnos on failure
++ *
++ * Registers onboard SPI device(s) present on the Kips Bay platform
++ */
++static int intel_cln_spi_add_onboard_devs(void)
++{
++ int ret = 0;
++
++ ret = spi_register_board_info(spi0_onboard_devs,
++ ARRAY_SIZE(spi0_onboard_devs));
++ if (ret)
++ return ret;
++
++ if (gpio_cs)
++ return spi_register_board_info(spi1_onboard_devs_gpiocs,
++ ARRAY_SIZE(spi1_onboard_devs_gpiocs));
++ else
++ return spi_register_board_info(spi1_onboard_devs,
++ ARRAY_SIZE(spi1_onboard_devs));
++}
++
++
++/**
++ * intel_cln_gpio_restrict_probe
++ *
++ * Make GPIOs pertaining to Firmware inaccessible by requesting them. The
++ * GPIOs are never released nor accessed by this driver.
++ */
++static int intel_cln_gpio_restrict_probe(struct platform_device *pdev)
++{
++ return intel_cln_spi_add_onboard_devs();
++}
++
++static struct platform_driver gpio_restrict_pdriver = {
++ .driver = {
++ .name = GPIO_RESTRICT_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_gpio_restrict_probe,
++};
++
++static int intel_cln_plat_kips_bay_probe(struct platform_device *pdev)
++{
++ return platform_driver_register(&gpio_restrict_pdriver);
++}
++
++static int intel_cln_plat_kips_bay_remove(struct platform_device *pdev)
++{
++ return 0;
++}
++
++static struct platform_driver cln_kips_bay_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_plat_kips_bay_probe,
++ .remove = intel_cln_plat_kips_bay_remove,
++};
++
++module_platform_driver(cln_kips_bay_driver);
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@intel.com>");
++MODULE_DESCRIPTION("Kips Bay BSP Data");
++MODULE_LICENSE("Dual BSD/GPL");
++MODULE_ALIAS("platform:"DRIVER_NAME);
++
+diff --git a/drivers/platform/x86/quark/intel_cln_sb.c b/drivers/platform/x86/quark/intel_cln_sb.c
+new file mode 100644
+index 0000000..be27d6a
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_sb.c
+@@ -0,0 +1,252 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton side-band driver
++ *
++ * Thread-safe sideband read/write routine.
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@linux.intel.com> 2012
++ */
++
++#include <linux/errno.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/spinlock.h>
++#include <linux/pci.h>
++#include "intel_cln_imr.h"
++
++#define INTEL_CLN_SB_CMD_ADDR (0x000000D0)
++#define INTEL_CLN_SB_DATA_ADDR (0x000000D4)
++
++#define INTEL_CLN_SB_MCR_SHIFT (24)
++#define INTEL_CLN_SB_PORT_SHIFT (16)
++#define INTEL_CLN_SB_REG_SHIFT (8)
++#define INTEL_CLN_SB_BYTEEN (0xF0) /* enable all 32 bits */
++
++/* Simple structure for module */
++struct intel_cln_sb_dev{
++ struct pci_dev * pdev;
++ spinlock_t slock;
++ u8 initialized;
++};
++
++static struct intel_cln_sb_dev sb_dev = {
++ .initialized = 0
++};
++
++/* Dependant drivers */
++static struct platform_device pdev [] = {
++ {
++ .name = "intel-cln-esram",
++ },
++ {
++ .name = "intel-cln-ecc",
++ },
++ {
++ .name = "intel-cln-thrm",
++ },
++};
++
++/**
++ * intel_cln_sb_read_reg
++ *
++ * @param cln_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to cln_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe read of side-band
++ * command - can be different read op-code types - which is why we don't
++ * hard-code this value directly into msg
++ */
++void intel_cln_sb_read_reg(cln_sb_id id, u8 cmd, u8 reg, u32 *data, u8 lock)
++{
++ u32 msg = (cmd << INTEL_CLN_SB_MCR_SHIFT) |
++ ((id << INTEL_CLN_SB_PORT_SHIFT) & 0xFF0000)|
++ ((reg << INTEL_CLN_SB_REG_SHIFT) & 0xFF00)|
++ INTEL_CLN_SB_BYTEEN;
++
++ if(data == NULL)
++ return;
++
++ if (likely(lock == 1)) {
++ spin_lock(&sb_dev.slock);
++ }
++
++ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_CMD_ADDR, msg);
++ pci_read_config_dword(sb_dev.pdev, INTEL_CLN_SB_DATA_ADDR, data);
++
++ if(likely(lock == 1)){
++ spin_unlock(&sb_dev.slock);
++ }
++
++}
++EXPORT_SYMBOL(intel_cln_sb_read_reg);
++
++/**
++ * intel_cln_sb_write_reg
++ *
++ * @param cln_sb_id: Sideband identifier
++ * @param command: Command to send to destination identifier
++ * @param reg: Target register w/r to cln_sb_id
++ * @return nothing
++ *
++ * Utility function to allow thread-safe write of side-band
++ */
++void intel_cln_sb_write_reg(cln_sb_id id, u8 cmd, u8 reg, u32 data, u8 lock)
++{
++ u32 msg = (cmd << INTEL_CLN_SB_MCR_SHIFT) |
++ ((id << INTEL_CLN_SB_PORT_SHIFT) & 0xFF0000)|
++ ((reg << INTEL_CLN_SB_REG_SHIFT) & 0xFF00)|
++ INTEL_CLN_SB_BYTEEN;
++
++ if(likely(lock == 1)){
++ spin_lock(&sb_dev.slock);
++ }
++
++ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_DATA_ADDR, data);
++ pci_write_config_dword(sb_dev.pdev, INTEL_CLN_SB_CMD_ADDR, msg);
++
++ if(likely(lock == 1)){
++ spin_unlock(&sb_dev.slock);
++ }
++}
++EXPORT_SYMBOL(intel_cln_sb_write_reg);
++
++/**
++ * intel_cln_sb_runfn_lock
++ *
++ * @param fn: Callback function - which requires side-band spinlock and !irq
++ * @param arg: Callback argument
++ * @return 0 on success < 0 on failure
++ *
++ * Runs the given function pointer inside of a call to the local spinlock using
++ * spin_lock_irqsave/spin_unlock_irqrestore. Needed for the eSRAMv1 driver to
++ * guarantee atomicity, but, available to any other user of sideband provided
++ * rules are respected.
++ * Rules:
++ * fn may not sleep
++ * fn may not change the state of irqs
++ */
++int intel_cln_sb_runfn_lock(int (*fn)( void * arg ), void * arg)
++{
++ unsigned long flags = 0;
++ int ret = 0;
++
++ if(unlikely(fn == NULL)){
++ return -EINVAL;
++ }
++
++ /* Get spinlock with IRQs off */
++ spin_lock_irqsave(&sb_dev.slock, flags);
++
++ /* Run function atomically */
++ ret = fn(arg);
++
++ /* Release lock */
++ spin_unlock_irqrestore(&sb_dev.slock, flags);
++
++ return ret;
++}
++EXPORT_SYMBOL(intel_cln_sb_runfn_lock);
++
++/**
++ * sb_probe
++ *
++ * @param dev: the PCI device matching
++ * @param id: entry in the match table
++ * @return 0
++ *
++ * Callback from PCI layer when dev/vendor ids match.
++ * Sets up necessary resources
++ */
++static int intel_cln_sb_probe(struct pci_dev *dev, const struct pci_device_id *id)
++{
++ int i = 0;
++
++ /* Init struct */
++ memset(&sb_dev, 0x00, sizeof(sb_dev));
++
++ /* Hook device */
++ sb_dev.pdev = dev;
++
++ /* Init locking structures */
++ spin_lock_init(&sb_dev.slock);
++
++ /* Set state */
++ sb_dev.initialized = 1;
++
++ /* Register side-band sub-ordinate drivers */
++ for (i = 0; i < sizeof(pdev)/sizeof(struct platform_device); i++){
++ /* Register side-band sub-ordinate drivers */
++ platform_device_register(&pdev[i]);
++ }
++ pr_info("Intel Clanton side-band driver registered\n");
++
++ /* Switch off boot-time IMRs nice and early */
++ return intel_cln_imr_init();
++}
++
++/**
++ * sb_remove
++ *
++ * @param pdev: PCI device
++ * @return nothing
++ *
++ * Callback from PCI sub-system upon PCI dev removal
++ */
++static void intel_cln_sb_remove(struct pci_dev *pdev)
++{
++}
++
++/* Clanton hardware */
++struct pci_device_id intel_cln_sb_ids[] = {
++ { PCI_VDEVICE(INTEL, 0x0958), 0},
++ { 0 }
++};
++
++MODULE_DEVICE_TABLE(pci, intel_cln_sb_ids);
++
++/* PCI callbacks */
++static struct pci_driver intel_cln_sb_driver = {
++ .name = "intel_cln_sb",
++ .id_table = intel_cln_sb_ids,
++ .probe = intel_cln_sb_probe,
++ .remove = intel_cln_sb_remove,
++};
++
++/**
++ * intel_cln_sb_init
++ *
++ * Module entry point
++ */
++static int __init intel_cln_sb_init(void)
++{
++ return pci_register_driver(&intel_cln_sb_driver);
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Clanton SOC side-band driver");
++MODULE_LICENSE("Dual BSD/GPL");
++
++/* Initialise early since other drivers eSRAM, DRAM ECC and thermal depend */
++subsys_initcall(intel_cln_sb_init);
+diff --git a/drivers/platform/x86/quark/intel_cln_smep_test.c b/drivers/platform/x86/quark/intel_cln_smep_test.c
+new file mode 100644
+index 0000000..16f43db
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_smep_test.c
+@@ -0,0 +1,290 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/**
++ * intel_cln_smep_test.c
++ *
++ * Simple test module to verify SMEP works as expected on MIA
++ * DO NOT RELEASE THIS FILE OUTSIDE OF CLANTON GROUP
++ * DO NOT ATTEMPT TO UPSTREAM THIS CODE - YOU WILL BE PUBLICLY EMBARRSSED !
++ *
++ * Author : Bryan O'Donoghue <bryan.odonoghue@intel.com>
++ *
++ */
++#include <asm/processor.h>
++#include <asm/processor-flags.h>
++#include <linux/cdev.h>
++#include <linux/crc16.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/fs.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/printk.h>
++#include <linux/slab.h>
++
++#define DRIVER_NAME "intel_cln_smep_test"
++
++/**
++ * struct intel_cln_smep_dev
++ *
++ * Structre to represent module state/data/etc
++ */
++struct intel_cln_smep_test_dev{
++ unsigned int opened;
++ struct platform_device *pldev; /* Platform device */
++ struct cdev cdev;
++ struct mutex open_lock;
++ char * pdata;
++ u32 size;
++};
++
++static struct intel_cln_smep_test_dev smep_test_dev;
++static struct class *smep_test_class;
++static DEFINE_MUTEX(smep_test_mutex);
++static int smep_test_major;
++static char * name = "testmap";
++
++/**
++ * smep_test_ioctl
++ *
++ * Allows user-space to command kernel switch SMEP on/off
++ */
++static long smep_test_ioctl(struct file *file, unsigned int cmd,
++ unsigned long arg)
++{
++ int cr4 = 0;
++
++ cr4 = read_cr4();
++ printk(KERN_INFO "%s entry CR4 is 0x%08x\n", __FUNCTION__, cr4);
++
++ switch(cmd){
++ case 0:
++ printk(KERN_INFO "Switching SMEP off\n");
++ cr4 &= ~X86_CR4_SMEP;
++
++ break;
++ case 1:
++ printk(KERN_INFO "Switching SMEP on\n");
++ cr4 |= X86_CR4_SMEP;
++ break;
++ default:
++ return -EINVAL;
++ }
++ /* Latch value */
++ write_cr4(cr4);
++
++ /* Print contents of CR4 */
++ cr4 = read_cr4();
++ printk(KERN_INFO "%s exit CR4 is 0x%08x\n", __FUNCTION__, cr4);
++
++ return 0;
++}
++
++/**
++ * smep_test_write
++ *
++ * Accepts a buffer from user-space and then tries to execute the contents
++ * Be very careful
++ */
++static ssize_t smep_test_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *ppos)
++{
++ /*
++ * We assume we are passed a pointer to function of type
++ * void fn(void)
++ */
++ void (*fn)(void) = (void(*))buf;
++ if (count) {
++ printk(KERN_INFO "Will attempt exec %d bytes of ring3 code @ 0x%p\n",
++ count, buf);
++ fn();
++ printk(KERN_INFO "Exec of data @ 0x%p complete\n", buf);
++ }
++ return count;
++}
++
++static int smep_test_open(struct inode *inode, struct file *file)
++{
++ mutex_lock(&smep_test_mutex);
++ nonseekable_open(inode, file);
++
++ if (mutex_lock_interruptible(&smep_test_dev.open_lock)) {
++ mutex_unlock(&smep_test_mutex);
++ return -ERESTARTSYS;
++ }
++
++ if (smep_test_dev.opened) {
++ mutex_unlock(&smep_test_dev.open_lock);
++ mutex_unlock(&smep_test_mutex);
++ return -EINVAL;
++ }
++
++ smep_test_dev.opened++;
++ mutex_unlock(&smep_test_dev.open_lock);
++ mutex_unlock(&smep_test_mutex);
++ return 0;
++}
++
++static int smep_test_release(struct inode *inode, struct file *file)
++{
++ mutex_lock(&smep_test_dev.open_lock);
++ smep_test_dev.opened = 0;
++ mutex_unlock(&smep_test_dev.open_lock);
++
++ return 0;
++}
++
++
++
++static const struct file_operations smep_test_file_ops = {
++ .open = smep_test_open,
++ .release = smep_test_release,
++ .unlocked_ioctl = smep_test_ioctl,
++ .write = smep_test_write,
++ .llseek = no_llseek,
++};
++
++
++/**
++ * intel_cln_smep_test_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This driver manages eSRAM on a per-page basis. Therefore if we find block
++ * mode is enabled, or any global, block-level or page-level locks are in place
++ * at module initialisation time - we bail out.
++ */
++static int intel_cln_smep_test_probe(struct platform_device * pdev)
++{
++ int retval = 0;
++ unsigned int minor = 0;
++
++ mutex_init(&smep_test_dev.open_lock);
++ cdev_init(&smep_test_dev.cdev, &smep_test_file_ops);
++ smep_test_dev.cdev.owner = THIS_MODULE;
++
++ retval = cdev_add(&smep_test_dev.cdev, MKDEV(smep_test_major, minor), 1);
++ if (retval) {
++ printk(KERN_ERR "chardev registration failed\n");
++ return -EINVAL;
++ }
++ if (IS_ERR(device_create(smep_test_class, NULL,
++ MKDEV(smep_test_major, minor), NULL,
++ "smeptest%u", minor))){
++ dev_err(&pdev->dev, "can't create device\n");
++ return -EINVAL;
++ }
++ printk(KERN_INFO "%s complete OK - device /dev/smeptest%u\n", __FUNCTION__, minor);
++ return 0;
++
++}
++
++/**
++ * intel_cln_smep_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_cln_smep_test_remove(struct platform_device * pdev)
++{
++ unsigned int minor = MINOR(smep_test_dev.cdev.dev);
++
++ device_destroy(smep_test_class, MKDEV(smep_test_major, minor));
++ cdev_del(&smep_test_dev.cdev);
++
++ return 0;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_smep_test_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .remove = intel_cln_smep_test_remove,
++};
++
++/**
++ * intel_cln_smep_init
++ *
++ * @return 0 success < 0 failure
++ *
++ * Module entry point
++ */
++static int __init intel_cln_smep_test_init(void)
++{
++ int retval = 0;
++ dev_t dev;
++
++ smep_test_class = class_create(THIS_MODULE,"cln_smep_test");
++ if (IS_ERR(smep_test_class)) {
++ retval = PTR_ERR(smep_test_class);
++ printk(KERN_ERR "smep_test: can't register earam_test class\n");
++ goto err;
++ }
++
++ retval = alloc_chrdev_region(&dev, 0, 1, "smep_test");
++ if (retval) {
++ printk(KERN_ERR "smep_test: can't register character device\n");
++ goto err_class;
++ }
++ smep_test_major = MAJOR(dev);
++
++ memset(&smep_test_dev, 0x00, sizeof(smep_test_dev));
++ smep_test_dev.pldev = platform_create_bundle(
++ &intel_cln_smep_test_driver, intel_cln_smep_test_probe, NULL, 0, NULL, 0);
++
++ if(IS_ERR(smep_test_dev.pldev)){
++ printk(KERN_ERR "smep_test platform_create_bundle fail!\n");
++ retval = PTR_ERR(smep_test_dev.pldev);
++ goto err_class;
++ }
++
++ return 0;
++
++err_class:
++ class_destroy(smep_test_class);
++err:
++ return retval;
++}
++
++/**
++ * intel_cln_smep_exit
++ *
++ * Module exit
++ */
++static void __exit intel_cln_smep_test_exit(void)
++{
++ platform_device_unregister(smep_test_dev.pldev);
++ platform_driver_unregister(&intel_cln_smep_test_driver);
++}
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Clanton SMEP test");
++MODULE_LICENSE("Dual BSD/GPL");
++
++module_init(intel_cln_smep_test_init);
++module_exit(intel_cln_smep_test_exit);
+diff --git a/drivers/platform/x86/quark/intel_cln_thermal.c b/drivers/platform/x86/quark/intel_cln_thermal.c
+new file mode 100644
+index 0000000..ce0da9cd
+--- /dev/null
++++ b/drivers/platform/x86/quark/intel_cln_thermal.c
+@@ -0,0 +1,360 @@
++/*
++ * Copyright(c) 2013 Intel Corporation. All rights reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License 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 St - Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Contact Information:
++ * Intel Corporation
++ */
++/*
++ * Intel Clanton Thermal driver
++ */
++#include <linux/err.h>
++#include <linux/fs.h>
++#include <linux/intel_cln_sb.h>
++#include <linux/list.h>
++#include <linux/mm.h>
++#include <linux/module.h>
++#include <linux/printk.h>
++#include <linux/platform_device.h>
++#include <linux/pm.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/thermal.h>
++#include <linux/timer.h>
++
++#define DRIVER_NAME "intel-cln-thrm"
++
++/* Definition of register locations for thermal management */
++#define THRM_CTRL_REG (0x80) /* Thermal control */
++#define THRM_MODE_REG (0xB0) /* Thermal mode */
++#define THRM_MODE_SENSOR_EN (0x00008000) /* Thermal mode sensor enable */
++#define THRM_TEMP_REG (0xB1) /* Thermal sensor temperature */
++#define THRM_TRPCLR_REG (0xB2) /* Catastropic/Hot trip/clear */
++#define THRM_AUXTRP_REG (0xB3) /* Aux0-Aux3 trip point */
++#define THRM_AUXCLR_REG (0xB4) /* Aux0-Aux3 clear trip */
++#define THRM_STATUS_REG (0xB5) /* Thermal sensor status */
++#define THRM_TRIPBEHAVE_REG (0xB6) /* Trip point behavior */
++#define THRM_MSIADDR_REG (0xC5) /* Thermal MSI addres reg */
++#define THRM_MSIDATA_REG (0xC6) /* Thermal MSI data reg */
++#define THRM_CTRL_READ (0x10) /* Config reg */
++#define THRM_CTRL_WRITE (0x11) /* Config reg */
++
++#define SOC_TSENSOR_REG (0x34)
++#define SOC_TSENSOR_RST (0x00000001)
++#define SOC_CTRL_READ (0x06)
++#define SOC_CTRL_WRITE (0x07)
++
++
++#define THRM_ZONE_COUNT 2 /* Only hot/critical relevant */
++#define ACTIVE_INTERVAL (1000)
++#define IDLE_INTERVAL (20000)
++#define MCELSIUS(x) ((x) * 1000)
++
++/* CPU Zone information */
++#define CATASTROPIC_ZONE 0
++#define HOT_ZONE 1
++#define AUX0_ZONE 2 /* Unused */
++#define AUX1_ZONE 3 /* Unused */
++#define AUX2_ZONE 4 /* Unused */
++#define AUX3_ZONE 5 /* Unused */
++#define MIN_USED_ZONE CATASTROPIC_ZONE
++#define MAX_USED_ZONE HOT_ZONE
++/*
++ * Default catastrophic/hot trip values - in degrees celsius
++ * Maximum temperature is 105 degrees
++ */
++#define CRIT_TEMP 104
++#define HOT_TEMP 95
++#define RAW2CELSIUS_DIFF 50
++
++static int driver_enable = 1;
++module_param(driver_enable, int, S_IRUGO | S_IWUSR);
++MODULE_PARM_DESC(driver_enable, "Disable Thermal Driver Polling");
++
++/* Shorten fn names to fit 80 char limit */
++#ifndef sb_read
++#define sb_read intel_cln_sb_read_reg
++#endif
++#ifndef sb_write
++#define sb_write intel_cln_sb_write_reg
++#endif
++
++struct intel_cln_therm_zone {
++ enum thermal_trip_type type;
++ int trip_value;
++};
++
++/**
++ * struct intel_cln_thermal_dev
++ *
++ */
++struct intel_cln_thermal_dev {
++ enum thermal_device_mode mode;
++ struct intel_cln_therm_zone tzone[THRM_ZONE_COUNT];
++ struct mutex lock;
++ struct platform_device *pldev; /* Platform device */
++ struct thermal_zone_device *therm_dev; /* Thermal device */
++};
++
++static struct intel_cln_thermal_dev cln_tdev;
++
++/******************************************************************************
++ * Thermal API implementation
++ ******************************************************************************/
++
++/**
++ * get_temp
++ *
++ * @param tz: Thermal zone descriptor
++ *
++ * Get the current temperature
++ * We have exactly one thermal zone/sensor
++ * Value passed is an unsigned long - our sensor reports up to -50 celsius so we
++ * just clip at zero if the temperature is negative.
++ */
++static int intel_cln_thermal_get_temp(struct thermal_zone_device *tz,
++ unsigned long *temp)
++{
++ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TEMP_REG, (u32 *)temp, 1);
++ *temp -= RAW2CELSIUS_DIFF;
++
++ /* Clip to unsigned output value if sensor is reporting sub-zero */
++ if ((int)*temp < 0)
++ *temp = 0;
++
++ *temp = MCELSIUS(*temp&0x000000FF);
++
++ return 0;
++}
++
++/**
++ * get_trend
++ *
++ * Wears good clothes
++ */
++static int intel_cln_thermal_get_trend(struct thermal_zone_device *tz,
++ int trip, enum thermal_trend *trend)
++{
++ if (tz->temperature >= trip)
++ *trend = THERMAL_TREND_RAISING;
++ else
++ *trend = THERMAL_TREND_DROPPING;
++
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_get_mode
++ *
++ * Get the mode
++ */
++static int intel_cln_thermal_get_mode(struct thermal_zone_device *tz,
++ enum thermal_device_mode *mode)
++{
++ mutex_lock(&cln_tdev.lock);
++ *mode = cln_tdev.mode;
++ mutex_unlock(&cln_tdev.lock);
++
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_set_mode
++ *
++ * Set the mode
++ */
++static int intel_cln_thermal_set_mode(struct thermal_zone_device *tz,
++ enum thermal_device_mode mode)
++{
++ mutex_lock(&cln_tdev.lock);
++
++ if (mode == THERMAL_DEVICE_ENABLED)
++ cln_tdev.therm_dev->polling_delay = IDLE_INTERVAL;
++ else
++ cln_tdev.therm_dev->polling_delay = 0;
++ cln_tdev.mode = mode;
++
++ mutex_unlock(&cln_tdev.lock);
++
++ thermal_zone_device_update(cln_tdev.therm_dev);
++ pr_info("thermal polling set for duration=%d msec\n",
++ cln_tdev.therm_dev->polling_delay);
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_get_trip_type
++ *
++ * Get trip type
++ */
++static int intel_cln_thermal_get_trip_type(struct thermal_zone_device *tz,
++ int trip, enum thermal_trip_type *type)
++{
++ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
++ return -EINVAL;
++
++ *type = cln_tdev.tzone[trip].type;
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_get_trip_temp
++ *
++ * Get trip temp
++ */
++static int intel_cln_thermal_get_trip_temp(struct thermal_zone_device *tz,
++ int trip, unsigned long *temp)
++{
++ if (trip < MIN_USED_ZONE || trip > MAX_USED_ZONE)
++ return -EINVAL;
++
++ /* Convert the temperature into millicelsius */
++ *temp = cln_tdev.tzone[trip].trip_value;
++
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_get_trip_type
++ *
++ * Get trip temp
++ */
++static int intel_cln_thermal_get_crit_temp(struct thermal_zone_device *tz,
++ unsigned long *temp)
++{
++ /* Critical zone */
++ *temp = cln_tdev.tzone[CATASTROPIC_ZONE].trip_value;
++ return 0;
++}
++
++static struct thermal_zone_device_ops intel_cln_thrm_dev_ops = {
++ .get_temp = intel_cln_thermal_get_temp,
++ .get_trend = intel_cln_thermal_get_trend,
++ .get_mode = intel_cln_thermal_get_mode,
++ .set_mode = intel_cln_thermal_set_mode,
++ .get_trip_type = intel_cln_thermal_get_trip_type,
++ .get_trip_temp = intel_cln_thermal_get_trip_temp,
++ .get_crit_temp = intel_cln_thermal_get_crit_temp,
++};
++
++
++
++/**
++ * intel_cln_init_zone
++ *
++ * Initialise a zone
++ */
++static void intel_cln_thermal_init_zone(struct intel_cln_therm_zone *tz,
++ enum thermal_trip_type type, int trip_value)
++{
++ tz->type = type;
++ tz->trip_value = MCELSIUS(trip_value);
++}
++
++/******************************************************************************
++ * Module Entry/Exit hooks
++ ******************************************************************************/
++
++/**
++ * intel_cln_thermal_probe
++ *
++ * @param pdev: Platform device
++ * @return 0 success < 0 failure
++ *
++ * Callback from platform sub-system to probe
++ *
++ * This routine registers a thermal device with the kernel's thermal management
++ * sub-system
++ */
++static int intel_cln_thermal_probe(struct platform_device *pdev)
++{
++ int err = 0;
++ int critical_temp = 0, hot_temp = 0;
++ uint32_t regval = 0;
++
++ if (driver_enable == 0)
++ return 0;
++
++ memset(&cln_tdev, 0x00, sizeof(cln_tdev));
++
++ critical_temp = CRIT_TEMP;
++ hot_temp = HOT_TEMP;
++
++ /* Enumerate zone type data */
++ memset(&cln_tdev, 0x00, sizeof(cln_tdev));
++ mutex_init(&cln_tdev.lock);
++
++ /* Set initial state disabled */
++ cln_tdev.mode = THERMAL_DEVICE_ENABLED;
++
++ intel_cln_thermal_init_zone(&cln_tdev.tzone[CATASTROPIC_ZONE],
++ THERMAL_TRIP_CRITICAL, critical_temp);
++ intel_cln_thermal_init_zone(&cln_tdev.tzone[HOT_ZONE],
++ THERMAL_TRIP_HOT, hot_temp);
++
++ /* Register a thermal zone */
++ cln_tdev.therm_dev = thermal_zone_device_register(DRIVER_NAME,
++ THRM_ZONE_COUNT, 0, 0, &intel_cln_thrm_dev_ops,
++ 0, IDLE_INTERVAL, ACTIVE_INTERVAL);
++
++ if (IS_ERR(cln_tdev.therm_dev)) {
++ err = PTR_ERR(cln_tdev.therm_dev);
++ return err;
++ }
++
++ /* Read the BIOS configured hardware catastrophic trip temp */
++ sb_read(SB_ID_THERMAL, THRM_CTRL_READ, THRM_TRPCLR_REG, &regval, 1);
++ regval = (regval & 0xff) - 50;
++
++ pr_info("THRM: critical reset %d c hot %d c hardware failover %d c\n",
++ critical_temp, hot_temp, regval);
++
++ return 0;
++}
++
++/**
++ * intel_cln_thermal_remove
++ *
++ * @return 0 success < 0 failure
++ *
++ * Removes a platform device
++ */
++static int intel_cln_thermal_remove(struct platform_device *pdev)
++{
++ if (cln_tdev.therm_dev != NULL) {
++ thermal_zone_device_unregister(cln_tdev.therm_dev);
++ return 0;
++ }
++ return -EINVAL;
++}
++
++/*
++ * Platform structures useful for interface to PM subsystem
++ */
++static struct platform_driver intel_cln_thermal_driver = {
++ .driver = {
++ .name = DRIVER_NAME,
++ .owner = THIS_MODULE,
++ },
++ .probe = intel_cln_thermal_probe,
++ .remove = intel_cln_thermal_remove,
++};
++
++module_platform_driver(intel_cln_thermal_driver);
++
++
++MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linux.intel.com>");
++MODULE_DESCRIPTION("Intel Clanton Thermal driver");
++MODULE_LICENSE("Dual BSD/GPL");
+diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
+index 8a7cfb3..5deac43 100644
+--- a/drivers/power/power_supply_core.c
++++ b/drivers/power/power_supply_core.c
+@@ -141,7 +141,7 @@ int power_supply_set_battery_charged(struct power_supply *psy)
+ }
+ EXPORT_SYMBOL_GPL(power_supply_set_battery_charged);
+
+-static int power_supply_match_device_by_name(struct device *dev, void *data)
++static int power_supply_match_device_by_name(struct device *dev, const void *data)
+ {
+ const char *name = data;
+ struct power_supply *psy = dev_get_drvdata(dev);
+@@ -149,7 +149,7 @@ static int power_supply_match_device_by_name(struct device *dev, void *data)
+ return strcmp(psy->name, name) == 0;
+ }
+
+-struct power_supply *power_supply_get_by_name(char *name)
++struct power_supply *power_supply_get_by_name(const char *name)
+ {
+ struct device *dev = class_find_device(power_supply_class, NULL, name,
+ power_supply_match_device_by_name);
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index e513cd9..03120a8 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -28,6 +28,10 @@ menuconfig PWM
+
+ if PWM
+
++config PWM_SYSFS
++ bool
++ default y if SYSFS
++
+ config PWM_AB8500
+ tristate "AB8500 PWM support"
+ depends on AB8500_CORE && ARCH_U8500
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index 62a2963..f98371b 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -1,4 +1,5 @@
+ obj-$(CONFIG_PWM) += core.o
++obj-$(CONFIG_PWM_SYSFS) += sysfs.o
+ obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o
+ obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
+ obj-$(CONFIG_PWM_IMX) += pwm-imx.o
+diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
+index 903138b..bfc8c05 100644
+--- a/drivers/pwm/core.c
++++ b/drivers/pwm/core.c
+@@ -272,6 +272,8 @@ int pwmchip_add(struct pwm_chip *chip)
+ if (IS_ENABLED(CONFIG_OF))
+ of_pwmchip_add(chip);
+
++ pwmchip_sysfs_export(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -308,6 +310,8 @@ int pwmchip_remove(struct pwm_chip *chip)
+
+ free_pwms(chip);
+
++ pwmchip_sysfs_unexport(chip);
++
+ out:
+ mutex_unlock(&pwm_lock);
+ return ret;
+@@ -400,10 +404,19 @@ EXPORT_SYMBOL_GPL(pwm_free);