aboutsummaryrefslogtreecommitdiffstats
path: root/target
diff options
context:
space:
mode:
authorZoltan HERPAI <wigyori@uid0.hu>2014-08-27 12:09:46 +0000
committerZoltan HERPAI <wigyori@uid0.hu>2014-08-27 12:09:46 +0000
commitd0d3be5d8287ff737cfe4381c44706f1d8f7b881 (patch)
treeab287cf326cc235e7ee9161a13b57f4bd0fecc5b /target
parent6e912a1e62ebb1ab2fdd3f63bff61936be65a84b (diff)
downloadmaster-187ad058-d0d3be5d8287ff737cfe4381c44706f1d8f7b881.tar.gz
master-187ad058-d0d3be5d8287ff737cfe4381c44706f1d8f7b881.tar.bz2
master-187ad058-d0d3be5d8287ff737cfe4381c44706f1d8f7b881.zip
sunxi: initial 3.14 patchset
Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@42313 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target')
-rw-r--r--target/linux/sunxi/config-3.14461
-rw-r--r--target/linux/sunxi/patches-3.14/100-dt-sun4i-add-missing-serial-aliases.patch33
-rw-r--r--target/linux/sunxi/patches-3.14/101-dt-sun6i-add-missing-serial-aliases.patch37
-rw-r--r--target/linux/sunxi/patches-3.14/102-dt-sun7i-add-missing-serial-aliases.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/103-dt-sun5i-add-missing-serial-aliases.patch32
-rw-r--r--target/linux/sunxi/patches-3.14/104-dt-sun7i-add-pinmuxing-for-uart2.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/105-dt-sun4i-add-linksprite-pcduino.patch86
-rw-r--r--target/linux/sunxi/patches-3.14/106-dt-sun7i-add-arch-timer-node.patch36
-rw-r--r--target/linux/sunxi/patches-3.14/107-dt-sun4i-add-a10-lime.patch149
-rw-r--r--target/linux/sunxi/patches-3.14/110-dt-sun6i-add-pll-and-spi-modclocks.patch82
-rw-r--r--target/linux/sunxi/patches-3.14/111-dt-sun4i-rename-clocknodes.patch139
-rw-r--r--target/linux/sunxi/patches-3.14/112-dt-sun5i-rename-clocknodes.patch261
-rw-r--r--target/linux/sunxi/patches-3.14/113-dt-sun6i-rename-clocknodes.patch112
-rw-r--r--target/linux/sunxi/patches-3.14/114-dt-sun7i-rename-clocknodes.patch132
-rw-r--r--target/linux/sunxi/patches-3.14/115-dt-sun6i-fix-mod0-compat.patch56
-rw-r--r--target/linux/sunxi/patches-3.14/120-dt-sun7i-add-gmac-clocknode.patch56
-rw-r--r--target/linux/sunxi/patches-3.14/121-dt-sun7i-add-gmac-ctrlnode.patch39
-rw-r--r--target/linux/sunxi/patches-3.14/122-dt-sun7i-add-pinmuxing-for-gmac.patch53
-rw-r--r--target/linux/sunxi/patches-3.14/123-dt-sun7i-cubietruck-enable-gmac.patch38
-rw-r--r--target/linux/sunxi/patches-3.14/124-dt-sun7i-cubieboard2-enable-gmac.patch61
-rw-r--r--target/linux/sunxi/patches-3.14/125-dt-sun7i-olinuxinom-enable-gmac.patch62
-rw-r--r--target/linux/sunxi/patches-3.14/126-dt-sun7i-add-eth-alias-for-gmac.patch31
-rw-r--r--target/linux/sunxi/patches-3.14/130-dt-sun4i-add-usbclock-bindings.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/131-dt-sun5i-add-usbclock-bindings.patch56
-rw-r--r--target/linux/sunxi/patches-3.14/132-dt-sun7i-add-usbclock-bindings.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/135-pinctrl-fixes.patch101
-rw-r--r--target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch415
-rw-r--r--target/linux/sunxi/patches-3.14/137-1-pinctrl-create-irq-pin-mapping.patch41
-rw-r--r--target/linux/sunxi/patches-3.14/137-2-pinctrl-add-IRQCHIP_SKIP_SET_WAKE.patch31
-rw-r--r--target/linux/sunxi/patches-3.14/137-3-dt-sun7i-add-interrupt-cells.patch31
-rw-r--r--target/linux/sunxi/patches-3.14/140-dt-sunxi-convert-to-new-clock-compats.patch1030
-rw-r--r--target/linux/sunxi/patches-3.14/141-dt-sunxi-add-common-regulator-include.patch103
-rw-r--r--target/linux/sunxi/patches-3.14/145-1-dt-sun7i-add-a20-spi.patch78
-rw-r--r--target/linux/sunxi/patches-3.14/145-2-dt-sun4i-add-a10-spi.patch77
-rw-r--r--target/linux/sunxi/patches-3.14/145-3-dt-sun5i-add-a13-spi.patch60
-rw-r--r--target/linux/sunxi/patches-3.14/146-1-spi-add-a31-spi.patch572
-rw-r--r--target/linux/sunxi/patches-3.14/146-2-spi-add-a10-spi.patch571
-rw-r--r--target/linux/sunxi/patches-3.14/147-sun6i-enable-spi-in-defconfig.patch34
-rw-r--r--target/linux/sunxi/patches-3.14/148-dt-sun7i-add-spi-muxing.patch38
-rw-r--r--target/linux/sunxi/patches-3.14/149-dt-sun7i-add-spi-on-olinuxinom.patch46
-rw-r--r--target/linux/sunxi/patches-3.14/150-dt-sun4i-add-ahci.patch87
-rw-r--r--target/linux/sunxi/patches-3.14/151-dt-sun7i-add-ahci.patch147
-rw-r--r--target/linux/sunxi/patches-3.14/155-wdt-add-new-compats.patch53
-rw-r--r--target/linux/sunxi/patches-3.14/156-dt-sunxi-update-wdt-compats.patch86
-rw-r--r--target/linux/sunxi/patches-3.14/160-dt-sun4i-add-usb-host-bindings.patch86
-rw-r--r--target/linux/sunxi/patches-3.14/161-dt-sun5i-add-usb-host-bindings.patch62
-rw-r--r--target/linux/sunxi/patches-3.14/162-dt-sun7i-add-usb-host-bindings.patch86
-rw-r--r--target/linux/sunxi/patches-3.14/163-dt-sun4i-add-usb-host-to-boards.patch295
-rw-r--r--target/linux/sunxi/patches-3.14/164-dt-sun5i-add-usb-host-to-boards.patch143
-rw-r--r--target/linux/sunxi/patches-3.14/165-dt-sun7i-add-usb-host-to-boards.patch201
-rw-r--r--target/linux/sunxi/patches-3.14/170-input-add-sun4i-ts-driver.patch354
-rw-r--r--target/linux/sunxi/patches-3.14/171-input-add-temp-sensor-support.patch264
-rw-r--r--target/linux/sunxi/patches-3.14/172-input-add-lradc-keys-driver.patch339
-rw-r--r--target/linux/sunxi/patches-3.14/173-1-dt-sun4i-add-lradc-node.patch31
-rw-r--r--target/linux/sunxi/patches-3.14/173-2-dt-sun5i-add-lradc-node.patch64
-rw-r--r--target/linux/sunxi/patches-3.14/173-3-dt-sun7i-add-lradc-node.patch59
-rw-r--r--target/linux/sunxi/patches-3.14/175-reset-add-of_reset_control_get.patch119
-rw-r--r--target/linux/sunxi/patches-3.14/176-clk-sun5i-add-support-for-reset-ctrler.patch69
-rw-r--r--target/linux/sunxi/patches-3.14/180-clk-sunxi-add-clock-output-names-dt-prop-support.patch55
-rw-r--r--target/linux/sunxi/patches-3.14/181-clk-sunxi-add-names-for-pll56.patch83
-rw-r--r--target/linux/sunxi/patches-3.14/182-clk-sunxi-add-support-for-usb-clockreg-reset.patch133
-rw-r--r--target/linux/sunxi/patches-3.14/182-clk-sunxi-get-divs-parent-clockname.patch45
-rw-r--r--target/linux/sunxi/patches-3.14/183-clk-sunxi-add-usb-clockreg-defs.patch76
-rw-r--r--target/linux/sunxi/patches-3.14/184-clk-sunxi-add-pll6-on-a31.patch111
-rw-r--r--target/linux/sunxi/patches-3.14/185-clk-sunxi-add-a20-a31-gmac-clock.patch182
-rw-r--r--target/linux/sunxi/patches-3.14/186-clk-sunxi-add-new-clock-compats.patch187
-rw-r--r--target/linux/sunxi/patches-3.14/187-clk-sunxi-automatic-reparenting.patch73
-rw-r--r--target/linux/sunxi/patches-3.14/188-clk-sunxi-implement-mmc-phasectrl.patch95
-rw-r--r--target/linux/sunxi/patches-3.14/190-ahci-libahci-changes.patch1361
-rw-r--r--target/linux/sunxi/patches-3.14/191-ahci-add-sunxi-driver.patch352
-rw-r--r--target/linux/sunxi/patches-3.14/192-ahci-platform-changes.patch305
-rw-r--r--target/linux/sunxi/patches-3.14/195-1-ohci-plat-changes.patch471
-rw-r--r--target/linux/sunxi/patches-3.14/195-2-ehci-plat-changes.patch552
-rw-r--r--target/linux/sunxi/patches-3.14/195-3-uhci-plat-changes.patch83
-rw-r--r--target/linux/sunxi/patches-3.14/195-4-xhci-plat-changes.patch56
-rw-r--r--target/linux/sunxi/patches-3.14/196-usb-add-sunxi-phy-driver.patch423
-rw-r--r--target/linux/sunxi/patches-3.14/200-mmc-add-driver.patch1163
-rw-r--r--target/linux/sunxi/patches-3.14/201-dt-sun4i-add-mmc-nodes_NEED_REFRESH.patch195
-rw-r--r--target/linux/sunxi/patches-3.14/202-dt-sun5i-add-mmc-nodes.patch138
-rw-r--r--target/linux/sunxi/patches-3.14/203-dt-sun7i-add-mmc-nodes.patch182
-rw-r--r--target/linux/sunxi/patches-3.14/205-nmi-add-driver.patch247
-rw-r--r--target/linux/sunxi/patches-3.14/206-dt-sun67i-add-nmi-irqchip.patch54
-rw-r--r--target/linux/sunxi/patches-3.14/210-mfd-add-axp20x-pmic-driver.patch517
-rw-r--r--target/linux/sunxi/patches-3.14/211-input-add-axp20x-power-enable-key-support.patch339
-rw-r--r--target/linux/sunxi/patches-3.14/212-regulator-add-axp20x-regulator-support.patch414
-rw-r--r--target/linux/sunxi/patches-3.14/213-dt-sunxi-add-x-powers.patch83
-rw-r--r--target/linux/sunxi/patches-3.14/214-1-dt-sun7i-add-axp209-to-cubieboard2.patch40
-rw-r--r--target/linux/sunxi/patches-3.14/214-2-dt-sun4i-add-axp209-to-boards.patch159
-rw-r--r--target/linux/sunxi/patches-3.14/214-3-dt-sun7i-add-axp209-to-cubietruck.patch56
-rw-r--r--target/linux/sunxi/patches-3.14/215-2-dt-sun5i-add-address-and-sizecells-to-i2c.patch45
-rw-r--r--target/linux/sunxi/patches-3.14/215-3-dt-sun7i-add-address-and-sizecells-to-i2c.patch63
-rw-r--r--target/linux/sunxi/patches-3.14/215-dt-sun4i-add-address-and-sizecells-to-i2c.patch45
-rw-r--r--target/linux/sunxi/patches-3.14/216-dt-sun7i-add-i2c-to-cubietruck.patch48
-rw-r--r--target/linux/sunxi/patches-3.14/220-clk-sunxi-remove-calls-to-clk_put.patch41
-rw-r--r--target/linux/sunxi/patches-3.14/230-net-rfkill-changes.patch271
-rw-r--r--target/linux/sunxi/patches-3.14/231-1-brcmfmac-fix-sdio-sending.patch37
-rw-r--r--target/linux/sunxi/patches-3.14/231-2-brcmfmac-fix-use-of-skb-ctrlbuf-in-SDIO.patch69
-rw-r--r--target/linux/sunxi/patches-3.14/232-1-dt-sun7i-add-wifi-to-cubietruck.patch96
-rw-r--r--target/linux/sunxi/patches-3.14/232-2-dt-sun7i-add-bluetooth-to-cubietruck.patch78
-rw-r--r--target/linux/sunxi/patches-3.14/250-pwm-add-driver.patch376
-rw-r--r--target/linux/sunxi/patches-3.14/251-1-dt-sun4i-add-pinmux-for-pwm.patch41
-rw-r--r--target/linux/sunxi/patches-3.14/251-2-dt-sun7i-add-pinmux-for-pwm.patch41
-rw-r--r--target/linux/sunxi/patches-3.14/252-1-dt-sun4i-add-pwm-support.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/252-2-dt-sun7i-add-pwm-support.patch35
-rw-r--r--target/linux/sunxi/patches-3.14/260-dt-sun7i-enable-arm-pmu.patch33
-rw-r--r--target/linux/sunxi/patches-3.14/270-dt-sun7i-add-ss-to-a20.patch23
-rw-r--r--target/linux/sunxi/patches-3.14/271-crypto-add-ss.patch1264
-rw-r--r--target/linux/sunxi/patches-3.14/300-dt-sun7i-add-pcduino3.patch47
-rw-r--r--target/linux/sunxi/patches-3.14/301-dt-sun7i-update-pcduino3.patch13
-rw-r--r--target/linux/sunxi/patches-3.14/302-dt-sun7i-add-bananapi-Makefile.patch11
-rw-r--r--target/linux/sunxi/patches-3.14/303-dt-sun7i-update-bananapi.patch13
111 files changed, 18880 insertions, 0 deletions
diff --git a/target/linux/sunxi/config-3.14 b/target/linux/sunxi/config-3.14
new file mode 100644
index 0000000000..7534814397
--- /dev/null
+++ b/target/linux/sunxi/config-3.14
@@ -0,0 +1,461 @@
+CONFIG_AHCI_SUNXI=y
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_APM_EMULATION is not set
+CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_RESET_CONTROLLER=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+# CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED is not set
+CONFIG_ARCH_NR_GPIO=288
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUNXI=y
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARM=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_ARM_ATAG_DTB_COMPAT=y
+# CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND is not set
+CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
+# CONFIG_ARM_CPU_SUSPEND is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_720789=y
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_NR_BANKS=8
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+CONFIG_ARM_PSCI=y
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATA=y
+CONFIG_ATAGS=y
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_AUDIT_GENERIC=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_AVERAGE=y
+CONFIG_BINFMT_MISC=y
+CONFIG_BLK_CGROUP=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_BOUNCE=y
+# CONFIG_CACHE_L2X0 is not set
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_FREEZER=y
+# CONFIG_CGROUP_NET_CLASSID is not set
+# CONFIG_CGROUP_PERF is not set
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="console=ttyS0,115200 earlyprintk rootwait root=/dev/mmcblk0p2"
+CONFIG_CMDLINE_FORCE=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMPACTION=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_CONNECTOR=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_COREDUMP=y
+CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=y
+CONFIG_CPUSETS=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRC_T10DIF=y
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_CRC32C=y
+CONFIG_CRYPTO_CRCT10DIF=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_DEV_SUNXI_SS=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_HW=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_DCACHE_WORD_ACCESS=y
+# CONFIG_DEBUG_BLK_CGROUP is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_UART_8250 is not set
+# CONFIG_DEBUG_UART_PL01X is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_LZ4=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_DECOMPRESS_XZ=y
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_DIRECT_IO=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_OF=y
+CONFIG_DNOTIFY=y
+CONFIG_DTC=y
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_DWMAC_SUNXI=y
+# CONFIG_DW_DMAC_CORE is not set
+CONFIG_DYNAMIC_DEBUG=y
+# CONFIG_EEPROM_SUNXI_SID is not set
+CONFIG_ELF_CORE=y
+# CONFIG_EMBEDDED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_EXPERT is not set
+CONFIG_EXT4_FS=y
+CONFIG_FRAME_POINTER=y
+CONFIG_FRAME_WARN=2048
+CONFIG_FREEZER=y
+CONFIG_FS_MBCACHE=y
+CONFIG_FS_POSIX_ACL=y
+CONFIG_GARP=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_NET_UTILS=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PHY=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_DEVRES=y
+# CONFIG_HAMRADIO is not set
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_HW_BREAKPOINT=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_HWMON=y
+CONFIG_HW_CONSOLE=y
+CONFIG_HZ_FIXED=0
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_MUX=y
+# CONFIG_I2C_MUX_GPIO is not set
+# CONFIG_I2C_MUX_PCA9541 is not set
+# CONFIG_I2C_MUX_PCA954x is not set
+CONFIG_I2C_MUX_PINCTRL=y
+CONFIG_I2C_MV64XXX=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_INPUT=y
+CONFIG_INPUT_AXP20X_PEK=y
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_IPC_NS=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_BOOTP is not set
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_RARP is not set
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_JBD2=y
+CONFIG_KALLSYMS=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_XZ is not set
+CONFIG_KSM=y
+CONFIG_KTIME_SCALAR=y
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_REGULATOR is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_LOG_BUF_SHIFT=19
+CONFIG_LZ4_DECOMPRESS=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MDIO_SUN4I=y
+# CONFIG_MEMCG is not set
+CONFIG_MFD_AXP20X=y
+CONFIG_MFD_CORE=y
+CONFIG_MIGRATION=y
+CONFIG_MMC=y
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_SUNXI=y
+CONFIG_MMC_UNSAFE_RESUME=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NAMESPACES=y
+CONFIG_NEED_DMA_MAP_STATE=y
+# CONFIG_NEON is not set
+# CONFIG_NET_CLS_CGROUP is not set
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NET_NS=y
+CONFIG_NET_RX_BUSY_POLL=y
+CONFIG_NET_VENDOR_ALLWINNER=y
+CONFIG_NLS=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NO_HZ=y
+CONFIG_NO_HZ_COMMON=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_NR_CPUS=4
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PARTITION_ADVANCED is not set
+# CONFIG_PCI_SYSCALL is not set
+CONFIG_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PHYLIB=y
+CONFIG_PHY_SUN4I_USB=y
+CONFIG_PID_NS=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_SINGLE is not set
+CONFIG_PINCTRL_SUNXI=y
+CONFIG_PM=y
+CONFIG_PM_CLK=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_RUNTIME=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_PPS=y
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_COUNT=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_RCU=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_PROC_DEVICETREE=y
+CONFIG_PROC_EVENTS=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_PROC_PID_CPUSET=y
+CONFIG_PTP_1588_CLOCK=y
+CONFIG_PWM=y
+CONFIG_PWM_SUNXI=y
+CONFIG_PWM_SYSFS=y
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
+CONFIG_QUOTA=y
+CONFIG_QUOTACTL=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_RCU_BOOST is not set
+CONFIG_RCU_CPU_STALL_VERBOSE=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_GZIP=y
+CONFIG_RD_LZ4=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+CONFIG_RD_XZ=y
+CONFIG_REGMAP=y
+CONFIG_REGMAP_I2C=y
+CONFIG_REGMAP_IRQ=y
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_AXP20X is not set
+# CONFIG_REGULATOR_DEBUG is not set
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+CONFIG_RELAY=y
+CONFIG_RESET_CONTROLLER=y
+CONFIG_RESOURCE_COUNTERS=y
+# CONFIG_RFKILL_REGULATOR is not set
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_SATA_AHCI_PLATFORM=y
+CONFIG_SCHED_HRTICK=y
+CONFIG_SCSI=y
+CONFIG_SECURITYFS=y
+CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_SYSRQ=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_APBPS2 is not set
+# CONFIG_SERIO_OLPC_APSP is not set
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+CONFIG_SLUB_CPU_PARTIAL=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLUB_DEBUG_ON is not set
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+CONFIG_SPI_SUN4I=y
+CONFIG_SPI_SUN6I=y
+# CONFIG_STAGING is not set
+# CONFIG_STMMAC_DA is not set
+# CONFIG_STMMAC_DEBUG_FS is not set
+CONFIG_STMMAC_ETH=y
+CONFIG_STMMAC_PLATFORM=y
+CONFIG_STOP_MACHINE=y
+CONFIG_STRICT_DEVMEM=y
+# CONFIG_SUN4I_EMAC is not set
+CONFIG_SUN4I_TIMER=y
+CONFIG_SUN5I_HSTIMER=y
+CONFIG_SUNXI_WATCHDOG=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_TASK_XACCT=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set
+# CONFIG_TOUCHSCREEN_AUO_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_BU21013 is not set
+# CONFIG_TOUCHSCREEN_CYTTSP4_CORE is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_EGALAX is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_MAX11801 is not set
+# CONFIG_TOUCHSCREEN_PIXCIR is not set
+# CONFIG_TOUCHSCREEN_ST1232 is not set
+CONFIG_TOUCHSCREEN_SUN4I=y
+# CONFIG_TOUCHSCREEN_TSC2005 is not set
+# CONFIG_TOUCHSCREEN_TSC_SERIO is not set
+CONFIG_TREE_PREEMPT_RCU=y
+CONFIG_UEVENT_HELPER_PATH=""
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_UNINLINE_SPIN_UNLOCK=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_COMMON=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_SUPPORT=y
+# CONFIG_USER_NS is not set
+CONFIG_USE_OF=y
+CONFIG_UTS_NS=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_VFP=y
+CONFIG_VFPv3=y
+CONFIG_VLAN_8021Q_GVRP=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+CONFIG_WATCHDOG_CORE=y
+# CONFIG_XEN is not set
+CONFIG_XFRM_ALGO=y
+CONFIG_XFRM_USER=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM_TEXT=0
+# CONFIG_ZBUD is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/sunxi/patches-3.14/100-dt-sun4i-add-missing-serial-aliases.patch b/target/linux/sunxi/patches-3.14/100-dt-sun4i-add-missing-serial-aliases.patch
new file mode 100644
index 0000000000..5048f8500a
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/100-dt-sun4i-add-missing-serial-aliases.patch
@@ -0,0 +1,33 @@
+From b25983b215e889447ae670a158b1af5e7f253091 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 2 Jan 2014 22:05:04 +0100
+Subject: [PATCH] ARM: sun4i: a10: Add missing serial aliases
+
+Some UART aliases have been defined, but not all of them. Add the remaining
+ones to be consistent and to ease the parsing of the DT by the bootloaders.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index d4d2763..64fc716 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -19,6 +19,12 @@
+ ethernet0 = &emac;
+ serial0 = &uart0;
+ serial1 = &uart1;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ serial5 = &uart5;
++ serial6 = &uart6;
++ serial7 = &uart7;
+ };
+
+ cpus {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/101-dt-sun6i-add-missing-serial-aliases.patch b/target/linux/sunxi/patches-3.14/101-dt-sun6i-add-missing-serial-aliases.patch
new file mode 100644
index 0000000000..e2ba3c19ea
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/101-dt-sun6i-add-missing-serial-aliases.patch
@@ -0,0 +1,37 @@
+From b6e3460ee25b8af673d00df0435a304f5dbf7c40 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 2 Jan 2014 22:05:04 +0100
+Subject: [PATCH] ARM: sun6i: Add missing serial aliases
+
+Some UART aliases have been defined, but not all of them. Add the remaining
+ones to be consistent and to ease the parsing of the DT by the bootloaders.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun6i-a31.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index 5256ad9..092bf97 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -16,6 +16,16 @@
+ / {
+ interrupt-parent = <&gic>;
+
++ aliases {
++ serial0 = &uart0;
++ serial1 = &uart1;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ serial5 = &uart5;
++ };
++
++
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/102-dt-sun7i-add-missing-serial-aliases.patch b/target/linux/sunxi/patches-3.14/102-dt-sun7i-add-missing-serial-aliases.patch
new file mode 100644
index 0000000000..a979036411
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/102-dt-sun7i-add-missing-serial-aliases.patch
@@ -0,0 +1,35 @@
+From 1070f51b55d11e8831317d718acf2af46a181311 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 2 Jan 2014 22:05:04 +0100
+Subject: [PATCH] ARM: sun7i: Add missing serial aliases
+
+Some UART aliases have been defined, but not all of them. Add the remaining
+ones to be consistent and to ease the parsing of the DT by the bootloaders.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 6f25cf5..0b6e610 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -18,6 +18,14 @@
+
+ aliases {
+ ethernet0 = &emac;
++ serial0 = &uart0;
++ serial1 = &uart1;
++ serial2 = &uart2;
++ serial3 = &uart3;
++ serial4 = &uart4;
++ serial5 = &uart5;
++ serial6 = &uart6;
++ serial7 = &uart7;
+ };
+
+ cpus {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/103-dt-sun5i-add-missing-serial-aliases.patch b/target/linux/sunxi/patches-3.14/103-dt-sun5i-add-missing-serial-aliases.patch
new file mode 100644
index 0000000000..c262dfe99c
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/103-dt-sun5i-add-missing-serial-aliases.patch
@@ -0,0 +1,32 @@
+From 0ffac463caf4b0022cf0d917552d51b3ec82849a Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Mon, 13 Jan 2014 11:08:47 +0100
+Subject: [PATCH] ARM: sun5i: a13: Add missing serial aliases
+
+Some UART aliases have been defined, but not all of them. Add the remaining
+ones to be consistent and to ease the parsing of the DT by the bootloaders.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun5i-a13.dtsi | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index c463fd7..d8207b0 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -16,6 +16,11 @@
+ / {
+ interrupt-parent = <&intc>;
+
++ aliases {
++ serial0 = &uart1;
++ serial1 = &uart3;
++ };
++
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/104-dt-sun7i-add-pinmuxing-for-uart2.patch b/target/linux/sunxi/patches-3.14/104-dt-sun7i-add-pinmuxing-for-uart2.patch
new file mode 100644
index 0000000000..cd343285e3
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/104-dt-sun7i-add-pinmuxing-for-uart2.patch
@@ -0,0 +1,35 @@
+From 875f2d579db0c3ea113f6367af9ccb32b3dbebcc Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Tue, 14 Jan 2014 22:49:50 +0800
+Subject: [PATCH] ARM: dts: sun7i: add pin muxing options for UART2
+
+UART2 is used on CubieTruck to connect to the Bluetooth module.
+Add the pin set used in this case.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 0b6e610..2139e0f 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -381,6 +381,13 @@
+ allwinner,pull = <0>;
+ };
+
++ uart2_pins_a: uart2@0 {
++ allwinner,pins = "PI16", "PI17", "PI18", "PI19";
++ allwinner,function = "uart2";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
+ uart6_pins_a: uart6@0 {
+ allwinner,pins = "PI12", "PI13";
+ allwinner,function = "uart6";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/105-dt-sun4i-add-linksprite-pcduino.patch b/target/linux/sunxi/patches-3.14/105-dt-sun4i-add-linksprite-pcduino.patch
new file mode 100644
index 0000000000..713c922501
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/105-dt-sun4i-add-linksprite-pcduino.patch
@@ -0,0 +1,86 @@
+From 2fc6dcd5e7c76c203d2e174e70ef21393a231163 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Mon, 13 Jan 2014 14:15:01 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add basic board support for LinkSprite
+ pcDuino
+
+This patch will add a basic board support DT for the
+LinkSprite pcDuino board.
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/sun4i-a10-pcduino.dts | 48 +++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+ create mode 100644 arch/arm/boot/dts/sun4i-a10-pcduino.dts
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 0320303..8e1d636 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -284,6 +284,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
+ sun4i-a10-cubieboard.dtb \
+ sun4i-a10-mini-xplus.dtb \
+ sun4i-a10-hackberry.dtb \
++ sun4i-a10-pcduino.dtb \
+ sun5i-a10s-olinuxino-micro.dtb \
+ sun5i-a13-olinuxino.dtb \
+ sun5i-a13-olinuxino-micro.dtb \
+diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+new file mode 100644
+index 0000000..f5692a3
+--- /dev/null
++++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+@@ -0,0 +1,48 @@
++/*
++ * Copyright 2014 Zoltan HERPAI
++ * Zoltan HERPAI <wigyori@uid0.hu>
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/dts-v1/;
++/include/ "sun4i-a10.dtsi"
++
++/ {
++ model = "LinkSprite pcDuino";
++ compatible = "linksprite,a10-pcduino", "allwinner,sun4i-a10";
++
++ soc@01c00000 {
++ emac: ethernet@01c0b000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&emac_pins_a>;
++ phy = <&phy1>;
++ status = "okay";
++ };
++
++ mdio@01c0b080 {
++ status = "okay";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
++
++ uart0: serial@01c28000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins_a>;
++ status = "okay";
++ };
++
++ i2c0: i2c@01c2ac00 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins_a>;
++ status = "okay";
++ };
++ };
++};
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/106-dt-sun7i-add-arch-timer-node.patch b/target/linux/sunxi/patches-3.14/106-dt-sun7i-add-arch-timer-node.patch
new file mode 100644
index 0000000000..4ded898bbf
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/106-dt-sun7i-add-arch-timer-node.patch
@@ -0,0 +1,36 @@
+From 0f9bb2cf6171f47d932df46e34cc5cfce384ff3d Mon Sep 17 00:00:00 2001
+From: Marc Zyngier <marc.zyngier@arm.com>
+Date: Tue, 18 Feb 2014 14:04:44 +0000
+Subject: [PATCH] ARM: sun7i: add arch timer node
+
+The Allwinner A20 SoC is built around a pair of Cortex-A7 cores,
+which have the usual generic timers. Report this in the DT.
+
+Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 822a816..911d4e4 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -49,6 +49,14 @@
+ reg = <0x40000000 0x80000000>;
+ };
+
++ timer {
++ compatible = "arm,armv7-timer";
++ interrupts = <1 13 0xf08>,
++ <1 14 0xf08>,
++ <1 11 0xf08>,
++ <1 10 0xf08>;
++ };
++
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/107-dt-sun4i-add-a10-lime.patch b/target/linux/sunxi/patches-3.14/107-dt-sun4i-add-a10-lime.patch
new file mode 100644
index 0000000000..c6f9edbf18
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/107-dt-sun4i-add-a10-lime.patch
@@ -0,0 +1,149 @@
+From a1c70ed831e4d5356618834202b0da3aa34e218e Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 10 Jan 2014 23:23:06 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add support for the A10-OLinuXino-LIME board
+
+This add support for the A10-OLinuXino-LIME:
+https://www.olimex.com/Products/OLinuXino/A10/A10-OLinuXino-LIME
+
+A low cost Allwinner A10 based dev-board, with sata, ethernet, hdmi and 2x USB.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 111 +++++++++++++++++++++++++
+ 2 files changed, 112 insertions(+)
+ create mode 100644 arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 8e1d636..66d6df3 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -284,6 +284,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
+ sun4i-a10-cubieboard.dtb \
+ sun4i-a10-mini-xplus.dtb \
+ sun4i-a10-hackberry.dtb \
++ sun4i-a10-olinuxino-lime.dtb \
+ sun4i-a10-pcduino.dtb \
+ sun5i-a10s-olinuxino-micro.dtb \
+ sun5i-a13-olinuxino.dtb \
+diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+new file mode 100644
+index 0000000..66cf0c7
+--- /dev/null
++++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+@@ -0,0 +1,111 @@
++/*
++ * Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/dts-v1/;
++/include/ "sun4i-a10.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
++
++/ {
++ model = "Olimex A10-OLinuXino-LIME";
++ compatible = "olimex,a10-olinuxino-lime", "allwinner,sun4i-a10";
++
++ soc@01c00000 {
++ emac: ethernet@01c0b000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&emac_pins_a>;
++ phy = <&phy1>;
++ status = "okay";
++ };
++
++ mdio@01c0b080 {
++ status = "okay";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
++
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
++ ahci: sata@01c18000 {
++ target-supply = <&reg_ahci_5v>;
++ status = "okay";
++ };
++
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
++ pinctrl@01c20800 {
++ ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
++ allwinner,pins = "PC3";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ led_pins_olinuxinolime: led_pins@0 {
++ allwinner,pins = "PH2";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <1>;
++ allwinner,pull = <0>;
++ };
++ };
++
++ uart0: serial@01c28000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart0_pins_a>;
++ status = "okay";
++ };
++ };
++
++ leds {
++ compatible = "gpio-leds";
++ pinctrl-names = "default";
++ pinctrl-0 = <&led_pins_olinuxinolime>;
++
++ green {
++ label = "a10-olinuxino-lime:green:usr";
++ gpios = <&pio 7 2 0>;
++ default-state = "on";
++ };
++ };
++
++ reg_ahci_5v: ahci-5v {
++ pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
++ gpio = <&pio 2 3 0>;
++ status = "okay";
++ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
++};
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/110-dt-sun6i-add-pll-and-spi-modclocks.patch b/target/linux/sunxi/patches-3.14/110-dt-sun6i-add-pll-and-spi-modclocks.patch
new file mode 100644
index 0000000000..75c0bd84ce
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/110-dt-sun6i-add-pll-and-spi-modclocks.patch
@@ -0,0 +1,82 @@
+From 7f94ebf35b017f1664e957857a7f36752e2577cd Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Wed, 5 Feb 2014 14:05:04 +0100
+Subject: [PATCH] ARM: sun6i: dt: Add PLL6 and SPI module clocks
+
+The module clocks in the A31 are still compatible with the A10 one. Add the SPI
+module clocks and the PLL6 in the device tree to allow their use by the SPI
+controllers.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun6i-a31.dtsi | 46 ++++++++++++++++++++++++++++++++--------
+ 1 file changed, 37 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index 092bf97..93d7bb6 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -83,16 +83,12 @@
+ clocks = <&osc24M>;
+ };
+
+- /*
+- * This is a dummy clock, to be used as placeholder on
+- * other mux clocks when a specific parent clock is not
+- * yet implemented. It should be dropped when the driver
+- * is complete.
+- */
+- pll6: pll6 {
++ pll6: clk@01c20028 {
+ #clock-cells = <0>;
+- compatible = "fixed-clock";
+- clock-frequency = <0>;
++ compatible = "allwinner,sun6i-a31-pll6-clk";
++ reg = <0x01c20028 0x4>;
++ clocks = <&osc24M>;
++ clock-output-names = "pll6";
+ };
+
+ cpu: cpu@01c20050 {
+@@ -192,6 +188,38 @@
+ "apb2_uart1", "apb2_uart2", "apb2_uart3",
+ "apb2_uart4", "apb2_uart5";
+ };
++
++ spi0_clk: clk@01c200a0 {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun4i-mod0-clk";
++ reg = <0x01c200a0 0x4>;
++ clocks = <&osc24M>, <&pll6>;
++ clock-output-names = "spi0";
++ };
++
++ spi1_clk: clk@01c200a4 {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun4i-mod0-clk";
++ reg = <0x01c200a4 0x4>;
++ clocks = <&osc24M>, <&pll6>;
++ clock-output-names = "spi1";
++ };
++
++ spi2_clk: clk@01c200a8 {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun4i-mod0-clk";
++ reg = <0x01c200a8 0x4>;
++ clocks = <&osc24M>, <&pll6>;
++ clock-output-names = "spi2";
++ };
++
++ spi3_clk: clk@01c200ac {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun4i-mod0-clk";
++ reg = <0x01c200ac 0x4>;
++ clocks = <&osc24M>, <&pll6>;
++ clock-output-names = "spi3";
++ };
+ };
+
+ soc@01c00000 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/111-dt-sun4i-rename-clocknodes.patch b/target/linux/sunxi/patches-3.14/111-dt-sun4i-rename-clocknodes.patch
new file mode 100644
index 0000000000..51280b55d2
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/111-dt-sun4i-rename-clocknodes.patch
@@ -0,0 +1,139 @@
+From 35b7dfc295f4d6079572a22a225c7444134e1f72 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:41 +0800
+Subject: [PATCH] ARM: dts: sun4i: rename clock node names to clk@N
+
+Device tree naming conventions state that node names should match
+node function. Change fully functioning clock nodes to match and
+add clock-output-names to all sunxi clock nodes.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 30 ++++++++++++++++++++----------
+ 1 file changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 64fc716..132b261 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -58,34 +58,38 @@
+ clock-frequency = <0>;
+ };
+
+- osc24M: osc24M@01c20050 {
++ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
++ clock-output-names = "osc24M";
+ };
+
+- osc32k: osc32k {
++ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
++ clock-output-names = "osc32k";
+ };
+
+- pll1: pll1@01c20000 {
++ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll1";
+ };
+
+- pll4: pll4@01c20018 {
++ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll4";
+ };
+
+- pll5: pll5@01c20020 {
++ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll5-clk";
+ reg = <0x01c20020 0x4>;
+@@ -93,7 +97,7 @@
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+- pll6: pll6@01c20028 {
++ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll6-clk";
+ reg = <0x01c20028 0x4>;
+@@ -107,6 +111,7 @@
+ compatible = "allwinner,sun4i-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
++ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+@@ -114,9 +119,10 @@
+ compatible = "allwinner,sun4i-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
++ clock-output-names = "axi";
+ };
+
+- axi_gates: axi_gates@01c2005c {
++ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+@@ -129,9 +135,10 @@
+ compatible = "allwinner,sun4i-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
++ clock-output-names = "ahb";
+ };
+
+- ahb_gates: ahb_gates@01c20060 {
++ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+@@ -154,9 +161,10 @@
+ compatible = "allwinner,sun4i-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
++ clock-output-names = "apb0";
+ };
+
+- apb0_gates: apb0_gates@01c20068 {
++ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-apb0-gates-clk";
+ reg = <0x01c20068 0x4>;
+@@ -171,6 +179,7 @@
+ compatible = "allwinner,sun4i-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
++ clock-output-names = "apb1_mux";
+ };
+
+ apb1: apb1@01c20058 {
+@@ -178,9 +187,10 @@
+ compatible = "allwinner,sun4i-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
++ clock-output-names = "apb1";
+ };
+
+- apb1_gates: apb1_gates@01c2006c {
++ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-apb1-gates-clk";
+ reg = <0x01c2006c 0x4>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/112-dt-sun5i-rename-clocknodes.patch b/target/linux/sunxi/patches-3.14/112-dt-sun5i-rename-clocknodes.patch
new file mode 100644
index 0000000000..4ed1f2d59e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/112-dt-sun5i-rename-clocknodes.patch
@@ -0,0 +1,261 @@
+From 266f79cef78cdf3545065a4786506eee0ae012b3 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:42 +0800
+Subject: [PATCH] ARM: dts: sun5i: rename clock node names to clk@N
+
+Device tree naming conventions state that node names should match
+node function. Change fully functioning clock nodes to match and
+add clock-output-names to all sunxi clock nodes.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 30 ++++++++++++++++++++----------
+ arch/arm/boot/dts/sun5i-a13.dtsi | 30 ++++++++++++++++++++----------
+ 2 files changed, 40 insertions(+), 20 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index 848baaa..99a5120 100644
+--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
+@@ -51,34 +51,38 @@
+ clock-frequency = <0>;
+ };
+
+- osc24M: osc24M@01c20050 {
++ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
++ clock-output-names = "osc24M";
+ };
+
+- osc32k: osc32k {
++ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
++ clock-output-names = "osc32k";
+ };
+
+- pll1: pll1@01c20000 {
++ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll1";
+ };
+
+- pll4: pll4@01c20018 {
++ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll4";
+ };
+
+- pll5: pll5@01c20020 {
++ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll5-clk";
+ reg = <0x01c20020 0x4>;
+@@ -86,7 +90,7 @@
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+- pll6: pll6@01c20028 {
++ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll6-clk";
+ reg = <0x01c20028 0x4>;
+@@ -100,6 +104,7 @@
+ compatible = "allwinner,sun4i-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
++ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+@@ -107,9 +112,10 @@
+ compatible = "allwinner,sun4i-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
++ clock-output-names = "axi";
+ };
+
+- axi_gates: axi_gates@01c2005c {
++ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+@@ -122,9 +128,10 @@
+ compatible = "allwinner,sun4i-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
++ clock-output-names = "ahb";
+ };
+
+- ahb_gates: ahb_gates@01c20060 {
++ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a10s-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+@@ -143,9 +150,10 @@
+ compatible = "allwinner,sun4i-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
++ clock-output-names = "apb0";
+ };
+
+- apb0_gates: apb0_gates@01c20068 {
++ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a10s-apb0-gates-clk";
+ reg = <0x01c20068 0x4>;
+@@ -159,6 +167,7 @@
+ compatible = "allwinner,sun4i-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
++ clock-output-names = "apb1_mux";
+ };
+
+ apb1: apb1@01c20058 {
+@@ -166,9 +175,10 @@
+ compatible = "allwinner,sun4i-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
++ clock-output-names = "apb1";
+ };
+
+- apb1_gates: apb1_gates@01c2006c {
++ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a10s-apb1-gates-clk";
+ reg = <0x01c2006c 0x4>;
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index d8207b0..b776baa 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -52,34 +52,38 @@
+ clock-frequency = <0>;
+ };
+
+- osc24M: osc24M@01c20050 {
++ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
++ clock-output-names = "osc24M";
+ };
+
+- osc32k: osc32k {
++ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
++ clock-output-names = "osc32k";
+ };
+
+- pll1: pll1@01c20000 {
++ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll1";
+ };
+
+- pll4: pll4@01c20018 {
++ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll4";
+ };
+
+- pll5: pll5@01c20020 {
++ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll5-clk";
+ reg = <0x01c20020 0x4>;
+@@ -87,7 +91,7 @@
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+- pll6: pll6@01c20028 {
++ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll6-clk";
+ reg = <0x01c20028 0x4>;
+@@ -101,6 +105,7 @@
+ compatible = "allwinner,sun4i-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
++ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+@@ -108,9 +113,10 @@
+ compatible = "allwinner,sun4i-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
++ clock-output-names = "axi";
+ };
+
+- axi_gates: axi_gates@01c2005c {
++ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+@@ -123,9 +129,10 @@
+ compatible = "allwinner,sun4i-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
++ clock-output-names = "ahb";
+ };
+
+- ahb_gates: ahb_gates@01c20060 {
++ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+@@ -143,9 +150,10 @@
+ compatible = "allwinner,sun4i-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
++ clock-output-names = "apb0";
+ };
+
+- apb0_gates: apb0_gates@01c20068 {
++ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-apb0-gates-clk";
+ reg = <0x01c20068 0x4>;
+@@ -158,6 +166,7 @@
+ compatible = "allwinner,sun4i-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
++ clock-output-names = "apb1_mux";
+ };
+
+ apb1: apb1@01c20058 {
+@@ -165,9 +174,10 @@
+ compatible = "allwinner,sun4i-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
++ clock-output-names = "apb1";
+ };
+
+- apb1_gates: apb1_gates@01c2006c {
++ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-apb1-gates-clk";
+ reg = <0x01c2006c 0x4>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/113-dt-sun6i-rename-clocknodes.patch b/target/linux/sunxi/patches-3.14/113-dt-sun6i-rename-clocknodes.patch
new file mode 100644
index 0000000000..56c0208b0a
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/113-dt-sun6i-rename-clocknodes.patch
@@ -0,0 +1,112 @@
+From 8bd1bb3a670aae791c4b2e9ab13c92768233368a Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:43 +0800
+Subject: [PATCH] ARM: dts: sun6i: rename clock node names to clk@N
+
+Device tree naming conventions state that node names should match
+node function. Change fully functioning clock nodes to match and
+add clock-output-names to all sunxi clock nodes.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun6i-a31.dtsi | 19 ++++++++++++++-----
+ 1 file changed, 14 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index fc07f70..d3f1995 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -70,17 +70,19 @@
+ clock-frequency = <24000000>;
+ };
+
+- osc32k: osc32k {
++ osc32k: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
++ clock-output-names = "osc32k";
+ };
+
+- pll1: pll1@01c20000 {
++ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun6i-a31-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll1";
+ };
+
+ pll6: clk@01c20028 {
+@@ -103,6 +105,7 @@
+ * Allwinner.
+ */
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
++ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20050 {
+@@ -110,6 +113,7 @@
+ compatible = "allwinner,sun4i-axi-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&cpu>;
++ clock-output-names = "axi";
+ };
+
+ ahb1_mux: ahb1_mux@01c20054 {
+@@ -117,6 +121,7 @@
+ compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
++ clock-output-names = "ahb1_mux";
+ };
+
+ ahb1: ahb1@01c20054 {
+@@ -124,9 +129,10 @@
+ compatible = "allwinner,sun4i-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1_mux>;
++ clock-output-names = "ahb1";
+ };
+
+- ahb1_gates: ahb1_gates@01c20060 {
++ ahb1_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun6i-a31-ahb1-gates-clk";
+ reg = <0x01c20060 0x8>;
+@@ -152,9 +158,10 @@
+ compatible = "allwinner,sun4i-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1>;
++ clock-output-names = "apb1";
+ };
+
+- apb1_gates: apb1_gates@01c20060 {
++ apb1_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun6i-a31-apb1-gates-clk";
+ reg = <0x01c20068 0x4>;
+@@ -169,6 +176,7 @@
+ compatible = "allwinner,sun4i-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
++ clock-output-names = "apb2_mux";
+ };
+
+ apb2: apb2@01c20058 {
+@@ -176,9 +184,10 @@
+ compatible = "allwinner,sun6i-a31-apb2-div-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb2_mux>;
++ clock-output-names = "apb2";
+ };
+
+- apb2_gates: apb2_gates@01c2006c {
++ apb2_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun6i-a31-apb2-gates-clk";
+ reg = <0x01c2006c 0x4>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/114-dt-sun7i-rename-clocknodes.patch b/target/linux/sunxi/patches-3.14/114-dt-sun7i-rename-clocknodes.patch
new file mode 100644
index 0000000000..a1786fc89e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/114-dt-sun7i-rename-clocknodes.patch
@@ -0,0 +1,132 @@
+From c57b781689bba48dad635caf005962cc9c8e5e3d Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:44 +0800
+Subject: [PATCH] ARM: dts: sun7i: rename clock node names to clk@N
+
+Device tree naming conventions state that node names should match
+node function. Change fully functioning clock nodes to match and
+add clock-output-names to all sunxi clock nodes.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 25 +++++++++++++++++--------
+ 1 file changed, 17 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 2139e0f..78f562a 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -54,11 +54,12 @@
+ #size-cells = <1>;
+ ranges;
+
+- osc24M: osc24M@01c20050 {
++ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
++ clock-output-names = "osc24M";
+ };
+
+ osc32k: clk@0 {
+@@ -68,21 +69,23 @@
+ clock-output-names = "osc32k";
+ };
+
+- pll1: pll1@01c20000 {
++ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll1";
+ };
+
+- pll4: pll4@01c20018 {
++ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
++ clock-output-names = "pll4";
+ };
+
+- pll5: pll5@01c20020 {
++ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll5-clk";
+ reg = <0x01c20020 0x4>;
+@@ -90,7 +93,7 @@
+ clock-output-names = "pll5_ddr", "pll5_other";
+ };
+
+- pll6: pll6@01c20028 {
++ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-pll6-clk";
+ reg = <0x01c20028 0x4>;
+@@ -103,6 +106,7 @@
+ compatible = "allwinner,sun4i-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6 1>;
++ clock-output-names = "cpu";
+ };
+
+ axi: axi@01c20054 {
+@@ -110,6 +114,7 @@
+ compatible = "allwinner,sun4i-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
++ clock-output-names = "axi";
+ };
+
+ ahb: ahb@01c20054 {
+@@ -117,9 +122,10 @@
+ compatible = "allwinner,sun4i-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
++ clock-output-names = "ahb";
+ };
+
+- ahb_gates: ahb_gates@01c20060 {
++ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun7i-a20-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+@@ -144,9 +150,10 @@
+ compatible = "allwinner,sun4i-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
++ clock-output-names = "apb0";
+ };
+
+- apb0_gates: apb0_gates@01c20068 {
++ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun7i-a20-apb0-gates-clk";
+ reg = <0x01c20068 0x4>;
+@@ -162,6 +169,7 @@
+ compatible = "allwinner,sun4i-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
++ clock-output-names = "apb1_mux";
+ };
+
+ apb1: apb1@01c20058 {
+@@ -169,9 +177,10 @@
+ compatible = "allwinner,sun4i-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
++ clock-output-names = "apb1";
+ };
+
+- apb1_gates: apb1_gates@01c2006c {
++ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun7i-a20-apb1-gates-clk";
+ reg = <0x01c2006c 0x4>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/115-dt-sun6i-fix-mod0-compat.patch b/target/linux/sunxi/patches-3.14/115-dt-sun6i-fix-mod0-compat.patch
new file mode 100644
index 0000000000..6b14459100
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/115-dt-sun6i-fix-mod0-compat.patch
@@ -0,0 +1,56 @@
+From 95c1fe603fbea0fd01d98262bd5ff7d5442a86db Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Mon, 24 Feb 2014 17:29:06 +0100
+Subject: [PATCH] ARM: sun6i: dt: Fix mod0 compatible
+
+The module 0 clock compatibles were changed between the time the patch was sent
+and it was merged. Update the compatibles.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun6i-a31.dtsi | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index af6f87c..42f310a 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -200,7 +200,7 @@
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi0";
+@@ -208,7 +208,7 @@
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi1";
+@@ -216,7 +216,7 @@
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi2";
+@@ -224,7 +224,7 @@
+
+ spi3_clk: clk@01c200ac {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200ac 0x4>;
+ clocks = <&osc24M>, <&pll6>;
+ clock-output-names = "spi3";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/120-dt-sun7i-add-gmac-clocknode.patch b/target/linux/sunxi/patches-3.14/120-dt-sun7i-add-gmac-clocknode.patch
new file mode 100644
index 0000000000..47dab70c69
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/120-dt-sun7i-add-gmac-clocknode.patch
@@ -0,0 +1,56 @@
+From 3e1660161aacc5aeeebb09a0c8d91ad01399e5cd Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:48 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add GMAC clock node to sun7i DTSI
+
+The GMAC uses 1 of 2 sources for its transmit clock, depending on the
+PHY interface mode. Add both sources as dummy clocks, and as parents
+to the GMAC clock node.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 78f562a..f6ae357 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -322,6 +322,34 @@
+ };
+
+ /*
++ * The following two are dummy clocks, placeholders used in the gmac_tx
++ * clock. The gmac driver will choose one parent depending on the PHY
++ * interface mode, using clk_set_rate auto-reparenting.
++ * The actual TX clock rate is not controlled by the gmac_tx clock.
++ */
++ mii_phy_tx_clk: clk@2 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <25000000>;
++ clock-output-names = "mii_phy_tx";
++ };
++
++ gmac_int_tx_clk: clk@3 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <125000000>;
++ clock-output-names = "gmac_int_tx";
++ };
++
++ gmac_tx_clk: clk@01c20164 {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun7i-a20-gmac-clk";
++ reg = <0x01c20164 0x4>;
++ clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
++ clock-output-names = "gmac_tx";
++ };
++
++ /*
+ * Dummy clock used by output clocks
+ */
+ osc24M_32k: clk@1 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/121-dt-sun7i-add-gmac-ctrlnode.patch b/target/linux/sunxi/patches-3.14/121-dt-sun7i-add-gmac-ctrlnode.patch
new file mode 100644
index 0000000000..bf2d384325
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/121-dt-sun7i-add-gmac-ctrlnode.patch
@@ -0,0 +1,39 @@
+From 22b9ac16c600694b12479a75461bce031295e4b9 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:49 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add GMAC controller node to sun7i DTSI
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index f6ae357..fa489fe 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -645,6 +645,21 @@
+ status = "disabled";
+ };
+
++ gmac: ethernet@01c50000 {
++ compatible = "allwinner,sun7i-a20-gmac";
++ reg = <0x01c50000 0x10000>;
++ interrupts = <0 85 4>;
++ interrupt-names = "macirq";
++ clocks = <&ahb_gates 49>, <&gmac_tx_clk>;
++ clock-names = "stmmaceth", "allwinner_gmac_tx";
++ snps,pbl = <2>;
++ snps,fixed-burst;
++ snps,force_sf_dma_mode;
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ hstimer@01c60000 {
+ compatible = "allwinner,sun7i-a20-hstimer";
+ reg = <0x01c60000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/122-dt-sun7i-add-pinmuxing-for-gmac.patch b/target/linux/sunxi/patches-3.14/122-dt-sun7i-add-pinmuxing-for-gmac.patch
new file mode 100644
index 0000000000..7fa7b9c898
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/122-dt-sun7i-add-pinmuxing-for-gmac.patch
@@ -0,0 +1,53 @@
+From 9f6deb688f4cb733cd3f36e0cc88f14d2f81982d Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:50 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add pin muxing options for the GMAC
+
+The A20 has EMAC and GMAC muxed on the same pins.
+Add pin sets with gmac function for MII and RGMII mode to the DTSI.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 26 ++++++++++++++++++++++++++
+ 1 file changed, 26 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index fa489fe..679dc50 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -484,6 +484,32 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ gmac_pins_mii_a: gmac_mii@0 {
++ allwinner,pins = "PA0", "PA1", "PA2",
++ "PA3", "PA4", "PA5", "PA6",
++ "PA7", "PA8", "PA9", "PA10",
++ "PA11", "PA12", "PA13", "PA14",
++ "PA15", "PA16";
++ allwinner,function = "gmac";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ gmac_pins_rgmii_a: gmac_rgmii@0 {
++ allwinner,pins = "PA0", "PA1", "PA2",
++ "PA3", "PA4", "PA5", "PA6",
++ "PA7", "PA8", "PA10",
++ "PA11", "PA12", "PA13",
++ "PA15", "PA16";
++ allwinner,function = "gmac";
++ /*
++ * data lines in RGMII mode use DDR mode
++ * and need a higher signal drive strength
++ */
++ allwinner,drive = <3>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ timer@01c20c00 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/123-dt-sun7i-cubietruck-enable-gmac.patch b/target/linux/sunxi/patches-3.14/123-dt-sun7i-cubietruck-enable-gmac.patch
new file mode 100644
index 0000000000..4bc4a76ab5
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/123-dt-sun7i-cubietruck-enable-gmac.patch
@@ -0,0 +1,38 @@
+From d09483e1cfcc00be70450c469c3c23496a063d98 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:51 +0800
+Subject: [PATCH] ARM: dts: sun7i: cubietruck: Enable the GMAC
+
+The CubieTruck uses the GMAC with an RGMII phy.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index f9dcb61..025ce52 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -51,6 +51,18 @@
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
++
++ gmac: ethernet@01c50000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&gmac_pins_rgmii_a>;
++ phy = <&phy1>;
++ phy-mode = "rgmii";
++ status = "okay";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
+ };
+
+ leds {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/124-dt-sun7i-cubieboard2-enable-gmac.patch b/target/linux/sunxi/patches-3.14/124-dt-sun7i-cubieboard2-enable-gmac.patch
new file mode 100644
index 0000000000..511606466d
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/124-dt-sun7i-cubieboard2-enable-gmac.patch
@@ -0,0 +1,61 @@
+From 856cae07bff4d7e7a111affd4f15803142d29880 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:52 +0800
+Subject: [PATCH] ARM: dts: sun7i: cubieboard2: Enable GMAC instead of EMAC
+
+GMAC has better performance and fewer hardware issues.
+Use the GMAC in MII mode for ethernet instead of the EMAC.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 27 ++++++++++++---------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+index 5c51cb8..7bf4935 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+@@ -19,21 +19,6 @@
+ compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+- emac: ethernet@01c0b000 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&emac_pins_a>;
+- phy = <&phy1>;
+- status = "okay";
+- };
+-
+- mdio@01c0b080 {
+- status = "okay";
+-
+- phy1: ethernet-phy@1 {
+- reg = <1>;
+- };
+- };
+-
+ pinctrl@01c20800 {
+ led_pins_cubieboard2: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+@@ -60,6 +45,18 @@
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+ };
++
++ gmac: ethernet@01c50000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&gmac_pins_mii_a>;
++ phy = <&phy1>;
++ phy-mode = "mii";
++ status = "okay";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
+ };
+
+ leds {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/125-dt-sun7i-olinuxinom-enable-gmac.patch b/target/linux/sunxi/patches-3.14/125-dt-sun7i-olinuxinom-enable-gmac.patch
new file mode 100644
index 0000000000..756400a557
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/125-dt-sun7i-olinuxinom-enable-gmac.patch
@@ -0,0 +1,62 @@
+From f5b426a2eb246e91eb2de0cd215565d38d1d5ce7 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:53 +0800
+Subject: [PATCH] ARM: dts: sun7i: a20-olinuxino-micro: Enable GMAC instead of
+ EMAC
+
+GMAC has better performance and fewer hardware issues.
+Use the GMAC in MII mode for ethernet instead of the EMAC.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 27 +++++++++++--------------
+ 1 file changed, 12 insertions(+), 15 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index ead3013..b02a796 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -19,21 +19,6 @@
+ compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+- emac: ethernet@01c0b000 {
+- pinctrl-names = "default";
+- pinctrl-0 = <&emac_pins_a>;
+- phy = <&phy1>;
+- status = "okay";
+- };
+-
+- mdio@01c0b080 {
+- status = "okay";
+-
+- phy1: ethernet-phy@1 {
+- reg = <1>;
+- };
+- };
+-
+ pinctrl@01c20800 {
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+@@ -78,6 +63,18 @@
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
++
++ gmac: ethernet@01c50000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&gmac_pins_mii_a>;
++ phy = <&phy1>;
++ phy-mode = "mii";
++ status = "okay";
++
++ phy1: ethernet-phy@1 {
++ reg = <1>;
++ };
++ };
+ };
+
+ leds {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/126-dt-sun7i-add-eth-alias-for-gmac.patch b/target/linux/sunxi/patches-3.14/126-dt-sun7i-add-eth-alias-for-gmac.patch
new file mode 100644
index 0000000000..0fe2087ebc
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/126-dt-sun7i-add-eth-alias-for-gmac.patch
@@ -0,0 +1,31 @@
+From 614b4b996be81daca9d8333e1ac163d23e1701c4 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:54 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add ethernet alias for GMAC
+
+All Allwinner A20 boards we support can only use either EMAC or GMAC,
+as they share the same pins. As we have switched all supported to
+GMAC, we should alias GMAC (the active controller) as ethernet0,
+so u-boot will insert the MAC address for the correct controller.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 679dc50..bfc3a95 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -17,7 +17,7 @@
+ interrupt-parent = <&gic>;
+
+ aliases {
+- ethernet0 = &emac;
++ ethernet0 = &gmac;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/130-dt-sun4i-add-usbclock-bindings.patch b/target/linux/sunxi/patches-3.14/130-dt-sun4i-add-usbclock-bindings.patch
new file mode 100644
index 0000000000..71d97c67ac
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/130-dt-sun4i-add-usbclock-bindings.patch
@@ -0,0 +1,35 @@
+From b5325f9813a6a7cf80ede22fbee66376abbe2384 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Fri, 7 Feb 2014 16:21:51 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add bindings for USB clocks
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 132b261..2d623d0 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -315,6 +315,15 @@
+ clock-output-names = "ir1";
+ };
+
++ usb_clk: clk@01c200cc {
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ compatible = "allwinner,sun4i-a10-usb-clk";
++ reg = <0x01c200cc 0x4>;
++ clocks = <&pll6 1>;
++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy";
++ };
++
+ spi3_clk: clk@01c200d4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/131-dt-sun5i-add-usbclock-bindings.patch b/target/linux/sunxi/patches-3.14/131-dt-sun5i-add-usbclock-bindings.patch
new file mode 100644
index 0000000000..337710cbf5
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/131-dt-sun5i-add-usbclock-bindings.patch
@@ -0,0 +1,56 @@
+From 5b08dd0d672b59fff16d02239ca6a36aaecdb1ca Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Fri, 7 Feb 2014 16:21:52 +0100
+Subject: [PATCH] ARM: sun5i: dt: Add bindings for USB clocks
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 9 +++++++++
+ arch/arm/boot/dts/sun5i-a13.dtsi | 9 +++++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index 99a5120..905317e 100644
+--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
+@@ -276,6 +276,15 @@
+ clock-output-names = "ir0";
+ };
+
++ usb_clk: clk@01c200cc {
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ compatible = "allwinner,sun5i-a13-usb-clk";
++ reg = <0x01c200cc 0x4>;
++ clocks = <&pll6 1>;
++ clock-output-names = "usb_ohci0", "usb_phy";
++ };
++
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index b776baa..d196ebc6 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -274,6 +274,15 @@
+ clock-output-names = "ir0";
+ };
+
++ usb_clk: clk@01c200cc {
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ compatible = "allwinner,sun5i-a13-usb-clk";
++ reg = <0x01c200cc 0x4>;
++ clocks = <&pll6 1>;
++ clock-output-names = "usb_ohci0", "usb_phy";
++ };
++
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/132-dt-sun7i-add-usbclock-bindings.patch b/target/linux/sunxi/patches-3.14/132-dt-sun7i-add-usbclock-bindings.patch
new file mode 100644
index 0000000000..151aa46162
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/132-dt-sun7i-add-usbclock-bindings.patch
@@ -0,0 +1,35 @@
+From 25a1ac92997df2b1e2c76a374d444605cbc96a9f Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Fri, 7 Feb 2014 16:21:53 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add bindings for USB clocks
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index bfc3a95..822a816 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -305,6 +305,15 @@
+ clock-output-names = "ir1";
+ };
+
++ usb_clk: clk@01c200cc {
++ #clock-cells = <1>;
++ #reset-cells = <1>;
++ compatible = "allwinner,sun4i-a10-usb-clk";
++ reg = <0x01c200cc 0x4>;
++ clocks = <&pll6 1>;
++ clock-output-names = "usb_ohci0", "usb_ohci1", "usb_phy";
++ };
++
+ spi3_clk: clk@01c200d4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-mod0-clk";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/135-pinctrl-fixes.patch b/target/linux/sunxi/patches-3.14/135-pinctrl-fixes.patch
new file mode 100644
index 0000000000..e653fe900f
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/135-pinctrl-fixes.patch
@@ -0,0 +1,101 @@
+From 68a7d9940935cb71440a9ff384e5859592b0dbfd Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 14 Dec 2013 17:20:13 +0100
+Subject: [PATCH] pinctrl-sunxi: Fix sun5i-a13 port F multiplexing
+
+The correct value for selecting the mmc0 function on port F pins is 2 not 4,
+as per the data-sheet:
+http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/pinctrl/pinctrl-sunxi-pins.h | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-sunxi-pins.h b/drivers/pinctrl/pinctrl-sunxi-pins.h
+index 6fd8d4d..3d60669 100644
+--- a/drivers/pinctrl/pinctrl-sunxi-pins.h
++++ b/drivers/pinctrl/pinctrl-sunxi-pins.h
+@@ -1932,27 +1932,27 @@ static const struct sunxi_desc_pin sun5i_a13_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* D1 */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF1,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* D0 */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF2,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* CLK */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF3,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* CMD */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF4,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* D3 */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PF5,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+- SUNXI_FUNCTION(0x4, "mmc0")), /* D2 */
++ SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN_PG0,
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+--
+2.0.3
+
+From 8d2c11e63a3302bbbdac41fc765c881da8a8eb37 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 15 Feb 2014 12:58:17 +0100
+Subject: [PATCH] pinctrl-sunxi: Fix hang on gpio irq
+
+Our irq handler was missing chained_irq_enter / exit calls, causing a
+hard hang as soon as a gpio irq happened.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/pinctrl/pinctrl-sunxi.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
+index f9fabe9..d16da53 100644
+--- a/drivers/pinctrl/pinctrl-sunxi.c
++++ b/drivers/pinctrl/pinctrl-sunxi.c
+@@ -13,6 +13,7 @@
+ #include <linux/io.h>
+ #include <linux/clk.h>
+ #include <linux/gpio.h>
++#include <linux/irqchip/chained_irq.h>
+ #include <linux/irqdomain.h>
+ #include <linux/irqchip/chained_irq.h>
+ #include <linux/module.h>
+@@ -670,6 +671,8 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
+ struct sunxi_pinctrl *pctl = irq_get_handler_data(irq);
+ const unsigned long reg = readl(pctl->membase + IRQ_STATUS_REG);
+
++ chained_irq_enter(chip, desc);
++
+ /* Clear all interrupts */
+ writel(reg, pctl->membase + IRQ_STATUS_REG);
+
+@@ -683,6 +686,7 @@ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
+ }
+ chained_irq_exit(chip, desc);
+ }
++ chained_irq_exit(chip, desc);
+ }
+
+ static struct of_device_id sunxi_pinctrl_match[] = {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch b/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch
new file mode 100644
index 0000000000..5a8c83c5e1
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/136-1-irqchip-sun4i-fixes.patch
@@ -0,0 +1,415 @@
+From 843da234cfc0e7014f9e2da82786a485e0820665 Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Thu, 13 Mar 2014 15:32:05 +0100
+Subject: [PATCH] irq: Add a new IRQCHIP_EOI_THREADED flag
+
+This flag must be used in combination with handle_fasteoi_irq, when set
+handle_fasteoi_irq will delay the calling of chip->irq_eoi until the threaded
+handler has run.
+
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Tested-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ include/linux/irq.h | 3 +++
+ kernel/irq/chip.c | 48 ++++++++++++++++++++++++++++++++++++++++--------
+ kernel/irq/internals.h | 1 +
+ kernel/irq/manage.c | 2 +-
+ 4 files changed, 45 insertions(+), 9 deletions(-)
+
+diff --git a/include/linux/irq.h b/include/linux/irq.h
+index 7dc1003..0f036fb 100644
+--- a/include/linux/irq.h
++++ b/include/linux/irq.h
+@@ -349,6 +349,8 @@ struct irq_chip {
+ * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
+ * when irq enabled
+ * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
++ * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask
++ * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode
+ */
+ enum {
+ IRQCHIP_SET_TYPE_MASKED = (1 << 0),
+@@ -357,6 +359,7 @@ enum {
+ IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
+ IRQCHIP_SKIP_SET_WAKE = (1 << 4),
+ IRQCHIP_ONESHOT_SAFE = (1 << 5),
++ IRQCHIP_EOI_THREADED = (1 << 6),
+ };
+
+ /* This include will go away once we isolated irq_desc usage to core code */
+diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
+index dc04c16..6397df2 100644
+--- a/kernel/irq/chip.c
++++ b/kernel/irq/chip.c
+@@ -281,6 +281,19 @@ void unmask_irq(struct irq_desc *desc)
+ }
+ }
+
++void unmask_threaded_irq(struct irq_desc *desc)
++{
++ struct irq_chip *chip = desc->irq_data.chip;
++
++ if (chip->flags & IRQCHIP_EOI_THREADED)
++ chip->irq_eoi(&desc->irq_data);
++
++ if (chip->irq_unmask) {
++ chip->irq_unmask(&desc->irq_data);
++ irq_state_clr_masked(desc);
++ }
++}
++
+ /*
+ * handle_nested_irq - Handle a nested irq from a irq thread
+ * @irq: the interrupt number
+@@ -435,6 +448,27 @@ static inline void preflow_handler(struct irq_desc *desc)
+ static inline void preflow_handler(struct irq_desc *desc) { }
+ #endif
+
++static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip)
++{
++ if (!(desc->istate & IRQS_ONESHOT)) {
++ chip->irq_eoi(&desc->irq_data);
++ return;
++ }
++ /*
++ * We need to unmask in the following cases:
++ * - Oneshot irq which did not wake the thread (caused by a
++ * spurious interrupt or a primary handler handling it
++ * completely).
++ */
++ if (!irqd_irq_disabled(&desc->irq_data) &&
++ irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) {
++ chip->irq_eoi(&desc->irq_data);
++ unmask_irq(desc);
++ } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) {
++ chip->irq_eoi(&desc->irq_data);
++ }
++}
++
+ /**
+ * handle_fasteoi_irq - irq handler for transparent controllers
+ * @irq: the interrupt number
+@@ -448,6 +482,8 @@ static inline void preflow_handler(struct irq_desc *desc) { }
+ void
+ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
+ {
++ struct irq_chip *chip = desc->irq_data.chip;
++
+ raw_spin_lock(&desc->lock);
+
+ if (unlikely(irqd_irq_inprogress(&desc->irq_data)))
+@@ -473,18 +509,14 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
+ preflow_handler(desc);
+ handle_irq_event(desc);
+
+- if (desc->istate & IRQS_ONESHOT)
+- cond_unmask_irq(desc);
++ cond_unmask_eoi_irq(desc, chip);
+
+-out_eoi:
+- desc->irq_data.chip->irq_eoi(&desc->irq_data);
+-out_unlock:
+ raw_spin_unlock(&desc->lock);
+ return;
+ out:
+- if (!(desc->irq_data.chip->flags & IRQCHIP_EOI_IF_HANDLED))
+- goto out_eoi;
+- goto out_unlock;
++ if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED))
++ chip->irq_eoi(&desc->irq_data);
++ raw_spin_unlock(&desc->lock);
+ }
+
+ /**
+diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
+index 001fa5b..e98bb56 100644
+--- a/kernel/irq/internals.h
++++ b/kernel/irq/internals.h
+@@ -73,6 +73,7 @@ extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu);
+ extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu);
+ extern void mask_irq(struct irq_desc *desc);
+ extern void unmask_irq(struct irq_desc *desc);
++extern void unmask_threaded_irq(struct irq_desc *desc);
+
+ extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr);
+
+diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
+index d3bf660..7593958 100644
+--- a/kernel/irq/manage.c
++++ b/kernel/irq/manage.c
+@@ -718,7 +718,7 @@ static void irq_finalize_oneshot(struct irq_desc *desc,
+
+ if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) &&
+ irqd_irq_masked(&desc->irq_data))
+- unmask_irq(desc);
++ unmask_threaded_irq(desc);
+
+ out_unlock:
+ raw_spin_unlock_irq(&desc->lock);
+--
+2.0.3
+
+From d000f9a5348e6d6c8b620a9c2d0b97c69d6d6153 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Mar 2014 16:47:46 +0100
+Subject: [PATCH] irqchip: sun4i: Fix irq 0 not working
+
+SUN4I_IRQ_VECTOR_REG containing 0 can mean one of 3 things:
+1) no more irqs pending
+2) irq 0 pending
+3) spurious irq
+
+So if we immediately get a reading of 0, check the irq-pending reg
+to differentiate between 2 and 3. We only do this once to avoid
+the extra check in the common case of 1) hapening after having
+read the vector-reg once.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/irqchip/irq-sun4i.c | 18 ++++++++++++++++--
+ 1 file changed, 16 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index a5438d8..5c25048 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -140,10 +140,24 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re
+ {
+ u32 irq, hwirq;
+
++ /*
++ * hwirq == 0 can mean one of 3 things:
++ * 1) no more irqs pending
++ * 2) irq 0 pending
++ * 3) spurious irq
++ * So if we immediately get a reading of 0, check the irq-pending reg
++ * to differentiate between 2 and 3. We only do this once to avoid
++ * the extra check in the common case of 1 hapening after having
++ * read the vector-reg once.
++ */
+ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
+- while (hwirq != 0) {
++ if (hwirq == 0 &&
++ !(readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0)) & BIT(0)))
++ return;
++
++ do {
+ irq = irq_find_mapping(sun4i_irq_domain, hwirq);
+ handle_IRQ(irq, regs);
+ hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
+- }
++ } while (hwirq != 0);
+ }
+--
+2.0.3
+
+From b37587009473582d9fc080e8b8b99b67b0077a90 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Mar 2014 16:53:23 +0100
+Subject: [PATCH] irqchip: sun4i: Fix a comment about mask register
+ initialization
+
+The comment was claiming that we were masking all irqs, while the code actually
+*un*masks all of them.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/irqchip/irq-sun4i.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index 5c25048..8a2fbee 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -109,7 +109,7 @@ static int __init sun4i_of_init(struct device_node *node,
+ writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(1));
+ writel(0, sun4i_irq_base + SUN4I_IRQ_ENABLE_REG(2));
+
+- /* Mask all the interrupts */
++ /* Unmask all the interrupts, ENABLE_REG(x) is used for masking */
+ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(0));
+ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(1));
+ writel(0, sun4i_irq_base + SUN4I_IRQ_MASK_REG(2));
+--
+2.0.3
+
+From c8865ee82b74b2d95339370972a0d9bfdbac09cf Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 12 Mar 2014 17:43:45 +0100
+Subject: [PATCH] irqchip: sun4i: Don't ack IRQs != 0, fix acking of IRQ 0
+
+All IRQs except for IRQ 0 seem to not need acking, so drop acking for them.
+
+The ENMI needs to have the ack done *after* clearing the interrupt source,
+otherwise we will get a spurious interrupt for each real interrupt.
+
+So use the new IRQCHIP_EOI_THREADED flag for this in combination with
+handle_fasteoi_irq. This uses a separate irq_chip struct for IRQ 0,
+since we only want this behavior for IRQ 0.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/irqchip/irq-sun4i.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index 8a2fbee..a0ed1ea 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -76,16 +76,29 @@ static void sun4i_irq_unmask(struct irq_data *irqd)
+
+ static struct irq_chip sun4i_irq_chip = {
+ .name = "sun4i_irq",
+- .irq_ack = sun4i_irq_ack,
+ .irq_mask = sun4i_irq_mask,
+ .irq_unmask = sun4i_irq_unmask,
+ };
+
++/* IRQ 0 / the ENMI needs a late eoi call */
++static struct irq_chip sun4i_irq_chip_enmi = {
++ .name = "sun4i_irq",
++ .irq_eoi = sun4i_irq_ack,
++ .irq_mask = sun4i_irq_mask,
++ .irq_unmask = sun4i_irq_unmask,
++ .flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED,
++};
++
+ static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+ {
+- irq_set_chip_and_handler(virq, &sun4i_irq_chip,
+- handle_level_irq);
++ if (hw == 0)
++ irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi,
++ handle_fasteoi_irq);
++ else
++ irq_set_chip_and_handler(virq, &sun4i_irq_chip,
++ handle_level_irq);
++
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+--
+2.0.3
+
+From f8b4347aa12d7a30aa1d3e5bfcdccece52d17af3 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 13 Mar 2014 19:38:26 +0100
+Subject: [PATCH] irqchip: sun4i: Use handle_fasteoi_irq for all interrupts
+
+Since the sun4i irq chip does not require any action and clears the interrupt
+when the level goes back to inactive, we don't need to mask / unmask for
+non oneshot IRQs, to achieve this we make sun4i_irq_ack a nop for all irqs
+except irq 0 and use handle_fasteoi_irq for all interrupts.
+
+Now there might be a case when the device reactivates the interrupt
+before the RETI. But that does not matter as we run the primary
+interrupt handlers with interrupts disabled.
+
+This also allows us to get rid of needing to use 2 irq_chip structs, this
+means that the IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED will now influence
+all interrupts rather then just irq 0, but that does not matter as the eoi
+is now a nop anyways for all interrupts but irq 0.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/irqchip/irq-sun4i.c | 18 ++++--------------
+ 1 file changed, 4 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index a0ed1ea..6a8c88d 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -45,6 +45,9 @@ static void sun4i_irq_ack(struct irq_data *irqd)
+ int reg = irq / 32;
+ u32 val;
+
++ if (irq != 0)
++ return; /* Only IRQ 0 / the ENMI needs to be acked */
++
+ val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+ writel(val | (1 << irq_off),
+ sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+@@ -76,13 +79,6 @@ static void sun4i_irq_unmask(struct irq_data *irqd)
+
+ static struct irq_chip sun4i_irq_chip = {
+ .name = "sun4i_irq",
+- .irq_mask = sun4i_irq_mask,
+- .irq_unmask = sun4i_irq_unmask,
+-};
+-
+-/* IRQ 0 / the ENMI needs a late eoi call */
+-static struct irq_chip sun4i_irq_chip_enmi = {
+- .name = "sun4i_irq",
+ .irq_eoi = sun4i_irq_ack,
+ .irq_mask = sun4i_irq_mask,
+ .irq_unmask = sun4i_irq_unmask,
+@@ -92,13 +88,7 @@ static struct irq_chip sun4i_irq_chip_enmi = {
+ static int sun4i_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+ {
+- if (hw == 0)
+- irq_set_chip_and_handler(virq, &sun4i_irq_chip_enmi,
+- handle_fasteoi_irq);
+- else
+- irq_set_chip_and_handler(virq, &sun4i_irq_chip,
+- handle_level_irq);
+-
++ irq_set_chip_and_handler(virq, &sun4i_irq_chip, handle_fasteoi_irq);
+ set_irq_flags(virq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+--
+2.0.3
+
+From de39bc31eaa554bd044e6adefacd3da6da5bf6e3 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 13 Mar 2014 20:41:20 +0100
+Subject: [PATCH] irqchip: sun4i: simplify sun4i_irq_ack
+
+Now that we only ack irq 0 the code can be simplified a lot.
+
+Also switch from read / modify / write to a simple write clear:
+1) This is what the android code does (it has a hack for acking irq 0
+ in its unmask code doing this)
+2) read / modify / write simply does not make sense for an irq status
+ register like this, if the other bits are writeable (and the data sheet says
+ they are not) they should be write 1 to clear, since otherwise a read /
+ modify / write can race with a device raising an interrupt and then clear
+ the pending bit unintentionally
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/irqchip/irq-sun4i.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
+index 6a8c88d..75615b5 100644
+--- a/drivers/irqchip/irq-sun4i.c
++++ b/drivers/irqchip/irq-sun4i.c
+@@ -41,16 +41,11 @@ static asmlinkage void __exception_irq_entry sun4i_handle_irq(struct pt_regs *re
+ static void sun4i_irq_ack(struct irq_data *irqd)
+ {
+ unsigned int irq = irqd_to_hwirq(irqd);
+- unsigned int irq_off = irq % 32;
+- int reg = irq / 32;
+- u32 val;
+
+ if (irq != 0)
+ return; /* Only IRQ 0 / the ENMI needs to be acked */
+
+- val = readl(sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
+- writel(val | (1 << irq_off),
+- sun4i_irq_base + SUN4I_IRQ_PENDING_REG(reg));
++ writel(BIT(0), sun4i_irq_base + SUN4I_IRQ_PENDING_REG(0));
+ }
+
+ static void sun4i_irq_mask(struct irq_data *irqd)
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/137-1-pinctrl-create-irq-pin-mapping.patch b/target/linux/sunxi/patches-3.14/137-1-pinctrl-create-irq-pin-mapping.patch
new file mode 100644
index 0000000000..cd209cdb59
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/137-1-pinctrl-create-irq-pin-mapping.patch
@@ -0,0 +1,41 @@
+From 4c228d02d1339a286e259893062ea445be82b573 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Tue, 7 Jan 2014 18:56:29 +0800
+Subject: [PATCH] pinctrl: sunxi: create irq/pin mapping during init
+
+The irq/pin mapping is used to lookup the pin to mux to the irq
+function when the irq is enabled. It is created when gpio_to_irq
+is called. Creating the mapping during init allows us to map the
+interrupts directly from the device tree.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ drivers/pinctrl/pinctrl-sunxi.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
+index d16da53..067e7e10 100644
+--- a/drivers/pinctrl/pinctrl-sunxi.c
++++ b/drivers/pinctrl/pinctrl-sunxi.c
+@@ -531,8 +531,6 @@ static int sunxi_pinctrl_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+ if (!desc)
+ return -EINVAL;
+
+- pctl->irq_array[desc->irqnum] = offset;
+-
+ dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
+ chip->label, offset + chip->base, desc->irqnum);
+
+@@ -759,6 +757,9 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev)
+ struct sunxi_desc_function *func = pin->functions;
+
+ while (func->name) {
++ /* Create interrupt mapping while we're at it */
++ if (!strcmp(func->name, "irq"))
++ pctl->irq_array[func->irqnum] = pin->pin.number;
+ sunxi_pinctrl_add_function(pctl, func->name);
+ func++;
+ }
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/137-2-pinctrl-add-IRQCHIP_SKIP_SET_WAKE.patch b/target/linux/sunxi/patches-3.14/137-2-pinctrl-add-IRQCHIP_SKIP_SET_WAKE.patch
new file mode 100644
index 0000000000..8db59a454d
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/137-2-pinctrl-add-IRQCHIP_SKIP_SET_WAKE.patch
@@ -0,0 +1,31 @@
+From 77f1265dd02dfd5dcaa0ebd6d3ea1d131bc095e2 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Tue, 7 Jan 2014 19:01:29 +0800
+Subject: [PATCH] pinctrl: sunxi: add IRQCHIP_SKIP_SET_WAKE flag for pinctrl
+ irq chip
+
+The sunxi pinctrl irq chip driver does not support wakeup at the
+moment. Adding IRQCHIP_SKIP_SET_WAKE lets the irqs work with drivers
+using wakeup.
+
+Also add a name to the irq chip.
+---
+ drivers/pinctrl/pinctrl-sunxi.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c
+index 067e7e10..d7a41a8 100644
+--- a/drivers/pinctrl/pinctrl-sunxi.c
++++ b/drivers/pinctrl/pinctrl-sunxi.c
+@@ -661,6 +661,8 @@ static struct irq_chip sunxi_pinctrl_irq_chip = {
+ .irq_mask_ack = sunxi_pinctrl_irq_mask_ack,
+ .irq_unmask = sunxi_pinctrl_irq_unmask,
+ .irq_set_type = sunxi_pinctrl_irq_set_type,
++ .name = "sunxi-pio",
++ .flags = IRQCHIP_SKIP_SET_WAKE,
+ };
+
+ static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc)
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/137-3-dt-sun7i-add-interrupt-cells.patch b/target/linux/sunxi/patches-3.14/137-3-dt-sun7i-add-interrupt-cells.patch
new file mode 100644
index 0000000000..31cf5e4852
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/137-3-dt-sun7i-add-interrupt-cells.patch
@@ -0,0 +1,31 @@
+From eda34c0692e479dd9cd2b7cb70986ae57f15187f Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Tue, 7 Jan 2014 18:50:01 +0800
+Subject: [PATCH] ARM: dts: sun7i: Add #interrupt-cells to pinctrl node
+
+The pinctrl device is also an interrupt controller for external
+interrupts. Add the missing #interrupt-cells property.
+
+Also remove the unused #address-cells property.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 0c57ac5..30b9aba 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -572,7 +572,7 @@
+ clocks = <&apb0_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+- #address-cells = <1>;
++ #interrupt-cells = <2>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/140-dt-sunxi-convert-to-new-clock-compats.patch b/target/linux/sunxi/patches-3.14/140-dt-sunxi-convert-to-new-clock-compats.patch
new file mode 100644
index 0000000000..443a65218e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/140-dt-sunxi-convert-to-new-clock-compats.patch
@@ -0,0 +1,1030 @@
+From 46b2ee17d7321149b4d48dd86ee2e346624aa141 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 6 Feb 2014 09:55:58 +0100
+Subject: [PATCH] ARM: sunxi: dt: Convert to the new clock compatibles
+
+Switch the device tree to the new compatibles introduced in the clock drivers
+to have a common pattern accross all Allwinner SoCs.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 60 +++++++++++++++++++--------------------
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 48 +++++++++++++++----------------
+ arch/arm/boot/dts/sun5i-a13.dtsi | 48 +++++++++++++++----------------
+ arch/arm/boot/dts/sun6i-a31.dtsi | 10 +++----
+ arch/arm/boot/dts/sun7i-a20.dtsi | 54 +++++++++++++++++------------------
+ 5 files changed, 110 insertions(+), 110 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 2d623d0..f6f41d6 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -60,7 +60,7 @@
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-osc-clk";
++ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+@@ -75,7 +75,7 @@
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+@@ -83,7 +83,7 @@
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+@@ -91,7 +91,7 @@
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll5-clk";
++ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+@@ -99,7 +99,7 @@
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll6-clk";
++ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+@@ -108,7 +108,7 @@
+ /* dummy is 200M */
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+@@ -116,7 +116,7 @@
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-axi-clk";
++ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+@@ -124,7 +124,7 @@
+
+ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-axi-gates-clk";
++ compatible = "allwinner,sun4i-a10-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "axi_dram";
+@@ -132,7 +132,7 @@
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-ahb-clk";
++ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "ahb";
+@@ -140,7 +140,7 @@
+
+ ahb_gates: clk@01c20060 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-ahb-gates-clk";
++ compatible = "allwinner,sun4i-a10-ahb-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb>;
+ clock-output-names = "ahb_usb0", "ahb_ehci0",
+@@ -158,7 +158,7 @@
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb0-clk";
++ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+@@ -166,7 +166,7 @@
+
+ apb0_gates: clk@01c20068 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-apb0-gates-clk";
++ compatible = "allwinner,sun4i-a10-apb0-gates-clk";
+ reg = <0x01c20068 0x4>;
+ clocks = <&apb0>;
+ clock-output-names = "apb0_codec", "apb0_spdif",
+@@ -176,7 +176,7 @@
+
+ apb1_mux: apb1_mux@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-mux-clk";
++ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1_mux";
+@@ -184,7 +184,7 @@
+
+ apb1: apb1@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-clk";
++ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
+ clock-output-names = "apb1";
+@@ -192,7 +192,7 @@
+
+ apb1_gates: clk@01c2006c {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-apb1-gates-clk";
++ compatible = "allwinner,sun4i-a10-apb1-gates-clk";
+ reg = <0x01c2006c 0x4>;
+ clocks = <&apb1>;
+ clock-output-names = "apb1_i2c0", "apb1_i2c1",
+@@ -205,7 +205,7 @@
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+@@ -213,7 +213,7 @@
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+@@ -221,7 +221,7 @@
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0";
+@@ -229,7 +229,7 @@
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc1";
+@@ -237,7 +237,7 @@
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc2";
+@@ -245,7 +245,7 @@
+
+ mmc3_clk: clk@01c20094 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20094 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc3";
+@@ -253,7 +253,7 @@
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+@@ -261,7 +261,7 @@
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+@@ -269,7 +269,7 @@
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+@@ -277,7 +277,7 @@
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+@@ -285,7 +285,7 @@
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+@@ -293,7 +293,7 @@
+
+ pata_clk: clk@01c200ac {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200ac 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "pata";
+@@ -301,7 +301,7 @@
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+@@ -309,7 +309,7 @@
+
+ ir1_clk: clk@01c200b4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir1";
+@@ -326,7 +326,7 @@
+
+ spi3_clk: clk@01c200d4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200d4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi3";
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index 905317e..df90a29 100644
+--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
+@@ -53,7 +53,7 @@
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-osc-clk";
++ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+@@ -68,7 +68,7 @@
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+@@ -76,7 +76,7 @@
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+@@ -84,7 +84,7 @@
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll5-clk";
++ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+@@ -92,7 +92,7 @@
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll6-clk";
++ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+@@ -101,7 +101,7 @@
+ /* dummy is 200M */
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+@@ -109,7 +109,7 @@
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-axi-clk";
++ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+@@ -117,7 +117,7 @@
+
+ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-axi-gates-clk";
++ compatible = "allwinner,sun4i-a10-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "axi_dram";
+@@ -125,7 +125,7 @@
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-ahb-clk";
++ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "ahb";
+@@ -147,7 +147,7 @@
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb0-clk";
++ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+@@ -164,7 +164,7 @@
+
+ apb1_mux: apb1_mux@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-mux-clk";
++ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1_mux";
+@@ -172,7 +172,7 @@
+
+ apb1: apb1@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-clk";
++ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
+ clock-output-names = "apb1";
+@@ -190,7 +190,7 @@
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+@@ -198,7 +198,7 @@
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+@@ -206,7 +206,7 @@
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0";
+@@ -214,7 +214,7 @@
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc1";
+@@ -222,7 +222,7 @@
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc2";
+@@ -230,7 +230,7 @@
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+@@ -238,7 +238,7 @@
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+@@ -246,7 +246,7 @@
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+@@ -254,7 +254,7 @@
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+@@ -262,7 +262,7 @@
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+@@ -270,7 +270,7 @@
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+@@ -287,7 +287,7 @@
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mbus";
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index d196ebc6..24cd86cb 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -54,7 +54,7 @@
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-osc-clk";
++ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+@@ -69,7 +69,7 @@
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+@@ -77,7 +77,7 @@
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+@@ -85,7 +85,7 @@
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll5-clk";
++ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+@@ -93,7 +93,7 @@
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll6-clk";
++ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+@@ -102,7 +102,7 @@
+ /* dummy is 200M */
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&dummy>;
+ clock-output-names = "cpu";
+@@ -110,7 +110,7 @@
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-axi-clk";
++ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+@@ -118,7 +118,7 @@
+
+ axi_gates: clk@01c2005c {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-axi-gates-clk";
++ compatible = "allwinner,sun4i-a10-axi-gates-clk";
+ reg = <0x01c2005c 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "axi_dram";
+@@ -126,7 +126,7 @@
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-ahb-clk";
++ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "ahb";
+@@ -147,7 +147,7 @@
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb0-clk";
++ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+@@ -163,7 +163,7 @@
+
+ apb1_mux: apb1_mux@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-mux-clk";
++ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1_mux";
+@@ -171,7 +171,7 @@
+
+ apb1: apb1@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-clk";
++ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
+ clock-output-names = "apb1";
+@@ -188,7 +188,7 @@
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+@@ -196,7 +196,7 @@
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+@@ -204,7 +204,7 @@
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0";
+@@ -212,7 +212,7 @@
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc1";
+@@ -220,7 +220,7 @@
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc2";
+@@ -228,7 +228,7 @@
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+@@ -236,7 +236,7 @@
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+@@ -244,7 +244,7 @@
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+@@ -252,7 +252,7 @@
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+@@ -260,7 +260,7 @@
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+@@ -268,7 +268,7 @@
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+@@ -285,7 +285,7 @@
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mbus";
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index d3f1995..af6f87c 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -95,7 +95,7 @@
+
+ cpu: cpu@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20050 0x4>;
+
+ /*
+@@ -110,7 +110,7 @@
+
+ axi: axi@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-axi-clk";
++ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+@@ -126,7 +126,7 @@
+
+ ahb1: ahb1@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-ahb-clk";
++ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1_mux>;
+ clock-output-names = "ahb1";
+@@ -155,7 +155,7 @@
+
+ apb1: apb1@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb0-clk";
++ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb1>;
+ clock-output-names = "apb1";
+@@ -173,7 +173,7 @@
+
+ apb2_mux: apb2_mux@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-mux-clk";
++ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ clock-output-names = "apb2_mux";
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 911d4e4..d00fbf8 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -64,7 +64,7 @@
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-osc-clk";
++ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+@@ -79,7 +79,7 @@
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+@@ -87,7 +87,7 @@
+
+ pll4: clk@01c20018 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20018 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+@@ -95,7 +95,7 @@
+
+ pll5: clk@01c20020 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll5-clk";
++ compatible = "allwinner,sun4i-a10-pll5-clk";
+ reg = <0x01c20020 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll5_ddr", "pll5_other";
+@@ -103,7 +103,7 @@
+
+ pll6: clk@01c20028 {
+ #clock-cells = <1>;
+- compatible = "allwinner,sun4i-pll6-clk";
++ compatible = "allwinner,sun4i-a10-pll6-clk";
+ reg = <0x01c20028 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll6_sata", "pll6_other", "pll6";
+@@ -111,7 +111,7 @@
+
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6 1>;
+ clock-output-names = "cpu";
+@@ -119,7 +119,7 @@
+
+ axi: axi@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-axi-clk";
++ compatible = "allwinner,sun4i-a10-axi-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&cpu>;
+ clock-output-names = "axi";
+@@ -127,7 +127,7 @@
+
+ ahb: ahb@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-ahb-clk";
++ compatible = "allwinner,sun4i-a10-ahb-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&axi>;
+ clock-output-names = "ahb";
+@@ -155,7 +155,7 @@
+
+ apb0: apb0@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb0-clk";
++ compatible = "allwinner,sun4i-a10-apb0-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&ahb>;
+ clock-output-names = "apb0";
+@@ -174,7 +174,7 @@
+
+ apb1_mux: apb1_mux@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-mux-clk";
++ compatible = "allwinner,sun4i-a10-apb1-mux-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&osc32k>;
+ clock-output-names = "apb1_mux";
+@@ -182,7 +182,7 @@
+
+ apb1: apb1@01c20058 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-apb1-clk";
++ compatible = "allwinner,sun4i-a10-apb1-clk";
+ reg = <0x01c20058 0x4>;
+ clocks = <&apb1_mux>;
+ clock-output-names = "apb1";
+@@ -203,7 +203,7 @@
+
+ nand_clk: clk@01c20080 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20080 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "nand";
+@@ -211,7 +211,7 @@
+
+ ms_clk: clk@01c20084 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20084 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ms";
+@@ -219,7 +219,7 @@
+
+ mmc0_clk: clk@01c20088 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20088 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0";
+@@ -227,7 +227,7 @@
+
+ mmc1_clk: clk@01c2008c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2008c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc1";
+@@ -235,7 +235,7 @@
+
+ mmc2_clk: clk@01c20090 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20090 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc2";
+@@ -243,7 +243,7 @@
+
+ mmc3_clk: clk@01c20094 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20094 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc3";
+@@ -251,7 +251,7 @@
+
+ ts_clk: clk@01c20098 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c20098 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ts";
+@@ -259,7 +259,7 @@
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ss";
+@@ -267,7 +267,7 @@
+
+ spi0_clk: clk@01c200a0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi0";
+@@ -275,7 +275,7 @@
+
+ spi1_clk: clk@01c200a4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi1";
+@@ -283,7 +283,7 @@
+
+ spi2_clk: clk@01c200a8 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200a8 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi2";
+@@ -291,7 +291,7 @@
+
+ pata_clk: clk@01c200ac {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200ac 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "pata";
+@@ -299,7 +299,7 @@
+
+ ir0_clk: clk@01c200b0 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b0 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir0";
+@@ -307,7 +307,7 @@
+
+ ir1_clk: clk@01c200b4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200b4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "ir1";
+@@ -324,7 +324,7 @@
+
+ spi3_clk: clk@01c200d4 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200d4 0x4>;
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "spi3";
+@@ -332,7 +332,7 @@
+
+ mbus_clk: clk@01c2015c {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-mod0-clk";
++ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2015c 0x4>;
+ clocks = <&osc24M>, <&pll6 2>, <&pll5 1>;
+ clock-output-names = "mbus";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/141-dt-sunxi-add-common-regulator-include.patch b/target/linux/sunxi/patches-3.14/141-dt-sunxi-add-common-regulator-include.patch
new file mode 100644
index 0000000000..07dda97efa
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/141-dt-sunxi-add-common-regulator-include.patch
@@ -0,0 +1,103 @@
+From 6e763a8ebe7a16ae5635ade146fd2930749ed775 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 1 Mar 2014 14:57:56 +0100
+Subject: [PATCH] ARM: sunxi: dt: Add sunxi-common-regulators include file
+
+Most sunxi boards with a sata connector also have a gpio controlled connector
+for sata target power and almost all sunxi boards have a gpio controlled vbus
+for usb1 and usb2.
+
+This commit adds an include file for the regulators representing these
+supplies, avoiding the need to copy and paste the regulator code to allmost
+all sunxi board dts files.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sunxi-common-regulators.dtsi | 75 ++++++++++++++++++++++++++
+ 1 file changed, 75 insertions(+)
+ create mode 100644 arch/arm/boot/dts/sunxi-common-regulators.dtsi
+
+diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+new file mode 100644
+index 0000000..18eeac0
+--- /dev/null
++++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+@@ -0,0 +1,75 @@
++/*
++ * sunxi boards common regulator (ahci target power supply, usb-vbus) code
++ *
++ * Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/ {
++ soc@01c00000 {
++ pio: pinctrl@01c20800 {
++ ahci_pwr_pin_a: ahci_pwr_pin@0 {
++ allwinner,pins = "PB8";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ usb1_vbus_pin_a: usb1_vbus_pin@0 {
++ allwinner,pins = "PH6";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ usb2_vbus_pin_a: usb2_vbus_pin@0 {
++ allwinner,pins = "PH3";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++ };
++ };
++
++ reg_ahci_5v: ahci-5v {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&ahci_pwr_pin_a>;
++ regulator-name = "ahci-5v";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ enable-active-high;
++ gpio = <&pio 1 8 0>;
++ status = "disabled";
++ };
++
++ reg_usb1_vbus: usb1-vbus {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&usb1_vbus_pin_a>;
++ regulator-name = "usb1-vbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ enable-active-high;
++ gpio = <&pio 7 6 0>;
++ status = "disabled";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&usb2_vbus_pin_a>;
++ regulator-name = "usb2-vbus";
++ regulator-min-microvolt = <5000000>;
++ regulator-max-microvolt = <5000000>;
++ enable-active-high;
++ gpio = <&pio 7 3 0>;
++ status = "disabled";
++ };
++};
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/145-1-dt-sun7i-add-a20-spi.patch b/target/linux/sunxi/patches-3.14/145-1-dt-sun7i-add-a20-spi.patch
new file mode 100644
index 0000000000..47e342c66a
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/145-1-dt-sun7i-add-a20-spi.patch
@@ -0,0 +1,78 @@
+From c9bfaadf8973cb4d9074e80c4bf8708deca62712 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:54 +0100
+Subject: [PATCH] ARM: dt: sun7i: Add A20 SPI controller nodes
+
+The A20 has 4 SPI controllers compatible with the one found in the A10. Add
+them in the DT.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 44 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index d00fbf8..0f0ee58 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -401,6 +401,28 @@
+ #size-cells = <1>;
+ ranges;
+
++ spi0: spi@01c05000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c05000 0x1000>;
++ interrupts = <0 10 4>;
++ clocks = <&ahb_gates 20>, <&spi0_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi1: spi@01c06000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c06000 0x1000>;
++ interrupts = <0 11 4>;
++ clocks = <&ahb_gates 21>, <&spi1_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ emac: ethernet@01c0b000 {
+ compatible = "allwinner,sun4i-a10-emac";
+ reg = <0x01c0b000 0x1000>;
+@@ -417,6 +439,28 @@
+ #size-cells = <0>;
+ };
+
++ spi2: spi@01c17000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c17000 0x1000>;
++ interrupts = <0 12 4>;
++ clocks = <&ahb_gates 22>, <&spi2_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi3: spi@01c1f000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c1f000 0x1000>;
++ interrupts = <0 50 4>;
++ clocks = <&ahb_gates 23>, <&spi3_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ pio: pinctrl@01c20800 {
+ compatible = "allwinner,sun7i-a20-pinctrl";
+ reg = <0x01c20800 0x400>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/145-2-dt-sun4i-add-a10-spi.patch b/target/linux/sunxi/patches-3.14/145-2-dt-sun4i-add-a10-spi.patch
new file mode 100644
index 0000000000..d39b6eebec
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/145-2-dt-sun4i-add-a10-spi.patch
@@ -0,0 +1,77 @@
+From cac3c4d67c80c4895d0d44e609beb535d66af6a3 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:55 +0100
+Subject: [PATCH] ARM: dt: sun4i: Add A10 SPI controller nodes
+
+The A10 has 4 SPI controllers that are now supported. Add them in the DT.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 44 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 44 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index f6f41d6..157bc09 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -339,6 +339,28 @@
+ #size-cells = <1>;
+ ranges;
+
++ spi0: spi@01c05000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c05000 0x1000>;
++ interrupts = <10>;
++ clocks = <&ahb_gates 20>, <&spi0_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi1: spi@01c06000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c06000 0x1000>;
++ interrupts = <11>;
++ clocks = <&ahb_gates 21>, <&spi1_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ emac: ethernet@01c0b000 {
+ compatible = "allwinner,sun4i-a10-emac";
+ reg = <0x01c0b000 0x1000>;
+@@ -355,6 +377,28 @@
+ #size-cells = <0>;
+ };
+
++ spi2: spi@01c17000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c17000 0x1000>;
++ interrupts = <12>;
++ clocks = <&ahb_gates 22>, <&spi2_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi3: spi@01c1f000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c1f000 0x1000>;
++ interrupts = <50>;
++ clocks = <&ahb_gates 23>, <&spi3_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ intc: interrupt-controller@01c20400 {
+ compatible = "allwinner,sun4i-ic";
+ reg = <0x01c20400 0x400>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/145-3-dt-sun5i-add-a13-spi.patch b/target/linux/sunxi/patches-3.14/145-3-dt-sun5i-add-a13-spi.patch
new file mode 100644
index 0000000000..75cbcee7cb
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/145-3-dt-sun5i-add-a13-spi.patch
@@ -0,0 +1,60 @@
+From aeb3b73fc416e14afd25f25e69f8713488edcc1b Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:57 +0100
+Subject: [PATCH] ARM: dt: sun5i: Add A13 SPI controller nodes
+
+The A13 has 3 SPI controllers compatible with the one found in the A10. Add
+them in the DT.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun5i-a13.dtsi | 33 +++++++++++++++++++++++++++++++++
+ 1 file changed, 33 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 24cd86cb..7102d12 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -298,6 +298,39 @@
+ #size-cells = <1>;
+ ranges;
+
++ spi0: spi@01c05000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c05000 0x1000>;
++ interrupts = <10>;
++ clocks = <&ahb_gates 20>, <&spi0_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi1: spi@01c06000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c06000 0x1000>;
++ interrupts = <11>;
++ clocks = <&ahb_gates 21>, <&spi1_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
++ spi2: spi@01c17000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c17000 0x1000>;
++ interrupts = <12>;
++ clocks = <&ahb_gates 22>, <&spi2_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ };
++
+ intc: interrupt-controller@01c20400 {
+ compatible = "allwinner,sun4i-ic";
+ reg = <0x01c20400 0x400>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/146-1-spi-add-a31-spi.patch b/target/linux/sunxi/patches-3.14/146-1-spi-add-a31-spi.patch
new file mode 100644
index 0000000000..3d52020e5e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/146-1-spi-add-a31-spi.patch
@@ -0,0 +1,572 @@
+From 86cb7c7ab176112f8b0031dc7c8d19103ba52277 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Wed, 5 Feb 2014 14:05:05 +0100
+Subject: [PATCH] spi: sunxi: Add Allwinner A31 SPI controller driver
+
+The Allwinner A31 has a new SPI controller IP compared to the older Allwinner
+SoCs.
+
+It supports DMA, but the driver only does PIO for now, and DMA will be
+supported eventually.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ .../devicetree/bindings/spi/spi-sun6i.txt | 24 +
+ drivers/spi/Kconfig | 6 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-sun6i.c | 483 +++++++++++++++++++++
+ 4 files changed, 514 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/spi-sun6i.txt
+ create mode 100644 drivers/spi/spi-sun6i.c
+
+diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
+new file mode 100644
+index 0000000..21de73d
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt
+@@ -0,0 +1,24 @@
++Allwinner A31 SPI controller
++
++Required properties:
++- compatible: Should be "allwinner,sun6i-a31-spi".
++- reg: Should contain register location and length.
++- interrupts: Should contain interrupt.
++- clocks: phandle to the clocks feeding the SPI controller. Two are
++ needed:
++ - "ahb": the gated AHB parent clock
++ - "mod": the parent module clock
++- clock-names: Must contain the clock names described just above
++- resets: phandle to the reset controller asserting this device in
++ reset
++
++Example:
++
++spi1: spi@01c69000 {
++ compatible = "allwinner,sun6i-a31-spi";
++ reg = <0x01c69000 0x1000>;
++ interrupts = <0 66 4>;
++ clocks = <&ahb1_gates 21>, <&spi1_clk>;
++ clock-names = "ahb", "mod";
++ resets = <&ahb1_rst 21>;
++};
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 581ee2a..58530d3 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -446,6 +446,12 @@ config SPI_SIRF
+ help
+ SPI driver for CSR SiRFprimaII SoCs
+
++config SPI_SUN6I
++ tristate "Allwinner A31 SPI controller"
++ depends on ARCH_SUNXI || COMPILE_TEST
++ help
++ This enables using the SPI controller on the Allwinner A31 SoCs.
++
+ config SPI_MXS
+ tristate "Freescale MXS SPI controller"
+ depends on ARCH_MXS
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 95af48d..13b6ccf9 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -70,6 +70,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
+ obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
+ obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
+ obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
++obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
+ obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
+ obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
+ obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o
+diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
+new file mode 100644
+index 0000000..94d38d0
+--- /dev/null
++++ b/drivers/spi/spi-sun6i.c
+@@ -0,0 +1,483 @@
++/*
++ * Copyright (C) 2012 - 2014 Allwinner Tech
++ * Pan Nan <pannan@allwinnertech.com>
++ *
++ * Copyright (C) 2014 Maxime Ripard
++ * Maxime Ripard <maxime.ripard@free-electrons.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/reset.h>
++#include <linux/workqueue.h>
++
++#include <linux/spi/spi.h>
++
++#define SUN6I_FIFO_DEPTH 128
++
++#define SUN6I_GBL_CTL_REG 0x04
++#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
++#define SUN6I_GBL_CTL_MASTER BIT(1)
++#define SUN6I_GBL_CTL_TP BIT(7)
++#define SUN6I_GBL_CTL_RST BIT(31)
++
++#define SUN6I_TFR_CTL_REG 0x08
++#define SUN6I_TFR_CTL_CPHA BIT(0)
++#define SUN6I_TFR_CTL_CPOL BIT(1)
++#define SUN6I_TFR_CTL_SPOL BIT(2)
++#define SUN6I_TFR_CTL_CS_MASK 0x3
++#define SUN6I_TFR_CTL_CS(cs) (((cs) & SUN6I_TFR_CTL_CS_MASK) << 4)
++#define SUN6I_TFR_CTL_CS_MANUAL BIT(6)
++#define SUN6I_TFR_CTL_CS_LEVEL BIT(7)
++#define SUN6I_TFR_CTL_DHB BIT(8)
++#define SUN6I_TFR_CTL_FBS BIT(12)
++#define SUN6I_TFR_CTL_XCH BIT(31)
++
++#define SUN6I_INT_CTL_REG 0x10
++#define SUN6I_INT_CTL_RF_OVF BIT(8)
++#define SUN6I_INT_CTL_TC BIT(12)
++
++#define SUN6I_INT_STA_REG 0x14
++
++#define SUN6I_FIFO_CTL_REG 0x18
++#define SUN6I_FIFO_CTL_RF_RST BIT(15)
++#define SUN6I_FIFO_CTL_TF_RST BIT(31)
++
++#define SUN6I_FIFO_STA_REG 0x1c
++#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f
++#define SUN6I_FIFO_STA_RF_CNT_BITS 0
++#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f
++#define SUN6I_FIFO_STA_TF_CNT_BITS 16
++
++#define SUN6I_CLK_CTL_REG 0x24
++#define SUN6I_CLK_CTL_CDR2_MASK 0xff
++#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0)
++#define SUN6I_CLK_CTL_CDR1_MASK 0xf
++#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8)
++#define SUN6I_CLK_CTL_DRS BIT(12)
++
++#define SUN6I_BURST_CNT_REG 0x30
++#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff)
++
++#define SUN6I_XMIT_CNT_REG 0x34
++#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
++
++#define SUN6I_BURST_CTL_CNT_REG 0x38
++#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff)
++
++#define SUN6I_TXDATA_REG 0x200
++#define SUN6I_RXDATA_REG 0x300
++
++struct sun6i_spi {
++ struct spi_master *master;
++ void __iomem *base_addr;
++ struct clk *hclk;
++ struct clk *mclk;
++ struct reset_control *rstc;
++
++ struct completion done;
++
++ const u8 *tx_buf;
++ u8 *rx_buf;
++ int len;
++};
++
++static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg)
++{
++ return readl(sspi->base_addr + reg);
++}
++
++static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value)
++{
++ writel(value, sspi->base_addr + reg);
++}
++
++static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len)
++{
++ u32 reg, cnt;
++ u8 byte;
++
++ /* See how much data is available */
++ reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG);
++ reg &= SUN6I_FIFO_STA_RF_CNT_MASK;
++ cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS;
++
++ if (len > cnt)
++ len = cnt;
++
++ while (len--) {
++ byte = readb(sspi->base_addr + SUN6I_RXDATA_REG);
++ if (sspi->rx_buf)
++ *sspi->rx_buf++ = byte;
++ }
++}
++
++static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len)
++{
++ u8 byte;
++
++ if (len > sspi->len)
++ len = sspi->len;
++
++ while (len--) {
++ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
++ writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG);
++ sspi->len--;
++ }
++}
++
++static void sun6i_spi_set_cs(struct spi_device *spi, bool enable)
++{
++ struct sun6i_spi *sspi = spi_master_get_devdata(spi->master);
++ u32 reg;
++
++ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
++ reg &= ~SUN6I_TFR_CTL_CS_MASK;
++ reg |= SUN6I_TFR_CTL_CS(spi->chip_select);
++
++ if (enable)
++ reg |= SUN6I_TFR_CTL_CS_LEVEL;
++ else
++ reg &= ~SUN6I_TFR_CTL_CS_LEVEL;
++
++ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
++}
++
++
++static int sun6i_spi_transfer_one(struct spi_master *master,
++ struct spi_device *spi,
++ struct spi_transfer *tfr)
++{
++ struct sun6i_spi *sspi = spi_master_get_devdata(master);
++ unsigned int mclk_rate, div, timeout;
++ unsigned int tx_len = 0;
++ int ret = 0;
++ u32 reg;
++
++ /* We don't support transfer larger than the FIFO */
++ if (tfr->len > SUN6I_FIFO_DEPTH)
++ return -EINVAL;
++
++ reinit_completion(&sspi->done);
++ sspi->tx_buf = tfr->tx_buf;
++ sspi->rx_buf = tfr->rx_buf;
++ sspi->len = tfr->len;
++
++ /* Clear pending interrupts */
++ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0);
++
++ /* Reset FIFO */
++ sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG,
++ SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST);
++
++ /*
++ * Setup the transfer control register: Chip Select,
++ * polarities, etc.
++ */
++ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
++
++ if (spi->mode & SPI_CPOL)
++ reg |= SUN6I_TFR_CTL_CPOL;
++ else
++ reg &= ~SUN6I_TFR_CTL_CPOL;
++
++ if (spi->mode & SPI_CPHA)
++ reg |= SUN6I_TFR_CTL_CPHA;
++ else
++ reg &= ~SUN6I_TFR_CTL_CPHA;
++
++ if (spi->mode & SPI_LSB_FIRST)
++ reg |= SUN6I_TFR_CTL_FBS;
++ else
++ reg &= ~SUN6I_TFR_CTL_FBS;
++
++ /*
++ * If it's a TX only transfer, we don't want to fill the RX
++ * FIFO with bogus data
++ */
++ if (sspi->rx_buf)
++ reg &= ~SUN6I_TFR_CTL_DHB;
++ else
++ reg |= SUN6I_TFR_CTL_DHB;
++
++ /* We want to control the chip select manually */
++ reg |= SUN6I_TFR_CTL_CS_MANUAL;
++
++ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
++
++ /* Ensure that we have a parent clock fast enough */
++ mclk_rate = clk_get_rate(sspi->mclk);
++ if (mclk_rate < (2 * spi->max_speed_hz)) {
++ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
++ mclk_rate = clk_get_rate(sspi->mclk);
++ }
++
++ /*
++ * Setup clock divider.
++ *
++ * We have two choices there. Either we can use the clock
++ * divide rate 1, which is calculated thanks to this formula:
++ * SPI_CLK = MOD_CLK / (2 ^ cdr)
++ * Or we can use CDR2, which is calculated with the formula:
++ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
++ * Wether we use the former or the latter is set through the
++ * DRS bit.
++ *
++ * First try CDR2, and if we can't reach the expected
++ * frequency, fall back to CDR1.
++ */
++ div = mclk_rate / (2 * spi->max_speed_hz);
++ if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
++ if (div > 0)
++ div--;
++
++ reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS;
++ } else {
++ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
++ reg = SUN6I_CLK_CTL_CDR1(div);
++ }
++
++ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
++
++ /* Setup the transfer now... */
++ if (sspi->tx_buf)
++ tx_len = tfr->len;
++
++ /* Setup the counters */
++ sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len));
++ sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len));
++ sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG,
++ SUN6I_BURST_CTL_CNT_STC(tx_len));
++
++ /* Fill the TX FIFO */
++ sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH);
++
++ /* Enable the interrupts */
++ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC);
++
++ /* Start the transfer */
++ reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG);
++ sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH);
++
++ timeout = wait_for_completion_timeout(&sspi->done,
++ msecs_to_jiffies(1000));
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH);
++
++out:
++ sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0);
++
++ return ret;
++}
++
++static irqreturn_t sun6i_spi_handler(int irq, void *dev_id)
++{
++ struct sun6i_spi *sspi = dev_id;
++ u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG);
++
++ /* Transfer complete */
++ if (status & SUN6I_INT_CTL_TC) {
++ sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC);
++ complete(&sspi->done);
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static int sun6i_spi_runtime_resume(struct device *dev)
++{
++ struct spi_master *master = dev_get_drvdata(dev);
++ struct sun6i_spi *sspi = spi_master_get_devdata(master);
++ int ret;
++
++ ret = clk_prepare_enable(sspi->hclk);
++ if (ret) {
++ dev_err(dev, "Couldn't enable AHB clock\n");
++ goto out;
++ }
++
++ ret = clk_prepare_enable(sspi->mclk);
++ if (ret) {
++ dev_err(dev, "Couldn't enable module clock\n");
++ goto err;
++ }
++
++ ret = reset_control_deassert(sspi->rstc);
++ if (ret) {
++ dev_err(dev, "Couldn't deassert the device from reset\n");
++ goto err2;
++ }
++
++ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
++ SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
++
++ return 0;
++
++err2:
++ clk_disable_unprepare(sspi->mclk);
++err:
++ clk_disable_unprepare(sspi->hclk);
++out:
++ return ret;
++}
++
++static int sun6i_spi_runtime_suspend(struct device *dev)
++{
++ struct spi_master *master = dev_get_drvdata(dev);
++ struct sun6i_spi *sspi = spi_master_get_devdata(master);
++
++ reset_control_assert(sspi->rstc);
++ clk_disable_unprepare(sspi->mclk);
++ clk_disable_unprepare(sspi->hclk);
++
++ return 0;
++}
++
++static int sun6i_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct sun6i_spi *sspi;
++ struct resource *res;
++ int ret = 0, irq;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi));
++ if (!master) {
++ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(pdev, master);
++ sspi = spi_master_get_devdata(master);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(sspi->base_addr)) {
++ ret = PTR_ERR(sspi->base_addr);
++ goto err_free_master;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "No spi IRQ specified\n");
++ ret = -ENXIO;
++ goto err_free_master;
++ }
++
++ ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler,
++ 0, "sun6i-spi", sspi);
++ if (ret) {
++ dev_err(&pdev->dev, "Cannot request IRQ\n");
++ goto err_free_master;
++ }
++
++ sspi->master = master;
++ master->set_cs = sun6i_spi_set_cs;
++ master->transfer_one = sun6i_spi_transfer_one;
++ master->num_chipselect = 4;
++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
++ master->dev.of_node = pdev->dev.of_node;
++ master->auto_runtime_pm = true;
++
++ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(sspi->hclk)) {
++ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
++ ret = PTR_ERR(sspi->hclk);
++ goto err_free_master;
++ }
++
++ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
++ if (IS_ERR(sspi->mclk)) {
++ dev_err(&pdev->dev, "Unable to acquire module clock\n");
++ ret = PTR_ERR(sspi->mclk);
++ goto err_free_master;
++ }
++
++ init_completion(&sspi->done);
++
++ sspi->rstc = devm_reset_control_get(&pdev->dev, NULL);
++ if (IS_ERR(sspi->rstc)) {
++ dev_err(&pdev->dev, "Couldn't get reset controller\n");
++ ret = PTR_ERR(sspi->rstc);
++ goto err_free_master;
++ }
++
++ /*
++ * This wake-up/shutdown pattern is to be able to have the
++ * device woken up, even if runtime_pm is disabled
++ */
++ ret = sun6i_spi_runtime_resume(&pdev->dev);
++ if (ret) {
++ dev_err(&pdev->dev, "Couldn't resume the device\n");
++ goto err_free_master;
++ }
++
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(&pdev->dev);
++ pm_runtime_idle(&pdev->dev);
++
++ ret = devm_spi_register_master(&pdev->dev, master);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot register SPI master\n");
++ goto err_pm_disable;
++ }
++
++ return 0;
++
++err_pm_disable:
++ pm_runtime_disable(&pdev->dev);
++ sun6i_spi_runtime_suspend(&pdev->dev);
++err_free_master:
++ spi_master_put(master);
++ return ret;
++}
++
++static int sun6i_spi_remove(struct platform_device *pdev)
++{
++ pm_runtime_disable(&pdev->dev);
++
++ return 0;
++}
++
++static const struct of_device_id sun6i_spi_match[] = {
++ { .compatible = "allwinner,sun6i-a31-spi", },
++ {}
++};
++MODULE_DEVICE_TABLE(of, sun6i_spi_match);
++
++static const struct dev_pm_ops sun6i_spi_pm_ops = {
++ .runtime_resume = sun6i_spi_runtime_resume,
++ .runtime_suspend = sun6i_spi_runtime_suspend,
++};
++
++static struct platform_driver sun6i_spi_driver = {
++ .probe = sun6i_spi_probe,
++ .remove = sun6i_spi_remove,
++ .driver = {
++ .name = "sun6i-spi",
++ .owner = THIS_MODULE,
++ .of_match_table = sun6i_spi_match,
++ .pm = &sun6i_spi_pm_ops,
++ },
++};
++module_platform_driver(sun6i_spi_driver);
++
++MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
++MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
++MODULE_DESCRIPTION("Allwinner A31 SPI controller driver");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/146-2-spi-add-a10-spi.patch b/target/linux/sunxi/patches-3.14/146-2-spi-add-a10-spi.patch
new file mode 100644
index 0000000000..38461d4dc0
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/146-2-spi-add-a10-spi.patch
@@ -0,0 +1,571 @@
+From 1ae7667375308c27023d793372d6be1f3b89f5b5 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:53 +0100
+Subject: [PATCH] spi: sunxi: Add Allwinner A10 SPI controller driver
+
+The older Allwinner SoCs (A10, A13, A10s and A20) all have the same SPI
+controller.
+
+Unfortunately, this SPI controller, even though quite similar, is significantly
+different from the recently supported A31 SPI controller (different registers
+offset, split/merged registers, etc.). Supporting both controllers in a single
+driver would be unreasonable, hence the addition of a new driver.
+
+Like its more recent counterpart, it supports DMA, but the driver only does PIO
+until we have a dmaengine driver for this platform.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ .../devicetree/bindings/spi/spi-sun4i.txt | 24 ++
+ drivers/spi/Kconfig | 6 +
+ drivers/spi/Makefile | 1 +
+ drivers/spi/spi-sun4i.c | 477 +++++++++++++++++++++
+ 4 files changed, 508 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/spi/spi-sun4i.txt
+ create mode 100644 drivers/spi/spi-sun4i.c
+
+diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
+new file mode 100644
+index 0000000..de827f5
+--- /dev/null
++++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt
+@@ -0,0 +1,24 @@
++Allwinner A10 SPI controller
++
++Required properties:
++- compatible: Should be "allwinner,sun4-a10-spi".
++- reg: Should contain register location and length.
++- interrupts: Should contain interrupt.
++- clocks: phandle to the clocks feeding the SPI controller. Two are
++ needed:
++ - "ahb": the gated AHB parent clock
++ - "mod": the parent module clock
++- clock-names: Must contain the clock names described just above
++
++Example:
++
++spi1: spi@01c06000 {
++ compatible = "allwinner,sun4i-a10-spi";
++ reg = <0x01c06000 0x1000>;
++ interrupts = <11>;
++ clocks = <&ahb_gates 21>, <&spi1_clk>;
++ clock-names = "ahb", "mod";
++ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
++};
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index 58530d3..78adfae 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -446,6 +446,12 @@ config SPI_SIRF
+ help
+ SPI driver for CSR SiRFprimaII SoCs
+
++config SPI_SUN4I
++ tristate "Allwinner A10 SoCs SPI controller"
++ depends on ARCH_SUNXI || COMPILE_TEST
++ help
++ SPI driver for Allwinner sun4i, sun5i and sun7i SoCs
++
+ config SPI_SUN6I
+ tristate "Allwinner A31 SPI controller"
+ depends on ARCH_SUNXI || COMPILE_TEST
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index 13b6ccf9..65f4993 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -70,6 +70,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
+ obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
+ obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
+ obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
++obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
+ obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
+ obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
+ obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o
+diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c
+new file mode 100644
+index 0000000..3f82705
+--- /dev/null
++++ b/drivers/spi/spi-sun4i.c
+@@ -0,0 +1,477 @@
++/*
++ * Copyright (C) 2012 - 2014 Allwinner Tech
++ * Pan Nan <pannan@allwinnertech.com>
++ *
++ * Copyright (C) 2014 Maxime Ripard
++ * Maxime Ripard <maxime.ripard@free-electrons.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/pm_runtime.h>
++#include <linux/workqueue.h>
++
++#include <linux/spi/spi.h>
++
++#define SUN4I_FIFO_DEPTH 64
++
++#define SUN4I_RXDATA_REG 0x00
++
++#define SUN4I_TXDATA_REG 0x04
++
++#define SUN4I_CTL_REG 0x08
++#define SUN4I_CTL_ENABLE BIT(0)
++#define SUN4I_CTL_MASTER BIT(1)
++#define SUN4I_CTL_CPHA BIT(2)
++#define SUN4I_CTL_CPOL BIT(3)
++#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4)
++#define SUN4I_CTL_LMTF BIT(6)
++#define SUN4I_CTL_TF_RST BIT(8)
++#define SUN4I_CTL_RF_RST BIT(9)
++#define SUN4I_CTL_XCH BIT(10)
++#define SUN4I_CTL_CS_MASK 0x3000
++#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK)
++#define SUN4I_CTL_DHB BIT(15)
++#define SUN4I_CTL_CS_MANUAL BIT(16)
++#define SUN4I_CTL_CS_LEVEL BIT(17)
++#define SUN4I_CTL_TP BIT(18)
++
++#define SUN4I_INT_CTL_REG 0x0c
++#define SUN4I_INT_CTL_TC BIT(16)
++
++#define SUN4I_INT_STA_REG 0x10
++
++#define SUN4I_DMA_CTL_REG 0x14
++
++#define SUN4I_WAIT_REG 0x18
++
++#define SUN4I_CLK_CTL_REG 0x1c
++#define SUN4I_CLK_CTL_CDR2_MASK 0xff
++#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK)
++#define SUN4I_CLK_CTL_CDR1_MASK 0xf
++#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8)
++#define SUN4I_CLK_CTL_DRS BIT(12)
++
++#define SUN4I_BURST_CNT_REG 0x20
++#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff)
++
++#define SUN4I_XMIT_CNT_REG 0x24
++#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff)
++
++#define SUN4I_FIFO_STA_REG 0x28
++#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f
++#define SUN4I_FIFO_STA_RF_CNT_BITS 0
++#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f
++#define SUN4I_FIFO_STA_TF_CNT_BITS 16
++
++struct sun4i_spi {
++ struct spi_master *master;
++ void __iomem *base_addr;
++ struct clk *hclk;
++ struct clk *mclk;
++
++ struct completion done;
++
++ const u8 *tx_buf;
++ u8 *rx_buf;
++ int len;
++};
++
++static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg)
++{
++ return readl(sspi->base_addr + reg);
++}
++
++static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value)
++{
++ writel(value, sspi->base_addr + reg);
++}
++
++static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len)
++{
++ u32 reg, cnt;
++ u8 byte;
++
++ /* See how much data is available */
++ reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG);
++ reg &= SUN4I_FIFO_STA_RF_CNT_MASK;
++ cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS;
++
++ if (len > cnt)
++ len = cnt;
++
++ while (len--) {
++ byte = readb(sspi->base_addr + SUN4I_RXDATA_REG);
++ if (sspi->rx_buf)
++ *sspi->rx_buf++ = byte;
++ }
++}
++
++static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len)
++{
++ u8 byte;
++
++ if (len > sspi->len)
++ len = sspi->len;
++
++ while (len--) {
++ byte = sspi->tx_buf ? *sspi->tx_buf++ : 0;
++ writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG);
++ sspi->len--;
++ }
++}
++
++static void sun4i_spi_set_cs(struct spi_device *spi, bool enable)
++{
++ struct sun4i_spi *sspi = spi_master_get_devdata(spi->master);
++ u32 reg;
++
++ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
++
++ reg &= ~SUN4I_CTL_CS_MASK;
++ reg |= SUN4I_CTL_CS(spi->chip_select);
++
++ if (enable)
++ reg |= SUN4I_CTL_CS_LEVEL;
++ else
++ reg &= ~SUN4I_CTL_CS_LEVEL;
++
++ /*
++ * Even though this looks irrelevant since we are supposed to
++ * be controlling the chip select manually, this bit also
++ * controls the levels of the chip select for inactive
++ * devices.
++ *
++ * If we don't set it, the chip select level will go low by
++ * default when the device is idle, which is not really
++ * expected in the common case where the chip select is active
++ * low.
++ */
++ if (spi->mode & SPI_CS_HIGH)
++ reg &= ~SUN4I_CTL_CS_ACTIVE_LOW;
++ else
++ reg |= SUN4I_CTL_CS_ACTIVE_LOW;
++
++ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
++}
++
++static int sun4i_spi_transfer_one(struct spi_master *master,
++ struct spi_device *spi,
++ struct spi_transfer *tfr)
++{
++ struct sun4i_spi *sspi = spi_master_get_devdata(master);
++ unsigned int mclk_rate, div, timeout;
++ unsigned int tx_len = 0;
++ int ret = 0;
++ u32 reg;
++
++ /* We don't support transfer larger than the FIFO */
++ if (tfr->len > SUN4I_FIFO_DEPTH)
++ return -EINVAL;
++
++ reinit_completion(&sspi->done);
++ sspi->tx_buf = tfr->tx_buf;
++ sspi->rx_buf = tfr->rx_buf;
++ sspi->len = tfr->len;
++
++ /* Clear pending interrupts */
++ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0);
++
++
++ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
++
++ /* Reset FIFOs */
++ sun4i_spi_write(sspi, SUN4I_CTL_REG,
++ reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST);
++
++ /*
++ * Setup the transfer control register: Chip Select,
++ * polarities, etc.
++ */
++ if (spi->mode & SPI_CPOL)
++ reg |= SUN4I_CTL_CPOL;
++ else
++ reg &= ~SUN4I_CTL_CPOL;
++
++ if (spi->mode & SPI_CPHA)
++ reg |= SUN4I_CTL_CPHA;
++ else
++ reg &= ~SUN4I_CTL_CPHA;
++
++ if (spi->mode & SPI_LSB_FIRST)
++ reg |= SUN4I_CTL_LMTF;
++ else
++ reg &= ~SUN4I_CTL_LMTF;
++
++
++ /*
++ * If it's a TX only transfer, we don't want to fill the RX
++ * FIFO with bogus data
++ */
++ if (sspi->rx_buf)
++ reg &= ~SUN4I_CTL_DHB;
++ else
++ reg |= SUN4I_CTL_DHB;
++
++ /* We want to control the chip select manually */
++ reg |= SUN4I_CTL_CS_MANUAL;
++
++ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg);
++
++ /* Ensure that we have a parent clock fast enough */
++ mclk_rate = clk_get_rate(sspi->mclk);
++ if (mclk_rate < (2 * spi->max_speed_hz)) {
++ clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz);
++ mclk_rate = clk_get_rate(sspi->mclk);
++ }
++
++ /*
++ * Setup clock divider.
++ *
++ * We have two choices there. Either we can use the clock
++ * divide rate 1, which is calculated thanks to this formula:
++ * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1))
++ * Or we can use CDR2, which is calculated with the formula:
++ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
++ * Wether we use the former or the latter is set through the
++ * DRS bit.
++ *
++ * First try CDR2, and if we can't reach the expected
++ * frequency, fall back to CDR1.
++ */
++ div = mclk_rate / (2 * spi->max_speed_hz);
++ if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) {
++ if (div > 0)
++ div--;
++
++ reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS;
++ } else {
++ div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz);
++ reg = SUN4I_CLK_CTL_CDR1(div);
++ }
++
++ sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg);
++
++ /* Setup the transfer now... */
++ if (sspi->tx_buf)
++ tx_len = tfr->len;
++
++ /* Setup the counters */
++ sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len));
++ sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len));
++
++ /* Fill the TX FIFO */
++ sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH);
++
++ /* Enable the interrupts */
++ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC);
++
++ /* Start the transfer */
++ reg = sun4i_spi_read(sspi, SUN4I_CTL_REG);
++ sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH);
++
++ timeout = wait_for_completion_timeout(&sspi->done,
++ msecs_to_jiffies(1000));
++ if (!timeout) {
++ ret = -ETIMEDOUT;
++ goto out;
++ }
++
++ sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH);
++
++out:
++ sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0);
++
++ return ret;
++}
++
++static irqreturn_t sun4i_spi_handler(int irq, void *dev_id)
++{
++ struct sun4i_spi *sspi = dev_id;
++ u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG);
++
++ /* Transfer complete */
++ if (status & SUN4I_INT_CTL_TC) {
++ sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC);
++ complete(&sspi->done);
++ return IRQ_HANDLED;
++ }
++
++ return IRQ_NONE;
++}
++
++static int sun4i_spi_runtime_resume(struct device *dev)
++{
++ struct spi_master *master = dev_get_drvdata(dev);
++ struct sun4i_spi *sspi = spi_master_get_devdata(master);
++ int ret;
++
++ ret = clk_prepare_enable(sspi->hclk);
++ if (ret) {
++ dev_err(dev, "Couldn't enable AHB clock\n");
++ goto out;
++ }
++
++ ret = clk_prepare_enable(sspi->mclk);
++ if (ret) {
++ dev_err(dev, "Couldn't enable module clock\n");
++ goto err;
++ }
++
++ sun4i_spi_write(sspi, SUN4I_CTL_REG,
++ SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP);
++
++ return 0;
++
++err:
++ clk_disable_unprepare(sspi->hclk);
++out:
++ return ret;
++}
++
++static int sun4i_spi_runtime_suspend(struct device *dev)
++{
++ struct spi_master *master = dev_get_drvdata(dev);
++ struct sun4i_spi *sspi = spi_master_get_devdata(master);
++
++ clk_disable_unprepare(sspi->mclk);
++ clk_disable_unprepare(sspi->hclk);
++
++ return 0;
++}
++
++static int sun4i_spi_probe(struct platform_device *pdev)
++{
++ struct spi_master *master;
++ struct sun4i_spi *sspi;
++ struct resource *res;
++ int ret = 0, irq;
++
++ master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi));
++ if (!master) {
++ dev_err(&pdev->dev, "Unable to allocate SPI Master\n");
++ return -ENOMEM;
++ }
++
++ platform_set_drvdata(pdev, master);
++ sspi = spi_master_get_devdata(master);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ sspi->base_addr = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(sspi->base_addr)) {
++ ret = PTR_ERR(sspi->base_addr);
++ goto err_free_master;
++ }
++
++ irq = platform_get_irq(pdev, 0);
++ if (irq < 0) {
++ dev_err(&pdev->dev, "No spi IRQ specified\n");
++ ret = -ENXIO;
++ goto err_free_master;
++ }
++
++ ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler,
++ 0, "sun4i-spi", sspi);
++ if (ret) {
++ dev_err(&pdev->dev, "Cannot request IRQ\n");
++ goto err_free_master;
++ }
++
++ sspi->master = master;
++ master->set_cs = sun4i_spi_set_cs;
++ master->transfer_one = sun4i_spi_transfer_one;
++ master->num_chipselect = 4;
++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
++ master->dev.of_node = pdev->dev.of_node;
++ master->auto_runtime_pm = true;
++
++ sspi->hclk = devm_clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(sspi->hclk)) {
++ dev_err(&pdev->dev, "Unable to acquire AHB clock\n");
++ ret = PTR_ERR(sspi->hclk);
++ goto err_free_master;
++ }
++
++ sspi->mclk = devm_clk_get(&pdev->dev, "mod");
++ if (IS_ERR(sspi->mclk)) {
++ dev_err(&pdev->dev, "Unable to acquire module clock\n");
++ ret = PTR_ERR(sspi->mclk);
++ goto err_free_master;
++ }
++
++ init_completion(&sspi->done);
++
++ /*
++ * This wake-up/shutdown pattern is to be able to have the
++ * device woken up, even if runtime_pm is disabled
++ */
++ ret = sun4i_spi_runtime_resume(&pdev->dev);
++ if (ret) {
++ dev_err(&pdev->dev, "Couldn't resume the device\n");
++ goto err_free_master;
++ }
++
++ pm_runtime_set_active(&pdev->dev);
++ pm_runtime_enable(&pdev->dev);
++ pm_runtime_idle(&pdev->dev);
++
++ ret = devm_spi_register_master(&pdev->dev, master);
++ if (ret) {
++ dev_err(&pdev->dev, "cannot register SPI master\n");
++ goto err_pm_disable;
++ }
++
++ return 0;
++
++err_pm_disable:
++ pm_runtime_disable(&pdev->dev);
++ sun4i_spi_runtime_suspend(&pdev->dev);
++err_free_master:
++ spi_master_put(master);
++ return ret;
++}
++
++static int sun4i_spi_remove(struct platform_device *pdev)
++{
++ pm_runtime_disable(&pdev->dev);
++
++ return 0;
++}
++
++static const struct of_device_id sun4i_spi_match[] = {
++ { .compatible = "allwinner,sun4i-a10-spi", },
++ {}
++};
++MODULE_DEVICE_TABLE(of, sun4i_spi_match);
++
++static const struct dev_pm_ops sun4i_spi_pm_ops = {
++ .runtime_resume = sun4i_spi_runtime_resume,
++ .runtime_suspend = sun4i_spi_runtime_suspend,
++};
++
++static struct platform_driver sun4i_spi_driver = {
++ .probe = sun4i_spi_probe,
++ .remove = sun4i_spi_remove,
++ .driver = {
++ .name = "sun4i-spi",
++ .owner = THIS_MODULE,
++ .of_match_table = sun4i_spi_match,
++ .pm = &sun4i_spi_pm_ops,
++ },
++};
++module_platform_driver(sun4i_spi_driver);
++
++MODULE_AUTHOR("Pan Nan <pannan@allwinnertech.com>");
++MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
++MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/147-sun6i-enable-spi-in-defconfig.patch b/target/linux/sunxi/patches-3.14/147-sun6i-enable-spi-in-defconfig.patch
new file mode 100644
index 0000000000..2eac6a45cd
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/147-sun6i-enable-spi-in-defconfig.patch
@@ -0,0 +1,34 @@
+From 3aa7ff0de5bddc825406ffff49dc4a38b13ebac3 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Wed, 5 Feb 2014 14:05:07 +0100
+Subject: [PATCH] ARM: sunxi: Enable A31 SPI and SID in the defconfig
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/configs/sunxi_defconfig | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index 3e2259b..b5df4a5 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -24,6 +24,7 @@ CONFIG_IP_PNP_BOOTP=y
+ # CONFIG_WIRELESS is not set
+ CONFIG_DEVTMPFS=y
+ CONFIG_DEVTMPFS_MOUNT=y
++CONFIG_EEPROM_SUNXI_SID=y
+ CONFIG_NETDEVICES=y
+ CONFIG_SUN4I_EMAC=y
+ # CONFIG_NET_CADENCE is not set
+@@ -48,6 +49,8 @@ CONFIG_I2C=y
+ # CONFIG_I2C_COMPAT is not set
+ CONFIG_I2C_CHARDEV=y
+ CONFIG_I2C_MV64XXX=y
++CONFIG_SPI=y
++CONFIG_SPI_SUN6I=y
+ CONFIG_GPIO_SYSFS=y
+ # CONFIG_HWMON is not set
+ CONFIG_WATCHDOG=y
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/148-dt-sun7i-add-spi-muxing.patch b/target/linux/sunxi/patches-3.14/148-dt-sun7i-add-spi-muxing.patch
new file mode 100644
index 0000000000..f554267a5e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/148-dt-sun7i-add-spi-muxing.patch
@@ -0,0 +1,38 @@
+From c38fe0f410a59e194ef5e58429658506d853f1b4 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:58 +0100
+Subject: [PATCH] ARM: dt: sun7i: Add SPI muxing options
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 0f0ee58..6161fd8 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -571,6 +571,20 @@
+ allwinner,drive = <3>;
+ allwinner,pull = <0>;
+ };
++
++ spi1_pins_a: spi1@0 {
++ allwinner,pins = "PI16", "PI17", "PI18", "PI19";
++ allwinner,function = "spi1";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ spi2_pins_a: spi2@0 {
++ allwinner,pins = "PC19", "PC20", "PC21", "PC22";
++ allwinner,function = "spi2";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ timer@01c20c00 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/149-dt-sun7i-add-spi-on-olinuxinom.patch b/target/linux/sunxi/patches-3.14/149-dt-sun7i-add-spi-on-olinuxinom.patch
new file mode 100644
index 0000000000..e814af5aef
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/149-dt-sun7i-add-spi-on-olinuxinom.patch
@@ -0,0 +1,46 @@
+From 3f134732aaf4d785532c716f4ef7703d631a510b Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sat, 22 Feb 2014 22:35:59 +0100
+Subject: [PATCH] ARM: dts: sun7i: Enable the SPI controllers of the
+ A20-olinuxino-micro
+
+The A20-Olinuxino-micro has two SPI bus exposed on its UEXT connectors, enable
+them.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index b02a796..9d98316 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -18,7 +18,24 @@
+ model = "Olimex A20-Olinuxino Micro";
+ compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
+
++ aliases {
++ spi0 = &spi1;
++ spi1 = &spi2;
++ };
++
+ soc@01c00000 {
++ spi1: spi@01c06000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi1_pins_a>;
++ status = "okay";
++ };
++
++ spi2: spi@01c17000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&spi2_pins_a>;
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/150-dt-sun4i-add-ahci.patch b/target/linux/sunxi/patches-3.14/150-dt-sun4i-add-ahci.patch
new file mode 100644
index 0000000000..f82261d52d
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/150-dt-sun4i-add-ahci.patch
@@ -0,0 +1,87 @@
+From a9868f7ef1d3828e55de36cfeac2f84a77653a1e Mon Sep 17 00:00:00 2001
+From: Oliver Schinagl <oliver@schinagl.nl>
+Date: Tue, 3 Dec 2013 12:10:11 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add ahci / sata support
+
+This patch adds sunxi sata support to A10 boards that have such a connector.
+Some boards also feature a regulator via a GPIO and support for this is also
+added.
+
+Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-a1000.dts | 4 ++++
+ arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 10 ++++++++++
+ arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++
+ 3 files changed, 22 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
+index cbd2e13..d6ec839 100644
+--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
+@@ -35,6 +35,10 @@
+ };
+ };
+
++ ahci: sata@01c18000 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ emac_power_pin_a1000: emac_power_pin@0 {
+ allwinner,pins = "PH15";
+diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+index b139ee6..20407ac 100644
+--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+@@ -12,6 +12,7 @@
+
+ /dts-v1/;
+ /include/ "sun4i-a10.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Cubietech Cubieboard";
+@@ -33,6 +34,11 @@
+ };
+ };
+
++ ahci: sata@01c18000 {
++ target-supply = <&reg_ahci_5v>;
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_cubieboard: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+@@ -77,4 +83,8 @@
+ linux,default-trigger = "heartbeat";
+ };
+ };
++
++ reg_ahci_5v: ahci-5v {
++ status = "okay";
++ };
+ };
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 157bc09..18e09b41 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -388,6 +388,14 @@
+ #size-cells = <0>;
+ };
+
++ ahci: sata@01c18000 {
++ compatible = "allwinner,sun4i-a10-ahci";
++ reg = <0x01c18000 0x1000>;
++ interrupts = <56>;
++ clocks = <&pll6 0>, <&ahb_gates 25>;
++ status = "disabled";
++ };
++
+ spi3: spi@01c1f000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c1f000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/151-dt-sun7i-add-ahci.patch b/target/linux/sunxi/patches-3.14/151-dt-sun7i-add-ahci.patch
new file mode 100644
index 0000000000..d4685d93d5
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/151-dt-sun7i-add-ahci.patch
@@ -0,0 +1,147 @@
+From cf454a47b64ef78ff85b097c8cb404120c14e6a5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 3 Jan 2014 10:27:51 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add ahci / sata support
+
+This patch adds sunxi sata support to A20 boards that have such a connector.
+Some boards also feature a regulator via a GPIO and support for this is also
+added.
+
+Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 10 ++++++++++
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 19 +++++++++++++++++++
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 10 ++++++++++
+ arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
+ 4 files changed, 47 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+index 7bf4935..4bed115 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+@@ -13,12 +13,18 @@
+
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Cubietech Cubieboard2";
+ compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ ahci: sata@01c18000 {
++ target-supply = <&reg_ahci_5v>;
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_cubieboard2: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+@@ -74,4 +80,8 @@
+ gpios = <&pio 7 20 0>;
+ };
+ };
++
++ reg_ahci_5v: ahci-5v {
++ status = "okay";
++ };
+ };
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index 025ce52..ef5fed8 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -13,13 +13,26 @@
+
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Cubietech Cubietruck";
+ compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ ahci: sata@01c18000 {
++ target-supply = <&reg_ahci_5v>;
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
++ ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
++ allwinner,pins = "PH12";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
+ led_pins_cubietruck: led_pins@0 {
+ allwinner,pins = "PH7", "PH11", "PH20", "PH21";
+ allwinner,function = "gpio_out";
+@@ -90,4 +103,10 @@
+ gpios = <&pio 7 7 0>;
+ };
+ };
++
++ reg_ahci_5v: ahci-5v {
++ pinctrl-0 = <&ahci_pwr_pin_cubietruck>;
++ gpio = <&pio 7 12 0>;
++ status = "okay";
++ };
+ };
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index 9d98316..c9b0f37 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -13,6 +13,7 @@
+
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Olimex A20-Olinuxino Micro";
+@@ -36,6 +37,11 @@
+ status = "okay";
+ };
+
++ ahci: sata@01c18000 {
++ target-supply = <&reg_ahci_5v>;
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+@@ -105,4 +111,8 @@
+ default-state = "on";
+ };
+ };
++
++ reg_ahci_5v: ahci-5v {
++ status = "okay";
++ };
+ };
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 6161fd8..864b7c6 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -450,6 +450,14 @@
+ #size-cells = <0>;
+ };
+
++ ahci: sata@01c18000 {
++ compatible = "allwinner,sun4i-a10-ahci";
++ reg = <0x01c18000 0x1000>;
++ interrupts = <0 56 4>;
++ clocks = <&pll6 0>, <&ahb_gates 25>;
++ status = "disabled";
++ };
++
+ spi3: spi@01c1f000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c1f000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/155-wdt-add-new-compats.patch b/target/linux/sunxi/patches-3.14/155-wdt-add-new-compats.patch
new file mode 100644
index 0000000000..1635025522
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/155-wdt-add-new-compats.patch
@@ -0,0 +1,53 @@
+From ac45fe6b0056d1f92b7c7e5f13514b591a6a9caf Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sun, 2 Feb 2014 14:55:23 +0100
+Subject: [PATCH] wdt: sunxi: Introduce a new compatible for the A10 and A31
+
+For historical reasons, the Allwinner A10 compatibles are not following the
+patterns used for this other Allwinner SoCs.
+
+Introduce a new compatible following the usual pattern, and deprecate the olders.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt | 7 ++++---
+ drivers/watchdog/sunxi_wdt.c | 1 +
+ 2 files changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
+index e39cb26..6e8c937 100644
+--- a/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
++++ b/Documentation/devicetree/bindings/watchdog/sunxi-wdt.txt
+@@ -2,13 +2,14 @@ Allwinner SoCs Watchdog timer
+
+ Required properties:
+
+-- compatible : should be "allwinner,<soc-family>-wdt", the currently supported
+- SoC families being sun4i and sun6i
++- compatible : should be either "allwinner,sun4i-a10-wdt" or
++ "allwinner,sun6i-a31-wdt" (deprecated:
++ "allwinner,sun4i-wdt", "allwinner,sun6i-wdt")
+ - reg : Specifies base physical address and size of the registers.
+
+ Example:
+
+ wdt: watchdog@01c20c90 {
+- compatible = "allwinner,sun4i-wdt";
++ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
+index 76332d89..7c8923d 100644
+--- a/drivers/watchdog/sunxi_wdt.c
++++ b/drivers/watchdog/sunxi_wdt.c
+@@ -206,6 +206,7 @@ static void sunxi_wdt_shutdown(struct platform_device *pdev)
+
+ static const struct of_device_id sunxi_wdt_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-wdt" },
++ { .compatible = "allwinner,sun4i-a10-wdt" },
+ { /* sentinel */ }
+ };
+ MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/156-dt-sunxi-update-wdt-compats.patch b/target/linux/sunxi/patches-3.14/156-dt-sunxi-update-wdt-compats.patch
new file mode 100644
index 0000000000..6ac1a7e8f9
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/156-dt-sunxi-update-wdt-compats.patch
@@ -0,0 +1,86 @@
+From f722ea226581a75107ef16b46db1b7b5b999c93a Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Sun, 2 Feb 2014 14:55:25 +0100
+Subject: [PATCH] ARM: sunxi: dt: Update the watchdog compatibles
+
+The watchdog compatibles were following a different pattern than the one found
+in the other devices. Now that the driver supports the right pattern, switch to
+it in the DT.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 2 +-
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 2 +-
+ arch/arm/boot/dts/sun5i-a13.dtsi | 2 +-
+ arch/arm/boot/dts/sun6i-a31.dtsi | 2 +-
+ arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
+ 5 files changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 3ce650b..4b90a18 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -597,7 +597,7 @@
+ };
+
+ wdt: watchdog@01c20c90 {
+- compatible = "allwinner,sun4i-wdt";
++ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index 1795c26..45300a6 100644
+--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
++++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
+@@ -508,7 +508,7 @@
+ };
+
+ wdt: watchdog@01c20c90 {
+- compatible = "allwinner,sun4i-wdt";
++ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 8bc8e14..280ffee 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -454,7 +454,7 @@
+ };
+
+ wdt: watchdog@01c20c90 {
+- compatible = "allwinner,sun4i-wdt";
++ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index e4267bd..8441733 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -289,7 +289,7 @@
+ };
+
+ wdt1: watchdog@01c20ca0 {
+- compatible = "allwinner,sun6i-wdt";
++ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x01c20ca0 0x20>;
+ };
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 30b9aba..4981f5e 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -725,7 +725,7 @@
+ };
+
+ wdt: watchdog@01c20c90 {
+- compatible = "allwinner,sun4i-wdt";
++ compatible = "allwinner,sun4i-a10-wdt";
+ reg = <0x01c20c90 0x10>;
+ };
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/160-dt-sun4i-add-usb-host-bindings.patch b/target/linux/sunxi/patches-3.14/160-dt-sun4i-add-usb-host-bindings.patch
new file mode 100644
index 0000000000..9ca7345e20
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/160-dt-sun4i-add-usb-host-bindings.patch
@@ -0,0 +1,86 @@
+From 991b5f6d2af837b56adfcb3b3a1fe167647b9fdb Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Wed, 18 Sep 2013 00:30:04 +0200
+Subject: [PATCH] ARM: sun4i: dt: Add USB host bindings
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 52 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 18e09b41..27dc6ee 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -377,6 +377,38 @@
+ #size-cells = <0>;
+ };
+
++ usbphy: phy@01c13400 {
++ #phy-cells = <1>;
++ compatible = "allwinner,sun4i-a10-usb-phy";
++ reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
++ reg-names = "phy_ctrl", "pmu1", "pmu2";
++ clocks = <&usb_clk 8>;
++ clock-names = "usb_phy";
++ resets = <&usb_clk 1>, <&usb_clk 2>;
++ reset-names = "usb1_reset", "usb2_reset";
++ status = "disabled";
++ };
++
++ ehci0: usb@01c14000 {
++ compatible = "allwinner,sun4i-a10-ehci", "generic-ehci";
++ reg = <0x01c14000 0x100>;
++ interrupts = <39>;
++ clocks = <&ahb_gates 1>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ ohci0: usb@01c14400 {
++ compatible = "allwinner,sun4i-a10-ohci", "generic-ohci";
++ reg = <0x01c14400 0x100>;
++ interrupts = <64>;
++ clocks = <&usb_clk 6>, <&ahb_gates 2>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+@@ -396,6 +428,26 @@
+ status = "disabled";
+ };
+
++ ehci1: usb@01c1c000 {
++ compatible = "allwinner,sun4i-a10-ehci", "generic-ehci";
++ reg = <0x01c1c000 0x100>;
++ interrupts = <40>;
++ clocks = <&ahb_gates 3>;
++ phys = <&usbphy 2>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ ohci1: usb@01c1c400 {
++ compatible = "allwinner,sun4i-a10-ohci", "generic-ohci";
++ reg = <0x01c1c400 0x100>;
++ interrupts = <65>;
++ clocks = <&usb_clk 7>, <&ahb_gates 4>;
++ phys = <&usbphy 2>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
+ spi3: spi@01c1f000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c1f000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/161-dt-sun5i-add-usb-host-bindings.patch b/target/linux/sunxi/patches-3.14/161-dt-sun5i-add-usb-host-bindings.patch
new file mode 100644
index 0000000000..1beb5e14d8
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/161-dt-sun5i-add-usb-host-bindings.patch
@@ -0,0 +1,62 @@
+From 1b5a1b92147936c5aa2acec1683663b4d22e9ae6 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Tue, 24 Sep 2013 20:03:40 +0200
+Subject: [PATCH] ARM: sun5i: dt: Add USB host bindings
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 32 ++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/sun5i-a13.dtsi | 32 ++++++++++++++++++++++++++++++++
+ 2 files changed, 64 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index b2cb5dc..f34e0d8 100644
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 7102d12..0e9c239 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -320,6 +320,38 @@
+ #size-cells = <0>;
+ };
+
++ usbphy: phy@01c13400 {
++ #phy-cells = <1>;
++ compatible = "allwinner,sun5i-a13-usb-phy";
++ reg = <0x01c13400 0x10 0x01c14800 0x4>;
++ reg-names = "phy_ctrl", "pmu1";
++ clocks = <&usb_clk 8>;
++ clock-names = "usb_phy";
++ resets = <&usb_clk 1>;
++ reset-names = "usb1_reset";
++ status = "disabled";
++ };
++
++ ehci0: usb@01c14000 {
++ compatible = "allwinner,sun5i-a13-ehci", "generic-ehci";
++ reg = <0x01c14000 0x100>;
++ interrupts = <39>;
++ clocks = <&ahb_gates 1>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ ohci0: usb@01c14400 {
++ compatible = "allwinner,sun5i-a13-ohci", "generic-ohci";
++ reg = <0x01c14400 0x100>;
++ interrupts = <40>;
++ clocks = <&usb_clk 6>, <&ahb_gates 2>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/162-dt-sun7i-add-usb-host-bindings.patch b/target/linux/sunxi/patches-3.14/162-dt-sun7i-add-usb-host-bindings.patch
new file mode 100644
index 0000000000..b2b9d33caa
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/162-dt-sun7i-add-usb-host-bindings.patch
@@ -0,0 +1,86 @@
+From 008dffff2fa751c988671c4fc0c9a404ea808280 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Thu, 19 Sep 2013 21:36:10 +0200
+Subject: [PATCH] ARM: sun7i: dt: Add USB host bindings
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 52 ++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 52 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 864b7c6..4cc2f5f 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -439,6 +439,38 @@
+ #size-cells = <0>;
+ };
+
++ usbphy: phy@01c13400 {
++ #phy-cells = <1>;
++ compatible = "allwinner,sun7i-a20-usb-phy";
++ reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
++ reg-names = "phy_ctrl", "pmu1", "pmu2";
++ clocks = <&usb_clk 8>;
++ clock-names = "usb_phy";
++ resets = <&usb_clk 1>, <&usb_clk 2>;
++ reset-names = "usb1_reset", "usb2_reset";
++ status = "disabled";
++ };
++
++ ehci0: usb@01c14000 {
++ compatible = "allwinner,sun7i-a20-ehci", "generic-ehci";
++ reg = <0x01c14000 0x100>;
++ interrupts = <0 39 4>;
++ clocks = <&ahb_gates 1>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ ohci0: usb@01c14400 {
++ compatible = "allwinner,sun7i-a20-ohci", "generic-ohci";
++ reg = <0x01c14400 0x100>;
++ interrupts = <0 64 4>;
++ clocks = <&usb_clk 6>, <&ahb_gates 2>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+@@ -458,6 +490,26 @@
+ status = "disabled";
+ };
+
++ ehci1: usb@01c1c000 {
++ compatible = "allwinner,sun7i-a20-ehci", "generic-ehci";
++ reg = <0x01c1c000 0x100>;
++ interrupts = <0 40 4>;
++ clocks = <&ahb_gates 3>;
++ phys = <&usbphy 2>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
++ ohci1: usb@01c1c400 {
++ compatible = "allwinner,sun7i-a20-ohci", "generic-ohci";
++ reg = <0x01c1c400 0x100>;
++ interrupts = <0 65 4>;
++ clocks = <&usb_clk 7>, <&ahb_gates 4>;
++ phys = <&usbphy 2>;
++ phy-names = "usb";
++ status = "disabled";
++ };
++
+ spi3: spi@01c1f000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c1f000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/163-dt-sun4i-add-usb-host-to-boards.patch b/target/linux/sunxi/patches-3.14/163-dt-sun4i-add-usb-host-to-boards.patch
new file mode 100644
index 0000000000..220bed603e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/163-dt-sun4i-add-usb-host-to-boards.patch
@@ -0,0 +1,295 @@
+From f2509ec45a09013e300460a967f694561d169b98 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 11 Jan 2014 04:47:38 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add USB host nodes to hackberry dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Based on fex file settings, the fex file also contains a mysterious line:
+usb_hub_vcc_en_gpio = port:PB09<1><0><default><0>
+
+Which also clashes with usbc0, which has:
+usb_drv_vbus_gpio = port:PB09<1><0><default><0>
+
+So if usb does not work properly we need someone with a hackberry to look
+closer into this.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-hackberry.dts | 40 +++++++++++++++++++++++++++++++
+ 1 file changed, 40 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+index 6692d336..d7c17e4 100644
+--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
++++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+@@ -13,6 +13,7 @@
+
+ /dts-v1/;
+ /include/ "sun4i-a10.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Miniand Hackberry";
+@@ -35,6 +36,28 @@
+ };
+ };
+
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ pio: pinctrl@01c20800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&hackberry_hogs>;
+@@ -45,6 +68,13 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ usb2_vbus_pin_hackberry: usb2_vbus_pin@0 {
++ allwinner,pins = "PH12";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ uart0: serial@01c28000 {
+@@ -62,4 +92,14 @@
+ enable-active-high;
+ gpio = <&pio 7 19 0>;
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ pinctrl-0 = <&usb2_vbus_pin_hackberry>;
++ gpio = <&pio 7 12 0>;
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From dbf6ffa0b3832d91c2509e6753f485cedc791051 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 11 Jan 2014 05:15:06 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add USB host nodes to mini-xplus dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 31 ++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+index 70b3323..dd84a9e3 100644
+--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
++++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+@@ -13,16 +13,47 @@
+
+ /dts-v1/;
+ /include/ "sun4i-a10.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "PineRiver Mini X-Plus";
+ compatible = "pineriver,mini-xplus", "allwinner,sun4i-a10";
+
+ soc@01c00000 {
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From 528808ae38fee761be9f3451f51b457cb56d33ee Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 17 Feb 2014 20:41:04 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add USB host nodes to pcduino.dts
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-pcduino.dts | 31 +++++++++++++++++++++++++++++++
+ 1 file changed, 31 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+index f5692a3..255b47e 100644
+--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
++++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+@@ -12,6 +12,7 @@
+
+ /dts-v1/;
+ /include/ "sun4i-a10.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "LinkSprite pcDuino";
+@@ -33,6 +34,28 @@
+ };
+ };
+
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+@@ -45,4 +68,12 @@
+ status = "okay";
+ };
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From 58b778ce8cbc6fdb1fda5a6998fdd114a2b77cc9 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Wed, 18 Sep 2013 22:45:06 +0200
+Subject: [PATCH] ARM: sun4i: dt: Add USB host nodes to cubieboard dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+index 20407ac..4684cbe 100644
+--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+@@ -34,11 +34,33 @@
+ };
+ };
+
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_cubieboard: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+@@ -87,4 +109,12 @@
+ reg_ahci_5v: ahci-5v {
+ status = "okay";
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/164-dt-sun5i-add-usb-host-to-boards.patch b/target/linux/sunxi/patches-3.14/164-dt-sun5i-add-usb-host-to-boards.patch
new file mode 100644
index 0000000000..203b185d3c
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/164-dt-sun5i-add-usb-host-to-boards.patch
@@ -0,0 +1,143 @@
+From 9f193366e6094f6e2087c4767e7e413a395bf0d2 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Tue, 24 Sep 2013 20:07:53 +0200
+Subject: [PATCH] ARM: sun5i: dt: Add USB host nodes to A13-Olinuxino
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+index a4ba5ff..7a9187b 100644
+--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+@@ -13,12 +13,26 @@
+
+ /dts-v1/;
+ /include/ "sun5i-a13.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Olimex A13-Olinuxino";
+ compatible = "olimex,a13-olinuxino", "allwinner,sun5i-a13";
+
+ soc@01c00000 {
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PG9";
+@@ -26,6 +40,13 @@
+ allwinner,drive = <1>;
+ allwinner,pull = <0>;
+ };
++
++ usb1_vbus_pin_olinuxino: usb1_vbus_pin@0 {
++ allwinner,pins = "PG11";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ uart1: serial@01c28400 {
+@@ -63,4 +84,10 @@
+ default-state = "on";
+ };
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ pinctrl-0 = <&usb1_vbus_pin_olinuxino>;
++ gpio = <&pio 6 11 0>;
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From a3396ca280066e9a1ee74b36f5e376c945382bff Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 11 Jan 2014 05:21:43 +0100
+Subject: [PATCH] ARM: sun5i: dt: Add USB host nodes to a13-olinuxino-micro
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 27 +++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+index fe2ce0a..11169d5 100644
+--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+@@ -14,12 +14,26 @@
+
+ /dts-v1/;
+ /include/ "sun5i-a13.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+
+ / {
+ model = "Olimex A13-Olinuxino Micro";
+ compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
+
+ soc@01c00000 {
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_olinuxinom: led_pins@0 {
+ allwinner,pins = "PG9";
+@@ -27,6 +41,13 @@
+ allwinner,drive = <1>;
+ allwinner,pull = <0>;
+ };
++
++ usb1_vbus_pin_olinuxinom: usb1_vbus_pin@0 {
++ allwinner,pins = "PG11";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ uart1: serial@01c28400 {
+@@ -65,4 +86,10 @@
+ default-state = "on";
+ };
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ pinctrl-0 = <&usb1_vbus_pin_olinuxinom>;
++ gpio = <&pio 6 11 0>;
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/165-dt-sun7i-add-usb-host-to-boards.patch b/target/linux/sunxi/patches-3.14/165-dt-sun7i-add-usb-host-to-boards.patch
new file mode 100644
index 0000000000..d720f645d6
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/165-dt-sun7i-add-usb-host-to-boards.patch
@@ -0,0 +1,201 @@
+From 56de1b69bf6782338193e373cee06fff252b31da Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 17 Dec 2013 23:04:57 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add USB host nodes to cubietruck dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 30 ++++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index ef5fed8..cb25d3c 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -20,11 +20,33 @@
+ compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
+ allwinner,pins = "PH12";
+@@ -109,4 +131,12 @@
+ gpio = <&pio 7 12 0>;
+ status = "okay";
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From 8ce7da7026a24fe522abb3d7798cea12358946c0 Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Thu, 19 Sep 2013 21:29:45 +0200
+Subject: [PATCH] ARM: sun7i: dt: Add USB host nodes to cubieboard2 dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 30 +++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+index 4bed115..68de89f 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+@@ -20,11 +20,33 @@
+ compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_cubieboard2: led_pins@0 {
+ allwinner,pins = "PH20", "PH21";
+@@ -84,4 +106,12 @@
+ reg_ahci_5v: ahci-5v {
+ status = "okay";
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
+From e0e1a55781f7ba89a776456c8764782165e5efcc Mon Sep 17 00:00:00 2001
+From: Zalan Blenessy <zalan.blenessy@gmail.com>
+Date: Sun, 22 Dec 2013 17:08:10 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add USB host nodes to a20-olinuxino-micro dts
+
+Add nodes for the usb-phy and ehci- and ohci-usb-host controllers.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 30 +++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index c9b0f37..eeadf76 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -31,6 +31,20 @@
+ status = "okay";
+ };
+
++ usbphy: phy@01c13400 {
++ usb1_vbus-supply = <&reg_usb1_vbus>;
++ usb2_vbus-supply = <&reg_usb2_vbus>;
++ status = "okay";
++ };
++
++ ehci0: usb@01c14000 {
++ status = "okay";
++ };
++
++ ohci0: usb@01c14400 {
++ status = "okay";
++ };
++
+ spi2: spi@01c17000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_pins_a>;
+@@ -42,6 +56,14 @@
+ status = "okay";
+ };
+
++ ehci1: usb@01c1c000 {
++ status = "okay";
++ };
++
++ ohci1: usb@01c1c400 {
++ status = "okay";
++ };
++
+ pinctrl@01c20800 {
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+@@ -115,4 +137,12 @@
+ reg_ahci_5v: ahci-5v {
+ status = "okay";
+ };
++
++ reg_usb1_vbus: usb1-vbus {
++ status = "okay";
++ };
++
++ reg_usb2_vbus: usb2-vbus {
++ status = "okay";
++ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/170-input-add-sun4i-ts-driver.patch b/target/linux/sunxi/patches-3.14/170-input-add-sun4i-ts-driver.patch
new file mode 100644
index 0000000000..d97b02a306
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/170-input-add-sun4i-ts-driver.patch
@@ -0,0 +1,354 @@
+From afbd58e1b1219cbcbe2cc07273fc51f658891e9b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 23 Dec 2013 16:21:02 +0100
+Subject: [PATCH] input: Add new sun4i-ts driver for Allwinner sunxi SoC's rtp
+ controller
+
+Note the sun4i-ts controller is capable of detecting a second touch, but when
+a second touch is present then the accuracy becomes so bad the reported touch
+location is not useable.
+
+The original android driver contains some complicated heuristics using the
+aprox. distance between the 2 touches to see if the user is making a pinch
+open / close movement, and then reports emulated multi-touch events around
+the last touch coordinate (as the dual-touch coordinates are worthless).
+
+These kinds of heuristics are just asking for trouble (and don't belong
+in the kernel). So this driver offers straight forward, reliable single
+touch functionality only.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../bindings/input/touchscreen/sun4i.txt | 15 ++
+ drivers/input/touchscreen/Kconfig | 10 +
+ drivers/input/touchscreen/Makefile | 1 +
+ drivers/input/touchscreen/sun4i-ts.c | 262 +++++++++++++++++++++
+ 4 files changed, 288 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+ create mode 100644 drivers/input/touchscreen/sun4i-ts.c
+
+diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+new file mode 100644
+index 0000000..e45927e
+--- /dev/null
++++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+@@ -0,0 +1,15 @@
++sun4i resistive touchscreen controller
++--------------------------------------
++
++Required properties:
++ - compatible: "allwinner,sun4i-ts"
++ - reg: mmio address range of the chip
++ - interrupts: interrupt to which the chip is connected
++
++Example:
++
++ rtp: rtp@01c25000 {
++ compatible = "allwinner,sun4i-ts";
++ reg = <0x01c25000 0x100>;
++ interrupts = <29>;
++ };
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 07e9e82..f4c5ca3 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -906,6 +906,16 @@ config TOUCHSCREEN_STMPE
+ To compile this driver as a module, choose M here: the
+ module will be called stmpe-ts.
+
++config TOUCHSCREEN_SUN4I
++ tristate "Allwinner sun4i resistive touchscreen controller support"
++ depends on ARCH_SUNXI
++ help
++ This selects support for the resistive touchscreen controller
++ found on Allwinner sunxi SoCs.
++
++ To compile this driver as a module, choose M here: the
++ module will be called sun4i-ts.
++
+ config TOUCHSCREEN_SUR40
+ tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen"
+ depends on USB
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 62801f2..c8f7375 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -54,6 +54,7 @@ obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
+ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
++obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
+ obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
+ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
+ obj-$(CONFIG_TOUCHSCREEN_TNETV107X) += tnetv107x-ts.o
+diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
+new file mode 100644
+index 0000000..5945219
+--- /dev/null
++++ b/drivers/input/touchscreen/sun4i-ts.c
+@@ -0,0 +1,262 @@
++/*
++ * Allwinner sunxi resistive touchscreen controller driver
++ *
++ * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++/*
++ * The sun4i-ts controller is capable of detecting a second touch, but when a
++ * second touch is present then the accuracy becomes so bad the reported touch
++ * location is not useable.
++ *
++ * The original android driver contains some complicated heuristics using the
++ * aprox. distance between the 2 touches to see if the user is making a pinch
++ * open / close movement, and then reports emulated multi-touch events around
++ * the last touch coordinate (as the dual-touch coordinates are worthless).
++ *
++ * These kinds of heuristics are just asking for trouble (and don't belong
++ * in the kernel). So this driver offers straight forward, reliable single
++ * touch functionality only.
++ */
++
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define TP_CTRL0 0x00
++#define TP_CTRL1 0x04
++#define TP_CTRL2 0x08
++#define TP_CTRL3 0x0c
++#define TP_INT_FIFOC 0x10
++#define TP_INT_FIFOS 0x14
++#define TP_TPR 0x18
++#define TP_CDAT 0x1c
++#define TEMP_DATA 0x20
++#define TP_DATA 0x24
++
++/* TP_CTRL0 bits */
++#define ADC_FIRST_DLY(x) ((x) << 24) /* 8 bits */
++#define ADC_FIRST_DLY_MODE(x) ((x) << 23)
++#define ADC_CLK_SEL(x) ((x) << 22)
++#define ADC_CLK_DIV(x) ((x) << 20) /* 3 bits */
++#define FS_DIV(x) ((x) << 16) /* 4 bits */
++#define T_ACQ(x) ((x) << 0) /* 16 bits */
++
++/* TP_CTRL1 bits */
++#define STYLUS_UP_DEBOUN(x) ((x) << 12) /* 8 bits */
++#define STYLUS_UP_DEBOUN_EN(x) ((x) << 9)
++#define TOUCH_PAN_CALI_EN(x) ((x) << 6)
++#define TP_DUAL_EN(x) ((x) << 5)
++#define TP_MODE_EN(x) ((x) << 4)
++#define TP_ADC_SELECT(x) ((x) << 3)
++#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
++
++/* TP_CTRL2 bits */
++#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
++#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
++#define PRE_MEA_EN(x) ((x) << 24)
++#define PRE_MEA_THRE_CNT(x) ((x) << 0) /* 24 bits */
++
++/* TP_CTRL3 bits */
++#define FILTER_EN(x) ((x) << 2)
++#define FILTER_TYPE(x) ((x) << 0) /* 2 bits */
++
++/* TP_INT_FIFOC irq and fifo mask / control bits */
++#define TEMP_IRQ_EN(x) ((x) << 18)
++#define OVERRUN_IRQ_EN(x) ((x) << 17)
++#define DATA_IRQ_EN(x) ((x) << 16)
++#define TP_DATA_XY_CHANGE(x) ((x) << 13)
++#define FIFO_TRIG(x) ((x) << 8) /* 5 bits */
++#define DATA_DRQ_EN(x) ((x) << 7)
++#define FIFO_FLUSH(x) ((x) << 4)
++#define TP_UP_IRQ_EN(x) ((x) << 1)
++#define TP_DOWN_IRQ_EN(x) ((x) << 0)
++
++/* TP_INT_FIFOS irq and fifo status bits */
++#define TEMP_DATA_PENDING BIT(18)
++#define FIFO_OVERRUN_PENDING BIT(17)
++#define FIFO_DATA_PENDING BIT(16)
++#define TP_IDLE_FLG BIT(2)
++#define TP_UP_PENDING BIT(1)
++#define TP_DOWN_PENDING BIT(0)
++
++/* TP_TPR bits */
++#define TEMP_ENABLE(x) ((x) << 16)
++#define TEMP_PERIOD(x) ((x) << 0) /* t = x * 256 * 16 / clkin */
++
++struct sun4i_ts_data {
++ struct device *dev;
++ struct input_dev *input;
++ void __iomem *base;
++ unsigned int irq;
++ bool ignore_fifo_data;
++};
++
++static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
++{
++ struct sun4i_ts_data *ts = dev_id;
++ u32 reg_val, x, y;
++
++ reg_val = readl(ts->base + TP_INT_FIFOS);
++
++ if (reg_val & FIFO_DATA_PENDING) {
++ x = readl(ts->base + TP_DATA);
++ y = readl(ts->base + TP_DATA);
++ /* The 1st location reported after an up event is unreliable */
++ if (!ts->ignore_fifo_data) {
++ input_report_abs(ts->input, ABS_X, x);
++ input_report_abs(ts->input, ABS_Y, y);
++ /*
++ * The hardware has a separate down status bit, but
++ * that gets set before we get the first location,
++ * resulting in reporting a click on the old location.
++ */
++ input_report_key(ts->input, BTN_TOUCH, 1);
++ input_sync(ts->input);
++ } else {
++ ts->ignore_fifo_data = false;
++ }
++ }
++
++ if (reg_val & TP_UP_PENDING) {
++ ts->ignore_fifo_data = true;
++ input_report_key(ts->input, BTN_TOUCH, 0);
++ input_sync(ts->input);
++ }
++
++ writel(reg_val, ts->base + TP_INT_FIFOS);
++
++ return IRQ_HANDLED;
++}
++
++static int sun4i_ts_open(struct input_dev *dev)
++{
++ struct sun4i_ts_data *ts = input_get_drvdata(dev);
++
++ /* Flush, set trig level to 1, enable data and up irqs */
++ writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1),
++ ts->base + TP_INT_FIFOC);
++
++ return 0;
++}
++
++static void sun4i_ts_close(struct input_dev *dev)
++{
++ struct sun4i_ts_data *ts = input_get_drvdata(dev);
++
++ /* Deactivate all IRQs */
++ writel(0, ts->base + TP_INT_FIFOC);
++}
++
++static int sun4i_ts_probe(struct platform_device *pdev)
++{
++ struct sun4i_ts_data *ts;
++ struct device *dev = &pdev->dev;
++ int ret;
++
++ ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
++ if (!ts)
++ return -ENOMEM;
++
++ ts->dev = dev;
++ ts->ignore_fifo_data = true;
++
++ ts->input = devm_input_allocate_device(dev);
++ if (!ts->input)
++ return -ENOMEM;
++
++ ts->input->name = pdev->name;
++ ts->input->phys = "sun4i_ts/input0";
++ ts->input->open = sun4i_ts_open;
++ ts->input->close = sun4i_ts_close;
++ ts->input->id.bustype = BUS_HOST;
++ ts->input->id.vendor = 0x0001;
++ ts->input->id.product = 0x0001;
++ ts->input->id.version = 0x0100;
++ ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
++ set_bit(BTN_TOUCH, ts->input->keybit);
++ input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
++ input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
++ input_set_drvdata(ts->input, ts);
++
++ ts->base = devm_ioremap_resource(dev,
++ platform_get_resource(pdev, IORESOURCE_MEM, 0));
++ if (IS_ERR(ts->base))
++ return PTR_ERR(ts->base);
++
++ ts->irq = platform_get_irq(pdev, 0);
++ ret = devm_request_irq(dev, ts->irq, sun4i_ts_irq, 0, "sun4i-ts", ts);
++ if (ret)
++ return ret;
++
++ /*
++ * Select HOSC clk, clkin = clk / 6, adc samplefreq = clkin / 8192,
++ * t_acq = clkin / (16 * 64)
++ */
++ writel(ADC_CLK_SEL(0) | ADC_CLK_DIV(2) | FS_DIV(7) | T_ACQ(63),
++ ts->base + TP_CTRL0);
++
++ /*
++ * sensitive_adjust = 15 : max, which is not all that sensitive,
++ * tp_mode = 0 : only x and y coordinates, as we don't use dual touch
++ */
++ writel(TP_SENSITIVE_ADJUST(15) | TP_MODE_SELECT(0),
++ ts->base + TP_CTRL2);
++
++ /* Enable median filter, type 1 : 5/3 */
++ writel(FILTER_EN(1) | FILTER_TYPE(1), ts->base + TP_CTRL3);
++
++ /* Enable temperature measurement, period 1953 (2 seconds) */
++ writel(TEMP_ENABLE(1) | TEMP_PERIOD(1953), ts->base + TP_TPR);
++
++ /*
++ * Set stylus up debounce to aprox 10 ms, enable debounce, and
++ * finally enable tp mode.
++ */
++ writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
++ ts->base + TP_CTRL1);
++
++ ret = input_register_device(ts->input);
++ if (ret)
++ return ret;
++
++ platform_set_drvdata(pdev, ts);
++ return 0;
++}
++
++static const struct of_device_id sun4i_ts_of_match[] = {
++ { .compatible = "allwinner,sun4i-ts", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
++
++static struct platform_driver sun4i_ts_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "sun4i-ts",
++ .of_match_table = of_match_ptr(sun4i_ts_of_match),
++ },
++ .probe = sun4i_ts_probe,
++};
++
++module_platform_driver(sun4i_ts_driver);
++
++MODULE_DESCRIPTION("Allwinner sun4i resistive touchscreen controller driver");
++MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/171-input-add-temp-sensor-support.patch b/target/linux/sunxi/patches-3.14/171-input-add-temp-sensor-support.patch
new file mode 100644
index 0000000000..3d0bdad31f
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/171-input-add-temp-sensor-support.patch
@@ -0,0 +1,264 @@
+From d8b5553dbf60e519d565dbd83327b08865e960e2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 27 Dec 2013 15:25:28 +0100
+Subject: [PATCH] input: sun4i-ts: Add support for temperature sensor
+
+The sun4i resisitive touchscreen controller also comes with a built-in
+temperature sensor. This commit adds support for it.
+
+This commit also introduces a new "ts-attached" device-tree property,
+when this is not set, the input part of the driver won't register. This way
+the internal temperature sensor can be used to measure the SoC temperature
+independent of there actually being a touchscreen attached to the controller.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../bindings/input/touchscreen/sun4i.txt | 5 +
+ drivers/input/touchscreen/sun4i-ts.c | 140 ++++++++++++++++-----
+ 2 files changed, 114 insertions(+), 31 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+index e45927e..6bac67b 100644
+--- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
++++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+@@ -6,10 +6,15 @@ Required properties:
+ - reg: mmio address range of the chip
+ - interrupts: interrupt to which the chip is connected
+
++Optional properties:
++ - allwinner,ts-attached: boolean indicating that an actual touchscreen is
++ attached to the controller
++
+ Example:
+
+ rtp: rtp@01c25000 {
+ compatible = "allwinner,sun4i-ts";
+ reg = <0x01c25000 0x100>;
+ interrupts = <29>;
++ allwinner,ts-attached;
+ };
+diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
+index 5945219..16cbb01 100644
+--- a/drivers/input/touchscreen/sun4i-ts.c
++++ b/drivers/input/touchscreen/sun4i-ts.c
+@@ -3,6 +3,9 @@
+ *
+ * Copyright (C) 2013 - 2014 Hans de Goede <hdegoede@redhat.com>
+ *
++ * The hwmon parts are based on work by Corentin LABBE which is:
++ * Copyright (C) 2013 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -30,6 +33,7 @@
+ */
+
+ #include <linux/err.h>
++#include <linux/hwmon.h>
+ #include <linux/init.h>
+ #include <linux/input.h>
+ #include <linux/interrupt.h>
+@@ -106,14 +110,12 @@ struct sun4i_ts_data {
+ void __iomem *base;
+ unsigned int irq;
+ bool ignore_fifo_data;
++ int temp_data;
+ };
+
+-static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
++static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
+ {
+- struct sun4i_ts_data *ts = dev_id;
+- u32 reg_val, x, y;
+-
+- reg_val = readl(ts->base + TP_INT_FIFOS);
++ u32 x, y;
+
+ if (reg_val & FIFO_DATA_PENDING) {
+ x = readl(ts->base + TP_DATA);
+@@ -139,6 +141,20 @@ static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
+ input_report_key(ts->input, BTN_TOUCH, 0);
+ input_sync(ts->input);
+ }
++}
++
++static irqreturn_t sun4i_ts_irq(int irq, void *dev_id)
++{
++ struct sun4i_ts_data *ts = dev_id;
++ u32 reg_val;
++
++ reg_val = readl(ts->base + TP_INT_FIFOS);
++
++ if (reg_val & TEMP_DATA_PENDING)
++ ts->temp_data = readl(ts->base + TEMP_DATA);
++
++ if (ts->input)
++ sun4i_ts_irq_handle_input(ts, reg_val);
+
+ writel(reg_val, ts->base + TP_INT_FIFOS);
+
+@@ -149,9 +165,9 @@ static int sun4i_ts_open(struct input_dev *dev)
+ {
+ struct sun4i_ts_data *ts = input_get_drvdata(dev);
+
+- /* Flush, set trig level to 1, enable data and up irqs */
+- writel(DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) | TP_UP_IRQ_EN(1),
+- ts->base + TP_INT_FIFOC);
++ /* Flush, set trig level to 1, enable temp, data and up irqs */
++ writel(TEMP_IRQ_EN(1) | DATA_IRQ_EN(1) | FIFO_TRIG(1) | FIFO_FLUSH(1) |
++ TP_UP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
+
+ return 0;
+ }
+@@ -160,15 +176,48 @@ static void sun4i_ts_close(struct input_dev *dev)
+ {
+ struct sun4i_ts_data *ts = input_get_drvdata(dev);
+
+- /* Deactivate all IRQs */
+- writel(0, ts->base + TP_INT_FIFOC);
++ /* Deactivate all input IRQs */
++ writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
++}
++
++static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
++ char *buf)
++{
++ struct sun4i_ts_data *ts = dev_get_drvdata(dev);
++
++ /* No temp_data until the first irq */
++ if (ts->temp_data == -1)
++ return -EAGAIN;
++
++ return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
++}
++
++static ssize_t show_temp_label(struct device *dev,
++ struct device_attribute *devattr, char *buf)
++{
++ return sprintf(buf, "SoC temperature\n");
+ }
+
++static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL);
++static DEVICE_ATTR(temp1_label, S_IRUGO, show_temp_label, NULL);
++
++static struct attribute *sun4i_ts_attrs[] = {
++ &dev_attr_temp1_input.attr,
++ &dev_attr_temp1_label.attr,
++ NULL
++};
++ATTRIBUTE_GROUPS(sun4i_ts);
++
+ static int sun4i_ts_probe(struct platform_device *pdev)
+ {
+ struct sun4i_ts_data *ts;
+ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ struct device *hwmon;
+ int ret;
++ bool ts_attached;
++
++ ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
+
+ ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
+ if (!ts)
+@@ -176,24 +225,27 @@ static int sun4i_ts_probe(struct platform_device *pdev)
+
+ ts->dev = dev;
+ ts->ignore_fifo_data = true;
+-
+- ts->input = devm_input_allocate_device(dev);
+- if (!ts->input)
+- return -ENOMEM;
+-
+- ts->input->name = pdev->name;
+- ts->input->phys = "sun4i_ts/input0";
+- ts->input->open = sun4i_ts_open;
+- ts->input->close = sun4i_ts_close;
+- ts->input->id.bustype = BUS_HOST;
+- ts->input->id.vendor = 0x0001;
+- ts->input->id.product = 0x0001;
+- ts->input->id.version = 0x0100;
+- ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
+- set_bit(BTN_TOUCH, ts->input->keybit);
+- input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
+- input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
+- input_set_drvdata(ts->input, ts);
++ ts->temp_data = -1;
++
++ if (ts_attached) {
++ ts->input = devm_input_allocate_device(dev);
++ if (!ts->input)
++ return -ENOMEM;
++
++ ts->input->name = pdev->name;
++ ts->input->phys = "sun4i_ts/input0";
++ ts->input->open = sun4i_ts_open;
++ ts->input->close = sun4i_ts_close;
++ ts->input->id.bustype = BUS_HOST;
++ ts->input->id.vendor = 0x0001;
++ ts->input->id.product = 0x0001;
++ ts->input->id.version = 0x0100;
++ ts->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
++ set_bit(BTN_TOUCH, ts->input->keybit);
++ input_set_abs_params(ts->input, ABS_X, 0, 4095, 0, 0);
++ input_set_abs_params(ts->input, ABS_Y, 0, 4095, 0, 0);
++ input_set_drvdata(ts->input, ts);
++ }
+
+ ts->base = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+@@ -232,14 +284,39 @@ static int sun4i_ts_probe(struct platform_device *pdev)
+ writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
+ ts->base + TP_CTRL1);
+
+- ret = input_register_device(ts->input);
+- if (ret)
+- return ret;
++ hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
++ ts, sun4i_ts_groups);
++ if (IS_ERR(hwmon))
++ return PTR_ERR(hwmon);
++
++ writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
++
++ if (ts_attached) {
++ ret = input_register_device(ts->input);
++ if (ret) {
++ writel(0, ts->base + TP_INT_FIFOC);
++ return ret;
++ }
++ }
+
+ platform_set_drvdata(pdev, ts);
+ return 0;
+ }
+
++static int sun4i_ts_remove(struct platform_device *pdev)
++{
++ struct sun4i_ts_data *ts = platform_get_drvdata(pdev);
++
++ /* Explicit unregister to avoid open/close changing the imask later */
++ if (ts->input)
++ input_unregister_device(ts->input);
++
++ /* Deactivate all IRQs */
++ writel(0, ts->base + TP_INT_FIFOC);
++
++ return 0;
++}
++
+ static const struct of_device_id sun4i_ts_of_match[] = {
+ { .compatible = "allwinner,sun4i-ts", },
+ { /* sentinel */ }
+@@ -253,6 +330,7 @@ static struct platform_driver sun4i_ts_driver = {
+ .of_match_table = of_match_ptr(sun4i_ts_of_match),
+ },
+ .probe = sun4i_ts_probe,
++ .remove = sun4i_ts_remove,
+ };
+
+ module_platform_driver(sun4i_ts_driver);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/172-input-add-lradc-keys-driver.patch b/target/linux/sunxi/patches-3.14/172-input-add-lradc-keys-driver.patch
new file mode 100644
index 0000000000..ee8f80668f
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/172-input-add-lradc-keys-driver.patch
@@ -0,0 +1,339 @@
+From 3f8fd9b9e2daefb7be4c46369f86af1c7bb2f1ca Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 1 Jan 2014 19:44:49 +0100
+Subject: [PATCH] input: Add new sun4i-lradc-keys driver
+
+Allwinnner sunxi SoCs have a low resolution adc (called lradc) which is
+specifically designed to have various (tablet) keys (ie home, back, search,
+etc). attached to it using a resistor network. This adds a driver for this.
+
+There are 2 channels, currently this driver only supports chan0 since there
+are no boards known to use chan1. The devicetree properties are already
+prefixed with chan0 as preparation for chan1 support in the future.
+
+This has been tested on an olimex a10s-olinuxino-micro, a13-olinuxino, and
+a20-olinuxino-micro.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../devicetree/bindings/input/sun4i-lradc-keys.txt | 22 ++
+ drivers/input/keyboard/Kconfig | 10 +
+ drivers/input/keyboard/Makefile | 1 +
+ drivers/input/keyboard/sun4i-lradc-keys.c | 243 +++++++++++++++++++++
+ 4 files changed, 276 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+ create mode 100644 drivers/input/keyboard/sun4i-lradc-keys.c
+
+diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+new file mode 100644
+index 0000000..7801264
+--- /dev/null
++++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+@@ -0,0 +1,22 @@
++Allwinner sun4i low res adc attached tablet keys
++------------------------------------------------
++
++Required properties:
++ - compatible: "allwinner,sun4i-lradc-keys"
++ - reg: mmio address range of the chip
++ - interrupts: interrupt to which the chip is connected
++ - allwinner,chan0-step: step in mV between keys must be 150 or 200
++ - linux,chan0-keycodes: array of dt-bindings/input/input.h KEY_ codes
++
++Example:
++
++#include <dt-bindings/input/input.h>
++
++ lradc: lradc@01c22800 {
++ compatible = "allwinner,sun4i-lradc-keys";
++ reg = <0x01c22800 0x100>;
++ interrupts = <31>;
++ allwinner,chan0-step = <200>;
++ linux,chan0-keycodes = <KEY_VOLUMEUP KEY_VOLUMEDOWN
++ KEY_MENU KEY_ENTER KEY_HOME>;
++ };
+diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
+index a673c9f..d8a51cd 100644
+--- a/drivers/input/keyboard/Kconfig
++++ b/drivers/input/keyboard/Kconfig
+@@ -544,6 +544,16 @@ config KEYBOARD_STMPE
+ To compile this driver as a module, choose M here: the module will be
+ called stmpe-keypad.
+
++config KEYBOARD_SUN4I_LRADC
++ tristate "Allwinner sun4i low res adc attached tablet keys support"
++ depends on ARCH_SUNXI
++ help
++ This selects support for the Allwinner low res adc attached tablet
++ keys found on Allwinner sunxi SoCs.
++
++ To compile this driver as a module, choose M here: the
++ module will be called sun4i-lradc-keys.
++
+ config KEYBOARD_DAVINCI
+ tristate "TI DaVinci Key Scan"
+ depends on ARCH_DAVINCI_DM365
+diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
+index a699b61..f3265bd 100644
+--- a/drivers/input/keyboard/Makefile
++++ b/drivers/input/keyboard/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
+ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
+ obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
+ obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
++obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
+ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
+ obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
+ obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
+diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
+new file mode 100644
+index 0000000..5c55e17
+--- /dev/null
++++ b/drivers/input/keyboard/sun4i-lradc-keys.c
+@@ -0,0 +1,243 @@
++/*
++ * Allwinner sun4i low res adc attached tablet keys driver
++ *
++ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++/*
++ * Allwinnner sunxi SoCs have a lradc which is specifically designed to have
++ * various (tablet) keys (ie home, back, search, etc). attached to it using
++ * a resistor network. This driver is for the keys on such boards.
++ *
++ * There are 2 channels, currently this driver only supports chan0 since there
++ * are no boards known to use chan1. The devicetree properties are already
++ * prefixed with chan0 as preparation for chan1 support in the future.
++ */
++
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of_platform.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#define LRADC_CTRL 0x00
++#define LRADC_INTC 0x04
++#define LRADC_INTS 0x08
++#define LRADC_DATA0 0x0c
++#define LRADC_DATA1 0x10
++
++/* LRADC_CTRL bits */
++#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */
++#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */
++#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
++#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
++#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
++#define HOLD_EN(x) ((x) << 6)
++#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
++#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
++#define ENABLE(x) ((x) << 0)
++
++/* LRADC_INTC and LRADC_INTS bits */
++#define CHAN1_KEYUP_IRQ BIT(12)
++#define CHAN1_ALRDY_HOLD_IRQ BIT(11)
++#define CHAN1_HOLD_IRQ BIT(10)
++#define CHAN1_KEYDOWN_IRQ BIT(9)
++#define CHAN1_DATA_IRQ BIT(8)
++#define CHAN0_KEYUP_IRQ BIT(4)
++#define CHAN0_ALRDY_HOLD_IRQ BIT(3)
++#define CHAN0_HOLD_IRQ BIT(2)
++#define CHAN0_KEYDOWN_IRQ BIT(1)
++#define CHAN0_DATA_IRQ BIT(0)
++
++#define MAX_KEYS 13
++
++/* Lookup table to map the adc val to a keycode index for 150 mv step size */
++static const u8 adc_val_to_key_index_step150[64] = {
++ 0, 0, 0,
++ 1, 1, 1, 1, 1,
++ 2, 2, 2, 2, 2,
++ 3, 3, 3, 3,
++ 4, 4, 4, 4, 4,
++ 5, 5, 5, 5, 5,
++ 6, 6, 6, 6, 6,
++ 7, 7, 7, 7,
++ 8, 8, 8, 8, 8,
++ 9, 9, 9, 9, 9,
++ 10, 10, 10, 10,
++ 11, 11, 11, 11,
++ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12
++};
++
++/* Lookup table to map the adc val to a keycode index for 200 mv step size */
++static const u8 adc_val_to_key_index_step200[64] = {
++ 0, 0, 0, 0, 0, 0, 0, 0,
++ 1, 1, 1, 1, 1, 1, 1,
++ 2, 2, 2, 2, 2, 2, 2,
++ 3, 3, 3, 3, 3, 3,
++ 4, 4, 4, 4, 4, 4,
++ 5, 5, 5, 5, 5, 5,
++ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
++ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
++};
++
++struct sun4i_lradc_data {
++ struct device *dev;
++ struct input_dev *input;
++ void __iomem *base;
++ u32 chan0_step;
++ u32 chan0_keycode;
++ u32 chan0_keycodes[MAX_KEYS];
++};
++
++static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
++{
++ struct sun4i_lradc_data *lradc = dev_id;
++ u32 ints, val;
++
++ ints = readl(lradc->base + LRADC_INTS);
++
++ /*
++ * lradc supports only one keypress at a time, release does not give
++ * any info as to which key was released, so we cache the keycode.
++ */
++ if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
++ val = readl(lradc->base + LRADC_DATA0);
++ if (lradc->chan0_step == 150)
++ val = adc_val_to_key_index_step150[val];
++ else
++ val = adc_val_to_key_index_step200[val];
++
++ lradc->chan0_keycode = lradc->chan0_keycodes[val];
++ input_report_key(lradc->input, lradc->chan0_keycode, 1);
++ }
++
++ if (ints & CHAN0_KEYUP_IRQ) {
++ input_report_key(lradc->input, lradc->chan0_keycode, 0);
++ lradc->chan0_keycode = 0;
++ }
++
++ input_sync(lradc->input);
++
++ writel(ints, lradc->base + LRADC_INTS);
++
++ return IRQ_HANDLED;
++}
++
++static int sun4i_lradc_open(struct input_dev *dev)
++{
++ struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
++
++ /*
++ * Set sample time to 16 ms / 62.5 Hz. Wait 2 * 16 ms for key to
++ * stabilize on press, wait (1 + 1) * 16 ms for key release
++ */
++ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
++ SAMPLE_RATE(2) | ENABLE(1), lradc->base + LRADC_CTRL);
++
++ writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
++
++ return 0;
++}
++
++static void sun4i_lradc_close(struct input_dev *dev)
++{
++ struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
++
++ /* Disable lradc, leave other settings unchanged */
++ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
++ SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
++ writel(0, lradc->base + LRADC_INTC);
++}
++
++static int sun4i_lradc_probe(struct platform_device *pdev)
++{
++ struct sun4i_lradc_data *lradc;
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ int i, ret;
++
++ lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
++ if (!lradc)
++ return -ENOMEM;
++
++ ret = of_property_read_u32(np, "allwinner,chan0-step",
++ &lradc->chan0_step);
++ if (ret || (lradc->chan0_step != 150 && lradc->chan0_step != 200)) {
++ dev_err(dev, "Invalid allwinner,chan0-step dt-property\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < MAX_KEYS; i++)
++ of_property_read_u32_index(np, "linux,chan0-keycodes",
++ i, &lradc->chan0_keycodes[i]);
++
++ lradc->dev = dev;
++ lradc->input = devm_input_allocate_device(dev);
++ if (!lradc->input)
++ return -ENOMEM;
++
++ lradc->input->name = pdev->name;
++ lradc->input->phys = "sun4i_lradc/input0";
++ lradc->input->open = sun4i_lradc_open;
++ lradc->input->close = sun4i_lradc_close;
++ lradc->input->id.bustype = BUS_HOST;
++ lradc->input->id.vendor = 0x0001;
++ lradc->input->id.product = 0x0001;
++ lradc->input->id.version = 0x0100;
++ lradc->input->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY);
++ for (i = 0; i < MAX_KEYS; i++)
++ set_bit(lradc->chan0_keycodes[i], lradc->input->keybit);
++ input_set_drvdata(lradc->input, lradc);
++
++ lradc->base = devm_ioremap_resource(dev,
++ platform_get_resource(pdev, IORESOURCE_MEM, 0));
++ if (IS_ERR(lradc->base))
++ return PTR_ERR(lradc->base);
++
++ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), sun4i_lradc_irq,
++ 0, "sun4i-lradc-keys", lradc);
++ if (ret)
++ return ret;
++
++ ret = input_register_device(lradc->input);
++ if (ret)
++ return ret;
++
++ platform_set_drvdata(pdev, lradc);
++ return 0;
++}
++
++static const struct of_device_id sun4i_lradc_of_match[] = {
++ { .compatible = "allwinner,sun4i-lradc-keys", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
++
++static struct platform_driver sun4i_lradc_driver = {
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "sun4i-lradc-keys",
++ .of_match_table = of_match_ptr(sun4i_lradc_of_match),
++ },
++ .probe = sun4i_lradc_probe,
++};
++
++module_platform_driver(sun4i_lradc_driver);
++
++MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver");
++MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/173-1-dt-sun4i-add-lradc-node.patch b/target/linux/sunxi/patches-3.14/173-1-dt-sun4i-add-lradc-node.patch
new file mode 100644
index 0000000000..1c7bc810f7
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/173-1-dt-sun4i-add-lradc-node.patch
@@ -0,0 +1,31 @@
+From 87d0c26803eec56971c8a7e6299aefc4d72dfb3c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 1 Jan 2014 19:51:36 +0100
+Subject: [PATCH] ARM: dts: sun4i: Add lradc node
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 7014518..3ce650b 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -607,6 +607,13 @@
+ interrupts = <24>;
+ };
+
++ lradc: lradc@01c22800 {
++ compatible = "allwinner,sun4i-lradc-keys";
++ reg = <0x01c22800 0x100>;
++ interrupts = <31>;
++ status = "disabled";
++ };
++
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun4i-sid";
+ reg = <0x01c23800 0x10>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/173-2-dt-sun5i-add-lradc-node.patch b/target/linux/sunxi/patches-3.14/173-2-dt-sun5i-add-lradc-node.patch
new file mode 100644
index 0000000000..fbb0a32ca4
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/173-2-dt-sun5i-add-lradc-node.patch
@@ -0,0 +1,64 @@
+From 9041b1f6118b32929e6357affb53db28439a11e7 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 1 Jan 2014 19:50:33 +0100
+Subject: [PATCH] ARM: dts: sun5i: Add lradc node
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 8 ++++++++
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 7 +++++++
+ arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 8 ++++++++
+ arch/arm/boot/dts/sun5i-a13.dtsi | 7 +++++++
+ 4 files changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+index 5bc25c7..93c6778 100644
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index 8ba1ed7..1795c26 100644
+diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+index 177196c..c2c455d 100644
+--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+@@ -14,6 +14,7 @@
+ /dts-v1/;
+ /include/ "sun5i-a13.dtsi"
+ /include/ "sunxi-common-regulators.dtsi"
++#include <dt-bindings/input/input.h>
+
+ / {
+ model = "Olimex A13-Olinuxino";
+@@ -64,6 +65,13 @@
+ };
+ };
+
++ lradc: lradc@01c22800 {
++ allwinner,chan0-step = <200>;
++ linux,chan0-keycodes = <KEY_VOLUMEUP KEY_VOLUMEDOWN
++ KEY_MENU KEY_ENTER KEY_HOME>;
++ status = "okay";
++ };
++
+ uart1: serial@01c28400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 6fc84a4..8bc8e14 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -458,6 +458,13 @@
+ reg = <0x01c20c90 0x10>;
+ };
+
++ lradc: lradc@01c22800 {
++ compatible = "allwinner,sun4i-lradc-keys";
++ reg = <0x01c22800 0x100>;
++ interrupts = <31>;
++ status = "disabled";
++ };
++
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun4i-sid";
+ reg = <0x01c23800 0x10>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/173-3-dt-sun7i-add-lradc-node.patch b/target/linux/sunxi/patches-3.14/173-3-dt-sun7i-add-lradc-node.patch
new file mode 100644
index 0000000000..417dddc2c0
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/173-3-dt-sun7i-add-lradc-node.patch
@@ -0,0 +1,59 @@
+From 98e21d18a26032912bf6c979f084c200a94e976b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 1 Jan 2014 20:26:21 +0100
+Subject: [PATCH] ARM: dts: sun7i: Add lradc node
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 9 +++++++++
+ arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index 822cbe2..15f1f3f 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -14,6 +14,7 @@
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
+ /include/ "sunxi-common-regulators.dtsi"
++#include <dt-bindings/input/input.h>
+
+ / {
+ model = "Olimex A20-Olinuxino Micro";
+@@ -96,6 +97,14 @@
+ };
+ };
+
++ lradc: lradc@01c22800 {
++ allwinner,chan0-step = <200>;
++ linux,chan0-keycodes = <KEY_VOLUMEUP KEY_VOLUMEDOWN
++ KEY_MENU KEY_SEARCH KEY_HOME
++ KEY_ESC KEY_ENTER>;
++ status = "okay";
++ };
++
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 1d9b314..0c57ac5 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -735,6 +735,13 @@
+ interrupts = <0 24 4>;
+ };
+
++ lradc: lradc@01c22800 {
++ compatible = "allwinner,sun4i-lradc-keys";
++ reg = <0x01c22800 0x100>;
++ interrupts = <0 31 4>;
++ status = "disabled";
++ };
++
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun7i-a20-sid";
+ reg = <0x01c23800 0x200>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/175-reset-add-of_reset_control_get.patch b/target/linux/sunxi/patches-3.14/175-reset-add-of_reset_control_get.patch
new file mode 100644
index 0000000000..7bf9511fe9
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/175-reset-add-of_reset_control_get.patch
@@ -0,0 +1,119 @@
+From bfea2b9be28b20e076d5df8863c25e966f413fa3 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Fri, 20 Dec 2013 22:41:07 +0100
+Subject: [PATCH] reset: Add of_reset_control_get
+
+In some cases, you might need to deassert from reset an hardware block that
+doesn't associated to a struct device (CPUs, timers, etc.).
+
+Add a small helper to retrieve the reset controller from the device tree
+without the need to pass a struct device.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/reset/core.c | 39 ++++++++++++++++++++++++++++++---------
+ include/linux/reset.h | 4 ++++
+ 2 files changed, 34 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/reset/core.c b/drivers/reset/core.c
+index d1b6089..4f3dda7 100644
+--- a/drivers/reset/core.c
++++ b/drivers/reset/core.c
+@@ -127,15 +127,16 @@ int reset_control_deassert(struct reset_control *rstc)
+ EXPORT_SYMBOL_GPL(reset_control_deassert);
+
+ /**
+- * reset_control_get - Lookup and obtain a reference to a reset controller.
+- * @dev: device to be reset by the controller
++ * of_reset_control_get - Lookup and obtain a reference to a reset controller.
++ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+-struct reset_control *reset_control_get(struct device *dev, const char *id)
++struct reset_control *of_reset_control_get(struct device_node *node,
++ const char *id)
+ {
+ struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+ struct reset_controller_dev *r, *rcdev;
+@@ -144,13 +145,10 @@ struct reset_control *reset_control_get(struct device *dev, const char *id)
+ int rstc_id;
+ int ret;
+
+- if (!dev)
+- return ERR_PTR(-EINVAL);
+-
+ if (id)
+- index = of_property_match_string(dev->of_node,
++ index = of_property_match_string(node,
+ "reset-names", id);
+- ret = of_parse_phandle_with_args(dev->of_node, "resets", "#reset-cells",
++ ret = of_parse_phandle_with_args(node, "resets", "#reset-cells",
+ index, &args);
+ if (ret)
+ return ERR_PTR(ret);
+@@ -185,12 +183,35 @@ struct reset_control *reset_control_get(struct device *dev, const char *id)
+ return ERR_PTR(-ENOMEM);
+ }
+
+- rstc->dev = dev;
+ rstc->rcdev = rcdev;
+ rstc->id = rstc_id;
+
+ return rstc;
+ }
++EXPORT_SYMBOL_GPL(of_reset_control_get);
++
++/**
++ * reset_control_get - Lookup and obtain a reference to a reset controller.
++ * @dev: device to be reset by the controller
++ * @id: reset line name
++ *
++ * Returns a struct reset_control or IS_ERR() condition containing errno.
++ *
++ * Use of id names is optional.
++ */
++struct reset_control *reset_control_get(struct device *dev, const char *id)
++{
++ struct reset_control *rstc;
++
++ if (!dev)
++ return ERR_PTR(-EINVAL);
++
++ rstc = of_reset_control_get(dev->of_node, id);
++ if (!IS_ERR(rstc))
++ rstc->dev = dev;
++
++ return rstc;
++}
+ EXPORT_SYMBOL_GPL(reset_control_get);
+
+ /**
+diff --git a/include/linux/reset.h b/include/linux/reset.h
+index 6082247..a398025 100644
+--- a/include/linux/reset.h
++++ b/include/linux/reset.h
+@@ -1,6 +1,8 @@
+ #ifndef _LINUX_RESET_H_
+ #define _LINUX_RESET_H_
+
++#include <linux/of.h>
++
+ struct device;
+ struct reset_control;
+
+@@ -8,6 +10,8 @@ int reset_control_reset(struct reset_control *rstc);
+ int reset_control_assert(struct reset_control *rstc);
+ int reset_control_deassert(struct reset_control *rstc);
+
++struct reset_control *of_reset_control_get(struct device_node *node,
++ const char *id);
+ struct reset_control *reset_control_get(struct device *dev, const char *id);
+ void reset_control_put(struct reset_control *rstc);
+ struct reset_control *devm_reset_control_get(struct device *dev, const char *id);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/176-clk-sun5i-add-support-for-reset-ctrler.patch b/target/linux/sunxi/patches-3.14/176-clk-sun5i-add-support-for-reset-ctrler.patch
new file mode 100644
index 0000000000..6d322c7bc6
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/176-clk-sun5i-add-support-for-reset-ctrler.patch
@@ -0,0 +1,69 @@
+From 3ec31fa2ce161d35f787354037f94d9d22d825d1 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Fri, 20 Dec 2013 22:41:08 +0100
+Subject: [PATCH] clocksource: sun5i: Add support for reset controller
+
+The Allwinner A31 that uses this timer has the timer IP asserted in reset.
+Add an optional reset property to the DT, and deassert the timer from reset if
+it's there.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ .../devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt | 4 ++++
+ drivers/clocksource/timer-sun5i.c | 6 ++++++
+ 2 files changed, 10 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
+index 7c26154..27cfc7d 100644
+--- a/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
++++ b/Documentation/devicetree/bindings/timer/allwinner,sun5i-a13-hstimer.txt
+@@ -9,6 +9,9 @@ Required properties:
+ one)
+ - clocks: phandle to the source clock (usually the AHB clock)
+
++Optionnal properties:
++- resets: phandle to a reset controller asserting the timer
++
+ Example:
+
+ timer@01c60000 {
+@@ -19,4 +22,5 @@ timer@01c60000 {
+ <0 53 1>,
+ <0 54 1>;
+ clocks = <&ahb1_gates 19>;
++ resets = <&ahb1rst 19>;
+ };
+diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
+index deebcd6..0226844 100644
+--- a/drivers/clocksource/timer-sun5i.c
++++ b/drivers/clocksource/timer-sun5i.c
+@@ -16,6 +16,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/irqreturn.h>
++#include <linux/reset.h>
+ #include <linux/sched_clock.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
+@@ -143,6 +144,7 @@ static u64 sun5i_timer_sched_read(void)
+
+ static void __init sun5i_timer_init(struct device_node *node)
+ {
++ struct reset_control *rstc;
+ unsigned long rate;
+ struct clk *clk;
+ int ret, irq;
+@@ -162,6 +164,10 @@ static void __init sun5i_timer_init(struct device_node *node)
+ clk_prepare_enable(clk);
+ rate = clk_get_rate(clk);
+
++ rstc = of_reset_control_get(node, NULL);
++ if (!IS_ERR(rstc))
++ reset_control_deassert(rstc);
++
+ writel(~0, timer_base + TIMER_INTVAL_LO_REG(1));
+ writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
+ timer_base + TIMER_CTL_REG(1));
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/180-clk-sunxi-add-clock-output-names-dt-prop-support.patch b/target/linux/sunxi/patches-3.14/180-clk-sunxi-add-clock-output-names-dt-prop-support.patch
new file mode 100644
index 0000000000..4f7d275522
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/180-clk-sunxi-add-clock-output-names-dt-prop-support.patch
@@ -0,0 +1,55 @@
+From 0bf618fda3ad24649add0bf943d16a9b4f5c3463 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:37 +0800
+Subject: [PATCH] clk: sunxi: add clock-output-names dt property support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+sunxi clock drivers use dt node name as clock name, but clock
+nodes should be named clk@X, so the names would be the same.
+Let the drivers read clock names from dt clock-output-names
+property.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Acked-by: Mike Turquette <mturquette@linaro.org>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index abb6c5a..0ed9794 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -51,6 +51,8 @@ static void __init sun4i_osc_clk_setup(struct device_node *node)
+ if (!gate)
+ goto err_free_fixed;
+
++ of_property_read_string(node, "clock-output-names", &clk_name);
++
+ /* set up gate and fixed rate properties */
+ gate->reg = of_iomap(node, 0);
+ gate->bit_idx = SUNXI_OSC24M_GATE;
+@@ -601,6 +603,8 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
++ of_property_read_string(node, "clock-output-names", &clk_name);
++
+ clk = clk_register_mux(NULL, clk_name, parents, i,
+ CLK_SET_RATE_NO_REPARENT, reg,
+ data->shift, SUNXI_MUX_GATE_WIDTH,
+@@ -660,6 +664,8 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
+
+ clk_parent = of_clk_get_parent_name(node, 0);
+
++ of_property_read_string(node, "clock-output-names", &clk_name);
++
+ clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
+ reg, data->shift, data->width,
+ data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/181-clk-sunxi-add-names-for-pll56.patch b/target/linux/sunxi/patches-3.14/181-clk-sunxi-add-names-for-pll56.patch
new file mode 100644
index 0000000000..879462b766
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/181-clk-sunxi-add-names-for-pll56.patch
@@ -0,0 +1,83 @@
+From 8f3156f3f2b70128b2761526c208c8e3bfda694e Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:39 +0800
+Subject: [PATCH] clk: sunxi: add names for pll5, pll6 parent clocks to
+ factors_data
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Some factor clocks, such as the parent clock of pll5 and pll6, have
+multiple output names. Add the corresponding names to factors_data
+tied to compatible string.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Acked-by: Mike Turquette <mturquette@linaro.org>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 27 ++++++++++++++++++---------
+ 1 file changed, 18 insertions(+), 9 deletions(-)
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 0ed9794..7a2ed98 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -389,6 +389,7 @@ struct factors_data {
+ int mux;
+ struct clk_factors_config *table;
+ void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
++ const char *name;
+ };
+
+ static struct clk_factors_config sun4i_pll1_config = {
+@@ -457,6 +458,14 @@ static const struct factors_data sun4i_pll5_data __initconst = {
+ .enable = 31,
+ .table = &sun4i_pll5_config,
+ .getter = sun4i_get_pll5_factors,
++ .name = "pll5",
++};
++
++static const struct factors_data sun4i_pll6_data __initconst = {
++ .enable = 31,
++ .table = &sun4i_pll5_config,
++ .getter = sun4i_get_pll5_factors,
++ .name = "pll6",
+ };
+
+ static const struct factors_data sun4i_apb1_data __initconst = {
+@@ -499,14 +508,14 @@ static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+- /* Nodes should be providing the name via clock-output-names
+- * but originally our dts didn't, and so we used node->name.
+- * The new, better nodes look like clk@deadbeef, so we pull the
+- * name just in this case */
+- if (!strcmp("clk", clk_name)) {
+- of_property_read_string_index(node, "clock-output-names",
+- 0, &clk_name);
+- }
++ /*
++ * some factor clocks, such as pll5 and pll6, may have multiple
++ * outputs, and have their name designated in factors_data
++ */
++ if (data->name)
++ clk_name = data->name;
++ else
++ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ factors = kzalloc(sizeof(struct clk_factors), GFP_KERNEL);
+ if (!factors)
+@@ -838,7 +847,7 @@ static const struct divs_data pll5_divs_data __initconst = {
+ };
+
+ static const struct divs_data pll6_divs_data __initconst = {
+- .factors = &sun4i_pll5_data,
++ .factors = &sun4i_pll6_data,
+ .div = {
+ { .shift = 0, .table = pll6_sata_tbl, .gate = 14 }, /* M, SATA */
+ { .fixed = 2 }, /* P, other */
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/182-clk-sunxi-add-support-for-usb-clockreg-reset.patch b/target/linux/sunxi/patches-3.14/182-clk-sunxi-add-support-for-usb-clockreg-reset.patch
new file mode 100644
index 0000000000..533b6013f1
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/182-clk-sunxi-add-support-for-usb-clockreg-reset.patch
@@ -0,0 +1,133 @@
+From 0643a93746775da2189ab0afd8f748afcaa791c5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 7 Feb 2014 16:21:49 +0100
+Subject: [PATCH] clk: sunxi: Add support for USB clock-register reset bits
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The usb-clk register is special in that it not only contains clk gate bits,
+but also has a few reset bits. This commit adds support for this by allowing
+gates type sunxi clks to also register a reset controller.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 71 +++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 71 insertions(+)
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 736fb60..23beb6e 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -18,6 +18,7 @@
+ #include <linux/clkdev.h>
+ #include <linux/of.h>
+ #include <linux/of_address.h>
++#include <linux/reset-controller.h>
+
+ #include "clk-factors.h"
+
+@@ -688,6 +689,59 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
+
+
+ /**
++ * sunxi_gates_reset... - reset bits in leaf gate clk registers handling
++ */
++
++struct gates_reset_data {
++ void __iomem *reg;
++ spinlock_t *lock;
++ struct reset_controller_dev rcdev;
++};
++
++static int sunxi_gates_reset_assert(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct gates_reset_data *data = container_of(rcdev,
++ struct gates_reset_data,
++ rcdev);
++ unsigned long flags;
++ u32 reg;
++
++ spin_lock_irqsave(data->lock, flags);
++
++ reg = readl(data->reg);
++ writel(reg & ~BIT(id), data->reg);
++
++ spin_unlock_irqrestore(data->lock, flags);
++
++ return 0;
++}
++
++static int sunxi_gates_reset_deassert(struct reset_controller_dev *rcdev,
++ unsigned long id)
++{
++ struct gates_reset_data *data = container_of(rcdev,
++ struct gates_reset_data,
++ rcdev);
++ unsigned long flags;
++ u32 reg;
++
++ spin_lock_irqsave(data->lock, flags);
++
++ reg = readl(data->reg);
++ writel(reg | BIT(id), data->reg);
++
++ spin_unlock_irqrestore(data->lock, flags);
++
++ return 0;
++}
++
++static struct reset_control_ops sunxi_gates_reset_ops = {
++ .assert = sunxi_gates_reset_assert,
++ .deassert = sunxi_gates_reset_deassert,
++};
++
++/**
+ * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks
+ */
+
+@@ -695,6 +749,7 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
+
+ struct gates_data {
+ DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
++ u32 reset_mask;
+ };
+
+ static const struct gates_data sun4i_axi_gates_data __initconst = {
+@@ -765,6 +820,7 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
+ struct gates_data *data)
+ {
+ struct clk_onecell_data *clk_data;
++ struct gates_reset_data *reset_data;
+ const char *clk_parent;
+ const char *clk_name;
+ void *reg;
+@@ -808,6 +864,21 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
+ clk_data->clk_num = i;
+
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
++
++ /* Register a reset controler for gates with reset bits */
++ if (data->reset_mask == 0)
++ return;
++
++ reset_data = kzalloc(sizeof(*reset_data), GFP_KERNEL);
++ if (!reset_data)
++ return;
++
++ reset_data->reg = reg;
++ reset_data->lock = &clk_lock;
++ reset_data->rcdev.nr_resets = __fls(data->reset_mask) + 1;
++ reset_data->rcdev.ops = &sunxi_gates_reset_ops;
++ reset_data->rcdev.of_node = node;
++ reset_controller_register(&reset_data->rcdev);
+ }
+
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/182-clk-sunxi-get-divs-parent-clockname.patch b/target/linux/sunxi/patches-3.14/182-clk-sunxi-get-divs-parent-clockname.patch
new file mode 100644
index 0000000000..53f2217247
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/182-clk-sunxi-get-divs-parent-clockname.patch
@@ -0,0 +1,45 @@
+From 0566b74f93eaf6b2281d2605a63e06e6ba809334 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 3 Feb 2014 09:51:40 +0800
+Subject: [PATCH] clk: sunxi: get divs parent clock name from parent factor
+ clock
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Divs clocks consist of a parent factor clock with multiple outputs,
+and seperate clocks for each output. Get the name of the parent
+clock from the parent factor clock, instead of the DT node name.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Acked-by: Mike Turquette <mturquette@linaro.org>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 7a2ed98..736fb60 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -869,7 +869,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
+ struct divs_data *data)
+ {
+ struct clk_onecell_data *clk_data;
+- const char *parent = node->name;
++ const char *parent;
+ const char *clk_name;
+ struct clk **clks, *pclk;
+ struct clk_hw *gate_hw, *rate_hw;
+@@ -883,6 +883,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
+
+ /* Set up factor clock that we will be dividing */
+ pclk = sunxi_factors_clk_setup(node, data->factors);
++ parent = __clk_get_name(pclk);
+
+ reg = of_iomap(node, 0);
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/183-clk-sunxi-add-usb-clockreg-defs.patch b/target/linux/sunxi/patches-3.14/183-clk-sunxi-add-usb-clockreg-defs.patch
new file mode 100644
index 0000000000..07e8879896
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/183-clk-sunxi-add-usb-clockreg-defs.patch
@@ -0,0 +1,76 @@
+From c61dfeb17581d32360a817ba40636aaed85caade Mon Sep 17 00:00:00 2001
+From: Roman Byshko <rbyshko@gmail.com>
+Date: Fri, 7 Feb 2014 16:21:50 +0100
+Subject: [PATCH] clk: sunxi: Add USB clock register defintions
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Add register definitions for the usb-clk register found on sun4i, sun5i and
+sun7i SoCs.
+
+Signed-off-by: Roman Byshko <rbyshko@gmail.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt | 5 +++++
+ drivers/clk/sunxi/clk-sunxi.c | 12 ++++++++++++
+ 2 files changed, 17 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
+index 0cf679b..ca2b692 100644
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -37,6 +37,8 @@ Required properties:
+ "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
+ "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
+ "allwinner,sun7i-a20-out-clk" - for the external output clocks
++ "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
++ "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
+
+ Required properties for all clocks:
+ - reg : shall be the control register address for the clock.
+@@ -50,6 +52,9 @@ Required properties for all clocks:
+ If the clock module only has one output, the name shall be the
+ module name.
+
++And "allwinner,*-usb-clk" clocks also require:
++- reset-cells : shall be set to 1
++
+ Clock consumers should specify the desired clocks they use with a
+ "clocks" phandle cell. Consumers that are using a gated clock should
+ provide an additional ID in their clock property. This ID is the
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 23beb6e..a779c31 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -816,6 +816,16 @@ static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
+ .mask = { 0xff80ff },
+ };
+
++static const struct gates_data sun4i_a10_usb_gates_data __initconst = {
++ .mask = {0x1C0},
++ .reset_mask = 0x07,
++};
++
++static const struct gates_data sun5i_a13_usb_gates_data __initconst = {
++ .mask = {0x140},
++ .reset_mask = 0x03,
++};
++
+ static void __init sunxi_gates_clk_setup(struct device_node *node,
+ struct gates_data *data)
+ {
+@@ -1107,6 +1117,8 @@ static const struct of_device_id clk_gates_match[] __initconst = {
+ {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
+ {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
+ {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
++ {.compatible = "allwinner,sun4i-a10-usb-clk", .data = &sun4i_a10_usb_gates_data,},
++ {.compatible = "allwinner,sun5i-a13-usb-clk", .data = &sun5i_a13_usb_gates_data,},
+ {}
+ };
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/184-clk-sunxi-add-pll6-on-a31.patch b/target/linux/sunxi/patches-3.14/184-clk-sunxi-add-pll6-on-a31.patch
new file mode 100644
index 0000000000..4d71742803
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/184-clk-sunxi-add-pll6-on-a31.patch
@@ -0,0 +1,111 @@
+From c225f78660cd61914f25dd00499c7ae71d1d6919 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Wed, 5 Feb 2014 14:05:03 +0100
+Subject: [PATCH] clk: sunxi: Add support for PLL6 on the A31
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The A31 has a slightly different PLL6 clock. Add support for this new clock in
+our driver.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt | 1 +
+ drivers/clk/sunxi/clk-sunxi.c | 45 +++++++++++++++++++++++
+ 2 files changed, 46 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
+index ca2b692..c37c764 100644
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -11,6 +11,7 @@ Required properties:
+ "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
+ "allwinner,sun4i-pll5-clk" - for the PLL5 clock
+ "allwinner,sun4i-pll6-clk" - for the PLL6 clock
++ "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
+ "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
+ "allwinner,sun4i-axi-clk" - for the AXI clock
+ "allwinner,sun4i-axi-gates-clk" - for the AXI gates
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index a779c31..d4cf297 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -252,7 +252,38 @@ static void sun4i_get_pll5_factors(u32 *freq, u32 parent_rate,
+ *n = DIV_ROUND_UP(div, (*k+1));
+ }
+
++/**
++ * sun6i_a31_get_pll6_factors() - calculates n, k factors for A31 PLL6
++ * PLL6 rate is calculated as follows
++ * rate = parent_rate * n * (k + 1) / 2
++ * parent_rate is always 24Mhz
++ */
++
++static void sun6i_a31_get_pll6_factors(u32 *freq, u32 parent_rate,
++ u8 *n, u8 *k, u8 *m, u8 *p)
++{
++ u8 div;
++
++ /*
++ * We always have 24MHz / 2, so we can just say that our
++ * parent clock is 12MHz.
++ */
++ parent_rate = parent_rate / 2;
++
++ /* Normalize value to a parent_rate multiple (24M / 2) */
++ div = *freq / parent_rate;
++ *freq = parent_rate * div;
++
++ /* we were called to round the frequency, we can now return */
++ if (n == NULL)
++ return;
++
++ *k = div / 32;
++ if (*k > 3)
++ *k = 3;
+
++ *n = DIV_ROUND_UP(div, (*k+1));
++}
+
+ /**
+ * sun4i_get_apb1_factors() - calculates m, p factors for APB1
+@@ -420,6 +451,13 @@ static struct clk_factors_config sun4i_pll5_config = {
+ .kwidth = 2,
+ };
+
++static struct clk_factors_config sun6i_a31_pll6_config = {
++ .nshift = 8,
++ .nwidth = 5,
++ .kshift = 4,
++ .kwidth = 2,
++};
++
+ static struct clk_factors_config sun4i_apb1_config = {
+ .mshift = 0,
+ .mwidth = 5,
+@@ -469,6 +507,12 @@ static const struct factors_data sun4i_pll6_data __initconst = {
+ .name = "pll6",
+ };
+
++static const struct factors_data sun6i_a31_pll6_data __initconst = {
++ .enable = 31,
++ .table = &sun6i_a31_pll6_config,
++ .getter = sun6i_a31_get_pll6_factors,
++};
++
+ static const struct factors_data sun4i_apb1_data __initconst = {
+ .table = &sun4i_apb1_config,
+ .getter = sun4i_get_apb1_factors,
+@@ -1069,6 +1113,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
+ static const struct of_device_id clk_factors_match[] __initconst = {
+ {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
+ {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
++ {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
+ {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
+ {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
+ {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/185-clk-sunxi-add-a20-a31-gmac-clock.patch b/target/linux/sunxi/patches-3.14/185-clk-sunxi-add-a20-a31-gmac-clock.patch
new file mode 100644
index 0000000000..e105c25702
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/185-clk-sunxi-add-a20-a31-gmac-clock.patch
@@ -0,0 +1,182 @@
+From dd91dc4b9c55c8fa24738249214274442e2fcbd3 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 10 Feb 2014 18:35:47 +0800
+Subject: [PATCH] clk: sunxi: Add Allwinner A20/A31 GMAC clock unit
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The Allwinner A20/A31 clock module controls the transmit clock source
+and interface type of the GMAC ethernet controller. Model this as
+a single clock for GMAC drivers to use.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt | 30 +++++++
+ drivers/clk/sunxi/clk-sunxi.c | 96 +++++++++++++++++++++++
+ 2 files changed, 126 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
+index c37c764..256a908 100644
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -38,6 +38,7 @@ Required properties:
+ "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
+ "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
+ "allwinner,sun7i-a20-out-clk" - for the external output clocks
++ "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
+ "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
+ "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
+
+@@ -56,6 +57,9 @@ Required properties for all clocks:
+ And "allwinner,*-usb-clk" clocks also require:
+ - reset-cells : shall be set to 1
+
++For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
++dummy clocks at 25 MHz and 125 MHz, respectively. See example.
++
+ Clock consumers should specify the desired clocks they use with a
+ "clocks" phandle cell. Consumers that are using a gated clock should
+ provide an additional ID in their clock property. This ID is the
+@@ -102,3 +106,29 @@ mmc0_clk: clk@01c20088 {
+ clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
+ clock-output-names = "mmc0";
+ };
++
++mii_phy_tx_clk: clk@2 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <25000000>;
++ clock-output-names = "mii_phy_tx";
++};
++
++gmac_int_tx_clk: clk@3 {
++ #clock-cells = <0>;
++ compatible = "fixed-clock";
++ clock-frequency = <125000000>;
++ clock-output-names = "gmac_int_tx";
++};
++
++gmac_clk: clk@01c20164 {
++ #clock-cells = <0>;
++ compatible = "allwinner,sun7i-a20-gmac-clk";
++ reg = <0x01c20164 0x4>;
++ /*
++ * The first clock must be fixed at 25MHz;
++ * the second clock must be fixed at 125MHz
++ */
++ clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
++ clock-output-names = "gmac";
++};
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index d4cf297..335c987 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -411,6 +411,102 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
+
+
+ /**
++ * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
++ *
++ * This clock looks something like this
++ * ________________________
++ * MII TX clock from PHY >-----|___________ _________|----> to GMAC core
++ * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
++ * Ext. 125MHz RGMII TX clk >--|__divider__/ |
++ * |________________________|
++ *
++ * The external 125 MHz reference is optional, i.e. GMAC can use its
++ * internal TX clock just fine. The A31 GMAC clock module does not have
++ * the divider controls for the external reference.
++ *
++ * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
++ * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
++ * select the appropriate source and gate/ungate the output to the PHY.
++ *
++ * Only the GMAC should use this clock. Altering the clock so that it doesn't
++ * match the GMAC's operation parameters will result in the GMAC not being
++ * able to send traffic out. The GMAC driver should set the clock rate and
++ * enable/disable this clock to configure the required state. The clock
++ * driver then responds by auto-reparenting the clock.
++ */
++
++#define SUN7I_A20_GMAC_GPIT 2
++#define SUN7I_A20_GMAC_MASK 0x3
++#define SUN7I_A20_GMAC_PARENTS 2
++
++static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
++{
++ struct clk *clk;
++ struct clk_mux *mux;
++ struct clk_gate *gate;
++ const char *clk_name = node->name;
++ const char *parents[SUN7I_A20_GMAC_PARENTS];
++ void *reg;
++
++ if (of_property_read_string(node, "clock-output-names", &clk_name))
++ return;
++
++ /* allocate mux and gate clock structs */
++ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
++ if (!mux)
++ return;
++
++ gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
++ if (!gate)
++ goto free_mux;
++
++ /* gmac clock requires exactly 2 parents */
++ parents[0] = of_clk_get_parent_name(node, 0);
++ parents[1] = of_clk_get_parent_name(node, 1);
++ if (!parents[0] || !parents[1])
++ goto free_gate;
++
++ reg = of_iomap(node, 0);
++ if (!reg)
++ goto free_gate;
++
++ /* set up gate and fixed rate properties */
++ gate->reg = reg;
++ gate->bit_idx = SUN7I_A20_GMAC_GPIT;
++ gate->lock = &clk_lock;
++ mux->reg = reg;
++ mux->mask = SUN7I_A20_GMAC_MASK;
++ mux->flags = CLK_MUX_INDEX_BIT;
++ mux->lock = &clk_lock;
++
++ clk = clk_register_composite(NULL, clk_name,
++ parents, SUN7I_A20_GMAC_PARENTS,
++ &mux->hw, &clk_mux_ops,
++ NULL, NULL,
++ &gate->hw, &clk_gate_ops,
++ 0);
++
++ if (IS_ERR(clk))
++ goto iounmap_reg;
++
++ of_clk_add_provider(node, of_clk_src_simple_get, clk);
++ clk_register_clkdev(clk, clk_name, NULL);
++
++ return;
++
++iounmap_reg:
++ iounmap(reg);
++free_gate:
++ kfree(gate);
++free_mux:
++ kfree(mux);
++}
++CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
++ sun7i_a20_gmac_clk_setup);
++
++
++
++/**
+ * sunxi_factors_clk_setup() - Setup function for factor clocks
+ */
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/186-clk-sunxi-add-new-clock-compats.patch b/target/linux/sunxi/patches-3.14/186-clk-sunxi-add-new-clock-compats.patch
new file mode 100644
index 0000000000..728fca8454
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/186-clk-sunxi-add-new-clock-compats.patch
@@ -0,0 +1,187 @@
+From 45ff9697ed1668e82ca3902b32309e157464e745 Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 6 Feb 2014 09:55:57 +0100
+Subject: [PATCH] clk: sunxi: Add new clock compatibles
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The Allwinner A10 compatibles were following a slightly different compatible
+patterns than the rest of the SoCs for historical reasons. Add compatibles
+matching the other pattern to the clock driver for consistency, and keep the
+older one for backward compatibility.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ Documentation/devicetree/bindings/clock/sunxi.txt | 36 +++++++++++------------
+ drivers/clk/sunxi/clk-sunxi.c | 30 +++++++++----------
+ 2 files changed, 33 insertions(+), 33 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
+index 256a908..a5160d8 100644
+--- a/Documentation/devicetree/bindings/clock/sunxi.txt
++++ b/Documentation/devicetree/bindings/clock/sunxi.txt
+@@ -6,37 +6,37 @@ This binding uses the common clock binding[1].
+
+ Required properties:
+ - compatible : shall be one of the following:
+- "allwinner,sun4i-osc-clk" - for a gatable oscillator
+- "allwinner,sun4i-pll1-clk" - for the main PLL clock and PLL4
++ "allwinner,sun4i-a10-osc-clk" - for a gatable oscillator
++ "allwinner,sun4i-a10-pll1-clk" - for the main PLL clock and PLL4
+ "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
+- "allwinner,sun4i-pll5-clk" - for the PLL5 clock
+- "allwinner,sun4i-pll6-clk" - for the PLL6 clock
++ "allwinner,sun4i-a10-pll5-clk" - for the PLL5 clock
++ "allwinner,sun4i-a10-pll6-clk" - for the PLL6 clock
+ "allwinner,sun6i-a31-pll6-clk" - for the PLL6 clock on A31
+- "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
+- "allwinner,sun4i-axi-clk" - for the AXI clock
+- "allwinner,sun4i-axi-gates-clk" - for the AXI gates
+- "allwinner,sun4i-ahb-clk" - for the AHB clock
+- "allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
++ "allwinner,sun4i-a10-cpu-clk" - for the CPU multiplexer clock
++ "allwinner,sun4i-a10-axi-clk" - for the AXI clock
++ "allwinner,sun4i-a10-axi-gates-clk" - for the AXI gates
++ "allwinner,sun4i-a10-ahb-clk" - for the AHB clock
++ "allwinner,sun4i-a10-ahb-gates-clk" - for the AHB gates on A10
+ "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
+ "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
+ "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
+ "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
+ "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
+- "allwinner,sun4i-apb0-clk" - for the APB0 clock
+- "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
++ "allwinner,sun4i-a10-apb0-clk" - for the APB0 clock
++ "allwinner,sun4i-a10-apb0-gates-clk" - for the APB0 gates on A10
+ "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
+ "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
+ "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
+- "allwinner,sun4i-apb1-clk" - for the APB1 clock
+- "allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
+- "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
++ "allwinner,sun4i-a10-apb1-clk" - for the APB1 clock
++ "allwinner,sun4i-a10-apb1-mux-clk" - for the APB1 clock muxing
++ "allwinner,sun4i-a10-apb1-gates-clk" - for the APB1 gates on A10
+ "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
+ "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
+ "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
+ "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
+ "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
+ "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
+- "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
++ "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
+ "allwinner,sun7i-a20-out-clk" - for the external output clocks
+ "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
+ "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
+@@ -69,7 +69,7 @@ For example:
+
+ osc24M: clk@01c20050 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-osc-clk";
++ compatible = "allwinner,sun4i-a10-osc-clk";
+ reg = <0x01c20050 0x4>;
+ clocks = <&osc24M_fixed>;
+ clock-output-names = "osc24M";
+@@ -77,7 +77,7 @@ osc24M: clk@01c20050 {
+
+ pll1: clk@01c20000 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-pll1-clk";
++ compatible = "allwinner,sun4i-a10-pll1-clk";
+ reg = <0x01c20000 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll1";
+@@ -93,7 +93,7 @@ pll5: clk@01c20020 {
+
+ cpu: cpu@01c20054 {
+ #clock-cells = <0>;
+- compatible = "allwinner,sun4i-cpu-clk";
++ compatible = "allwinner,sun4i-a10-cpu-clk";
+ reg = <0x01c20054 0x4>;
+ clocks = <&osc32k>, <&osc24M>, <&pll1>;
+ clock-output-names = "cpu";
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 335c987..23baad9 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -80,7 +80,7 @@ static void __init sun4i_osc_clk_setup(struct device_node *node)
+ err_free_fixed:
+ kfree(fixed);
+ }
+-CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup);
++CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup);
+
+
+
+@@ -1207,52 +1207,52 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
+
+ /* Matches for factors clocks */
+ static const struct of_device_id clk_factors_match[] __initconst = {
+- {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
++ {.compatible = "allwinner,sun4i-a10-pll1-clk", .data = &sun4i_pll1_data,},
+ {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
+ {.compatible = "allwinner,sun6i-a31-pll6-clk", .data = &sun6i_a31_pll6_data,},
+- {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
+- {.compatible = "allwinner,sun4i-mod0-clk", .data = &sun4i_mod0_data,},
++ {.compatible = "allwinner,sun4i-a10-apb1-clk", .data = &sun4i_apb1_data,},
++ {.compatible = "allwinner,sun4i-a10-mod0-clk", .data = &sun4i_mod0_data,},
+ {.compatible = "allwinner,sun7i-a20-out-clk", .data = &sun7i_a20_out_data,},
+ {}
+ };
+
+ /* Matches for divider clocks */
+ static const struct of_device_id clk_div_match[] __initconst = {
+- {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,},
+- {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,},
+- {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,},
++ {.compatible = "allwinner,sun4i-a10-axi-clk", .data = &sun4i_axi_data,},
++ {.compatible = "allwinner,sun4i-a10-ahb-clk", .data = &sun4i_ahb_data,},
++ {.compatible = "allwinner,sun4i-a10-apb0-clk", .data = &sun4i_apb0_data,},
+ {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
+ {}
+ };
+
+ /* Matches for divided outputs */
+ static const struct of_device_id clk_divs_match[] __initconst = {
+- {.compatible = "allwinner,sun4i-pll5-clk", .data = &pll5_divs_data,},
+- {.compatible = "allwinner,sun4i-pll6-clk", .data = &pll6_divs_data,},
++ {.compatible = "allwinner,sun4i-a10-pll5-clk", .data = &pll5_divs_data,},
++ {.compatible = "allwinner,sun4i-a10-pll6-clk", .data = &pll6_divs_data,},
+ {}
+ };
+
+ /* Matches for mux clocks */
+ static const struct of_device_id clk_mux_match[] __initconst = {
+- {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
+- {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
++ {.compatible = "allwinner,sun4i-a10-cpu-clk", .data = &sun4i_cpu_mux_data,},
++ {.compatible = "allwinner,sun4i-a10-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
+ {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
+ {}
+ };
+
+ /* Matches for gate clocks */
+ static const struct of_device_id clk_gates_match[] __initconst = {
+- {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
+- {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
++ {.compatible = "allwinner,sun4i-a10-axi-gates-clk", .data = &sun4i_axi_gates_data,},
++ {.compatible = "allwinner,sun4i-a10-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
+ {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
+ {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
+ {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
+- {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
++ {.compatible = "allwinner,sun4i-a10-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
+ {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
+ {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
+- {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
++ {.compatible = "allwinner,sun4i-a10-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
+ {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
+ {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
+ {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/187-clk-sunxi-automatic-reparenting.patch b/target/linux/sunxi/patches-3.14/187-clk-sunxi-automatic-reparenting.patch
new file mode 100644
index 0000000000..b78b661ed8
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/187-clk-sunxi-automatic-reparenting.patch
@@ -0,0 +1,73 @@
+From b416520f239aeaa4207ebe84c22247cff2da444f Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
+Date: Thu, 5 Sep 2013 19:52:41 -0300
+Subject: [PATCH] clk: sunxi: factors: automatic reparenting support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This commit implements .determine_rate, so that our factor clocks can be
+reparented when needed.
+
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+---
+ drivers/clk/sunxi/clk-factors.c | 36 ++++++++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
+index 9e23264..3806d97 100644
+--- a/drivers/clk/sunxi/clk-factors.c
++++ b/drivers/clk/sunxi/clk-factors.c
+@@ -77,6 +77,41 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
+ return rate;
+ }
+
++static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
++ unsigned long *best_parent_rate,
++ struct clk **best_parent_p)
++{
++ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
++ int i, num_parents;
++ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
++
++ /* find the parent that can help provide the fastest rate <= rate */
++ num_parents = __clk_get_num_parents(clk);
++ for (i = 0; i < num_parents; i++) {
++ parent = clk_get_parent_by_index(clk, i);
++ if (!parent)
++ continue;
++ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
++ parent_rate = __clk_round_rate(parent, rate);
++ else
++ parent_rate = __clk_get_rate(parent);
++
++ child_rate = clk_factors_round_rate(hw, rate, &parent_rate);
++
++ if (child_rate <= rate && child_rate > best_child_rate) {
++ best_parent = parent;
++ best = parent_rate;
++ best_child_rate = child_rate;
++ }
++ }
++
++ if (best_parent)
++ *best_parent_p = best_parent;
++ *best_parent_rate = best;
++
++ return best_child_rate;
++}
++
+ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+ {
+@@ -113,6 +148,7 @@ static int clk_factors_set_rate(struct clk_hw *hw, unsigned long rate,
+ }
+
+ const struct clk_ops clk_factors_ops = {
++ .determine_rate = clk_factors_determine_rate,
+ .recalc_rate = clk_factors_recalc_rate,
+ .round_rate = clk_factors_round_rate,
+ .set_rate = clk_factors_set_rate,
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/188-clk-sunxi-implement-mmc-phasectrl.patch b/target/linux/sunxi/patches-3.14/188-clk-sunxi-implement-mmc-phasectrl.patch
new file mode 100644
index 0000000000..1288f8fed9
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/188-clk-sunxi-implement-mmc-phasectrl.patch
@@ -0,0 +1,95 @@
+From 36268d704307282109ec246f65cac2a42c825629 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
+Date: Fri, 20 Sep 2013 20:29:17 -0300
+Subject: [PATCH] clk: sunxi: Implement MMC phase control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+HdG: add header exporting clk_sunxi_mmc_phase_control
+
+Signed-off-by: Emilio López <emilio@elopez.com.ar>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 35 +++++++++++++++++++++++++++++++++++
+ include/linux/clk/sunxi.h | 22 ++++++++++++++++++++++
+ 2 files changed, 57 insertions(+)
+ create mode 100644 include/linux/clk/sunxi.h
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 23baad9..9afd8dd 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -507,6 +507,41 @@ CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
+
+
+ /**
++ * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
++ */
++
++void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output)
++{
++ #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
++ #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
++
++ struct clk_composite *composite = to_clk_composite(hw);
++ struct clk_hw *rate_hw = composite->rate_hw;
++ struct clk_factors *factors = to_clk_factors(rate_hw);
++ unsigned long flags = 0;
++ u32 reg;
++
++ if (factors->lock)
++ spin_lock_irqsave(factors->lock, flags);
++
++ reg = readl(factors->reg);
++
++ /* set sample clock phase control */
++ reg &= ~(0x7 << 20);
++ reg |= ((sample & 0x7) << 20);
++
++ /* set output clock phase control */
++ reg &= ~(0x7 << 8);
++ reg |= ((output & 0x7) << 8);
++
++ writel(reg, factors->reg);
++
++ if (factors->lock)
++ spin_unlock_irqrestore(factors->lock, flags);
++}
++
++
++/**
+ * sunxi_factors_clk_setup() - Setup function for factor clocks
+ */
+
+diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
+new file mode 100644
+index 0000000..1ef5c89
+--- /dev/null
++++ b/include/linux/clk/sunxi.h
+@@ -0,0 +1,22 @@
++/*
++ * Copyright 2013 - Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __LINUX_CLK_SUNXI_H_
++#define __LINUX_CLK_SUNXI_H_
++
++#include <linux/clk.h>
++
++void clk_sunxi_mmc_phase_control(struct clk_hw *hw, u8 sample, u8 output);
++
++#endif
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/190-ahci-libahci-changes.patch b/target/linux/sunxi/patches-3.14/190-ahci-libahci-changes.patch
new file mode 100644
index 0000000000..21a119f96b
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/190-ahci-libahci-changes.patch
@@ -0,0 +1,1361 @@
+From 3b5db9d024f173c30ef4060c31bb8e9fbd194cc1 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 2 Dec 2013 16:13:32 +0100
+Subject: [PATCH] libahci: Allow drivers to override start_engine
+
+Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
+special register to be poked before starting the DMA engine.
+
+This register gets reset on an ahci_stop_engine call, so there is no other
+place then ahci_start_engine where this poking can be done.
+
+This commit allows drivers to override ahci_start_engine behavior for use by
+the Allwinner AHCI driver (and potentially other drivers in the future).
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci.c | 6 ++++--
+ drivers/ata/ahci.h | 6 ++++++
+ drivers/ata/libahci.c | 26 +++++++++++++++++++-------
+ drivers/ata/sata_highbank.c | 3 ++-
+ 4 files changed, 31 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
+index c81d809..8bfc477 100644
+--- a/drivers/ata/ahci.c
++++ b/drivers/ata/ahci.c
+@@ -578,6 +578,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+ {
+ struct ata_port *ap = link->ap;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ bool online;
+ int rc;
+
+@@ -588,7 +589,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
+ deadline, &online, NULL);
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
+
+@@ -603,6 +604,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
+ {
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ bool online;
+@@ -618,7 +620,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
+ rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
+ deadline, &online, NULL);
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ /* The pseudo configuration device on SIMG4726 attached to
+ * ASUS P5W-DH Deluxe doesn't send signature FIS after
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index 2289efd..64d1a99d 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -323,6 +323,12 @@ struct ahci_host_priv {
+ u32 em_msg_type; /* EM message type */
+ struct clk *clk; /* Only for platforms supporting clk */
+ void *plat_data; /* Other platform data */
++ /*
++ * Optional ahci_start_engine override, if not set this gets set to the
++ * default ahci_start_engine during ahci_save_initial_config, this can
++ * be overridden anytime before the host is activated.
++ */
++ void (*start_engine)(struct ata_port *ap);
+ };
+
+ extern int ahci_ignore_sss;
+diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
+index 36605ab..f839bb3 100644
+--- a/drivers/ata/libahci.c
++++ b/drivers/ata/libahci.c
+@@ -394,6 +394,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
+ *
+ * If inconsistent, config values are fixed up by this function.
+ *
++ * If it is not set already this function sets hpriv->start_engine to
++ * ahci_start_engine.
++ *
+ * LOCKING:
+ * None.
+ */
+@@ -500,6 +503,9 @@ void ahci_save_initial_config(struct device *dev,
+ hpriv->cap = cap;
+ hpriv->cap2 = cap2;
+ hpriv->port_map = port_map;
++
++ if (!hpriv->start_engine)
++ hpriv->start_engine = ahci_start_engine;
+ }
+ EXPORT_SYMBOL_GPL(ahci_save_initial_config);
+
+@@ -766,7 +772,7 @@ static void ahci_start_port(struct ata_port *ap)
+
+ /* enable DMA */
+ if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ /* turn on LEDs */
+ if (ap->flags & ATA_FLAG_EM) {
+@@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
+
+ /* restart engine */
+ out_restart:
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+ return rc;
+ }
+ EXPORT_SYMBOL_GPL(ahci_kick_engine);
+@@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ bool online;
+@@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
+ rc = sata_link_hardreset(link, timing, deadline, &online,
+ ahci_check_ready);
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+@@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
+
+ void ahci_error_handler(struct ata_port *ap)
+ {
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
+ /* restart engine */
+ ahci_stop_engine(ap);
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+ }
+
+ sata_pmp_error_handler(ap);
+@@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
+
+ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
+ {
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ struct ata_device *dev = ap->link.device;
+ u32 devslp, dm, dito, mdat, deto;
+@@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
+ PORT_DEVSLP_ADSE);
+ writel(devslp, port_mmio + PORT_DEVSLP);
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ /* enable device sleep feature for the drive */
+ err_mask = ata_dev_set_feature(dev,
+@@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
+
+ static void ahci_enable_fbs(struct ata_port *ap)
+ {
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+@@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
+ } else
+ dev_err(ap->host->dev, "Failed to enable FBS\n");
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+ }
+
+ static void ahci_disable_fbs(struct ata_port *ap)
+ {
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+@@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
+ pp->fbs_enabled = false;
+ }
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+ }
+
+ static void ahci_pmp_attach(struct ata_port *ap)
+diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
+index 870b11e..b3b18d1 100644
+--- a/drivers/ata/sata_highbank.c
++++ b/drivers/ata/sata_highbank.c
+@@ -403,6 +403,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
+ static const unsigned long timing[] = { 5, 100, 500};
+ struct ata_port *ap = link->ap;
+ struct ahci_port_priv *pp = ap->private_data;
++ struct ahci_host_priv *hpriv = ap->host->private_data;
+ u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+ struct ata_taskfile tf;
+ bool online;
+@@ -431,7 +432,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
+ break;
+ } while (!online && retry--);
+
+- ahci_start_engine(ap);
++ hpriv->start_engine(ap);
+
+ if (online)
+ *class = ahci_dev_classify(ap);
+--
+2.0.3
+
+From fcc3a79f048480e6723b0cfd294f9eecbf73dfd9 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Thu, 16 Jan 2014 14:32:35 +0100
+Subject: [PATCH] ahci-platform: Add support for devices with more then 1 clock
+
+The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
+imx AHCI controller needs 3 clocks to be enabled.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../devicetree/bindings/ata/ahci-platform.txt | 1 +
+ drivers/ata/ahci.h | 3 +-
+ drivers/ata/ahci_platform.c | 119 ++++++++++++++++-----
+ include/linux/ahci_platform.h | 4 +
+ 4 files changed, 99 insertions(+), 28 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+index 89de156..3ced07d 100644
+--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
++++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+@@ -10,6 +10,7 @@ Required properties:
+
+ Optional properties:
+ - dma-coherent : Present if dma operations are coherent
++- clocks : a list of phandle + clock specifier pairs
+
+ Example:
+ sata@ffe08000 {
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index 64d1a99d..c12862b 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -51,6 +51,7 @@
+
+ enum {
+ AHCI_MAX_PORTS = 32,
++ AHCI_MAX_CLKS = 3,
+ AHCI_MAX_SG = 168, /* hardware max is 64K */
+ AHCI_DMA_BOUNDARY = 0xffffffff,
+ AHCI_MAX_CMDS = 32,
+@@ -321,7 +322,7 @@ struct ahci_host_priv {
+ u32 em_loc; /* enclosure management location */
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
+- struct clk *clk; /* Only for platforms supporting clk */
++ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 4b231ba..609975d 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -87,6 +87,66 @@ static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT("ahci_platform"),
+ };
+
++/**
++ * ahci_platform_enable_clks - Enable platform clocks
++ * @hpriv: host private area to store config values
++ *
++ * This function enables all the clks found in hpriv->clks, starting
++ * at index 0. If any clk fails to enable it disables all the clks
++ * already enabled in reverse order, and then returns an error.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
++{
++ int c, rc;
++
++ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
++ rc = clk_prepare_enable(hpriv->clks[c]);
++ if (rc)
++ goto disable_unprepare_clk;
++ }
++ return 0;
++
++disable_unprepare_clk:
++ while (--c >= 0)
++ clk_disable_unprepare(hpriv->clks[c]);
++ return rc;
++}
++EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
++
++/**
++ * ahci_platform_disable_clks - Disable platform clocks
++ * @hpriv: host private area to store config values
++ *
++ * This function disables all the clks found in hpriv->clks, in reverse
++ * order of ahci_platform_enable_clks (starting at the end of the array).
++ *
++ * LOCKING:
++ * None.
++ */
++void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
++{
++ int c;
++
++ for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
++ if (hpriv->clks[c])
++ clk_disable_unprepare(hpriv->clks[c]);
++}
++EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
++
++static void ahci_put_clks(struct ahci_host_priv *hpriv)
++{
++ int c;
++
++ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
++ clk_put(hpriv->clks[c]);
++}
++
+ static int ahci_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -97,6 +157,7 @@ static int ahci_probe(struct platform_device *pdev)
+ struct ahci_host_priv *hpriv;
+ struct ata_host *host;
+ struct resource *mem;
++ struct clk *clk;
+ int irq;
+ int n_ports;
+ int i;
+@@ -131,17 +192,31 @@ static int ahci_probe(struct platform_device *pdev)
+ return -ENOMEM;
+ }
+
+- hpriv->clk = clk_get(dev, NULL);
+- if (IS_ERR(hpriv->clk)) {
+- dev_err(dev, "can't get clock\n");
+- } else {
+- rc = clk_prepare_enable(hpriv->clk);
+- if (rc) {
+- dev_err(dev, "clock prepare enable failed");
+- goto free_clk;
++ for (i = 0; i < AHCI_MAX_CLKS; i++) {
++ /*
++ * For now we must use clk_get(dev, NULL) for the first clock,
++ * because some platforms (da850, spear13xx) are not yet
++ * converted to use devicetree for clocks. For new platforms
++ * this is equivalent to of_clk_get(dev->of_node, 0).
++ */
++ if (i == 0)
++ clk = clk_get(dev, NULL);
++ else
++ clk = of_clk_get(dev->of_node, i);
++
++ if (IS_ERR(clk)) {
++ rc = PTR_ERR(clk);
++ if (rc == -EPROBE_DEFER)
++ goto free_clk;
++ break;
+ }
++ hpriv->clks[i] = clk;
+ }
+
++ rc = ahci_enable_clks(dev, hpriv);
++ if (rc)
++ goto free_clk;
++
+ /*
+ * Some platforms might need to prepare for mmio region access,
+ * which could be done in the following init call. So, the mmio
+@@ -222,11 +297,9 @@ static int ahci_probe(struct platform_device *pdev)
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+ disable_unprepare_clk:
+- if (!IS_ERR(hpriv->clk))
+- clk_disable_unprepare(hpriv->clk);
++ ahci_disable_clks(hpriv);
+ free_clk:
+- if (!IS_ERR(hpriv->clk))
+- clk_put(hpriv->clk);
++ ahci_put_clks(hpriv);
+ return rc;
+ }
+
+@@ -239,10 +312,8 @@ static void ahci_host_stop(struct ata_host *host)
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+
+- if (!IS_ERR(hpriv->clk)) {
+- clk_disable_unprepare(hpriv->clk);
+- clk_put(hpriv->clk);
+- }
++ ahci_disable_clks(hpriv);
++ ahci_put_clks(hpriv);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -277,8 +348,7 @@ static int ahci_suspend(struct device *dev)
+ if (pdata && pdata->suspend)
+ return pdata->suspend(dev);
+
+- if (!IS_ERR(hpriv->clk))
+- clk_disable_unprepare(hpriv->clk);
++ ahci_disable_clks(hpriv);
+
+ return 0;
+ }
+@@ -290,13 +360,9 @@ static int ahci_resume(struct device *dev)
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+- if (!IS_ERR(hpriv->clk)) {
+- rc = clk_prepare_enable(hpriv->clk);
+- if (rc) {
+- dev_err(dev, "clock prepare enable failed");
+- return rc;
+- }
+- }
++ rc = ahci_enable_clks(dev, hpriv);
++ if (rc)
++ return rc;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+@@ -317,8 +383,7 @@ static int ahci_resume(struct device *dev)
+ return 0;
+
+ disable_unprepare_clk:
+- if (!IS_ERR(hpriv->clk))
+- clk_disable_unprepare(hpriv->clk);
++ ahci_disable_clks(hpriv);
+
+ return rc;
+ }
+diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
+index 73a2500..769d065 100644
+--- a/include/linux/ahci_platform.h
++++ b/include/linux/ahci_platform.h
+@@ -19,6 +19,7 @@
+
+ struct device;
+ struct ata_port_info;
++struct ahci_host_priv;
+
+ struct ahci_platform_data {
+ int (*init)(struct device *dev, void __iomem *addr);
+@@ -30,4 +31,7 @@ struct ahci_platform_data {
+ unsigned int mask_port_map;
+ };
+
++int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
++void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
++
+ #endif /* _AHCI_PLATFORM_H */
+--
+2.0.3
+
+From 3dc53b267843b6dfeb2eb67e52e17915dc2347ab Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Fri, 17 Jan 2014 13:23:21 +0100
+Subject: [PATCH] ahci-platform: Add support for an optional regulator for
+ sata-target power
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../devicetree/bindings/ata/ahci-platform.txt | 1 +
+ drivers/ata/ahci.h | 2 ++
+ drivers/ata/ahci_platform.c | 36 ++++++++++++++++++++--
+ 3 files changed, 37 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+index 3ced07d..1ac807f 100644
+--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
++++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+@@ -11,6 +11,7 @@ Required properties:
+ Optional properties:
+ - dma-coherent : Present if dma operations are coherent
+ - clocks : a list of phandle + clock specifier pairs
++- target-supply : regulator for SATA target power
+
+ Example:
+ sata@ffe08000 {
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index c12862b..bf8100c 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -37,6 +37,7 @@
+
+ #include <linux/clk.h>
+ #include <linux/libata.h>
++#include <linux/regulator/consumer.h>
+
+ /* Enclosure Management Control */
+ #define EM_CTRL_MSG_TYPE 0x000f0000
+@@ -323,6 +324,7 @@ struct ahci_host_priv {
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
++ struct regulator *target_pwr; /* Optional */
+ void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 609975d..907c076 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -192,6 +192,14 @@ static int ahci_probe(struct platform_device *pdev)
+ return -ENOMEM;
+ }
+
++ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
++ if (IS_ERR(hpriv->target_pwr)) {
++ rc = PTR_ERR(hpriv->target_pwr);
++ if (rc == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ hpriv->target_pwr = NULL;
++ }
++
+ for (i = 0; i < AHCI_MAX_CLKS; i++) {
+ /*
+ * For now we must use clk_get(dev, NULL) for the first clock,
+@@ -213,9 +221,15 @@ static int ahci_probe(struct platform_device *pdev)
+ hpriv->clks[i] = clk;
+ }
+
++ if (hpriv->target_pwr) {
++ rc = regulator_enable(hpriv->target_pwr);
++ if (rc)
++ goto free_clk;
++ }
++
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+- goto free_clk;
++ goto disable_regulator;
+
+ /*
+ * Some platforms might need to prepare for mmio region access,
+@@ -298,6 +312,9 @@ static int ahci_probe(struct platform_device *pdev)
+ pdata->exit(dev);
+ disable_unprepare_clk:
+ ahci_disable_clks(hpriv);
++disable_regulator:
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
+ free_clk:
+ ahci_put_clks(hpriv);
+ return rc;
+@@ -314,6 +331,9 @@ static void ahci_host_stop(struct ata_host *host)
+
+ ahci_disable_clks(hpriv);
+ ahci_put_clks(hpriv);
++
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -350,6 +370,9 @@ static int ahci_suspend(struct device *dev)
+
+ ahci_disable_clks(hpriv);
+
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
++
+ return 0;
+ }
+
+@@ -360,9 +383,15 @@ static int ahci_resume(struct device *dev)
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
++ if (hpriv->target_pwr) {
++ rc = regulator_enable(hpriv->target_pwr);
++ if (rc)
++ return rc;
++ }
++
+ rc = ahci_enable_clks(dev, hpriv);
+ if (rc)
+- return rc;
++ goto disable_regulator;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+@@ -384,6 +413,9 @@ static int ahci_resume(struct device *dev)
+
+ disable_unprepare_clk:
+ ahci_disable_clks(hpriv);
++disable_regulator:
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
+
+ return rc;
+ }
+--
+2.0.3
+
+From 74f54552b061865ff46d43aa68d0c6e8852dc592 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 20 Jan 2014 14:54:40 +0100
+Subject: [PATCH] ahci-platform: Add enable_ / disable_resources helper
+ functions
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci_platform.c | 112 ++++++++++++++++++++++++++++--------------
+ include/linux/ahci_platform.h | 2 +
+ 2 files changed, 77 insertions(+), 37 deletions(-)
+
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 907c076..6ebbc17 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -139,6 +139,68 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
+ }
+ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+
++/**
++ * ahci_platform_enable_resources - Enable platform resources
++ * @hpriv: host private area to store config values
++ *
++ * This function enables all ahci_platform managed resources in
++ * the following order:
++ * 1) Regulator
++ * 2) Clocks (through ahci_platform_enable_clks)
++ *
++ * If resource enabling fails at any point the previous enabled
++ * resources are disabled in reverse order.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
++{
++ int rc;
++
++ if (hpriv->target_pwr) {
++ rc = regulator_enable(hpriv->target_pwr);
++ if (rc)
++ return rc;
++ }
++
++ rc = ahci_platform_enable_clks(hpriv);
++ if (rc)
++ goto disable_regulator;
++
++ return 0;
++
++disable_regulator:
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
++ return rc;
++}
++EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
++
++/**
++ * ahci_platform_disable_resources - Disable platform resources
++ * @hpriv: host private area to store config values
++ *
++ * This function disables all ahci_platform managed resources in
++ * the following order:
++ * 1) Clocks (through ahci_platform_disable_clks)
++ * 2) Regulator
++ *
++ * LOCKING:
++ * None.
++ */
++void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
++{
++ ahci_platform_disable_clks(hpriv);
++
++ if (hpriv->target_pwr)
++ regulator_disable(hpriv->target_pwr);
++}
++EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
++
+ static void ahci_put_clks(struct ahci_host_priv *hpriv)
+ {
+ int c;
+@@ -221,15 +283,9 @@ static int ahci_probe(struct platform_device *pdev)
+ hpriv->clks[i] = clk;
+ }
+
+- if (hpriv->target_pwr) {
+- rc = regulator_enable(hpriv->target_pwr);
+- if (rc)
+- goto free_clk;
+- }
+-
+- rc = ahci_enable_clks(dev, hpriv);
++ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+- goto disable_regulator;
++ goto free_clk;
+
+ /*
+ * Some platforms might need to prepare for mmio region access,
+@@ -240,7 +296,7 @@ static int ahci_probe(struct platform_device *pdev)
+ if (pdata && pdata->init) {
+ rc = pdata->init(dev, hpriv->mmio);
+ if (rc)
+- goto disable_unprepare_clk;
++ goto disable_resources;
+ }
+
+ ahci_save_initial_config(dev, hpriv,
+@@ -310,11 +366,8 @@ static int ahci_probe(struct platform_device *pdev)
+ pdata_exit:
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+-disable_unprepare_clk:
+- ahci_disable_clks(hpriv);
+-disable_regulator:
+- if (hpriv->target_pwr)
+- regulator_disable(hpriv->target_pwr);
++disable_resources:
++ ahci_platform_disable_resources(hpriv);
+ free_clk:
+ ahci_put_clks(hpriv);
+ return rc;
+@@ -329,11 +382,8 @@ static void ahci_host_stop(struct ata_host *host)
+ if (pdata && pdata->exit)
+ pdata->exit(dev);
+
+- ahci_disable_clks(hpriv);
++ ahci_platform_disable_resources(hpriv);
+ ahci_put_clks(hpriv);
+-
+- if (hpriv->target_pwr)
+- regulator_disable(hpriv->target_pwr);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+@@ -368,10 +418,7 @@ static int ahci_suspend(struct device *dev)
+ if (pdata && pdata->suspend)
+ return pdata->suspend(dev);
+
+- ahci_disable_clks(hpriv);
+-
+- if (hpriv->target_pwr)
+- regulator_disable(hpriv->target_pwr);
++ ahci_platform_disable_resources(hpriv);
+
+ return 0;
+ }
+@@ -383,26 +430,20 @@ static int ahci_resume(struct device *dev)
+ struct ahci_host_priv *hpriv = host->private_data;
+ int rc;
+
+- if (hpriv->target_pwr) {
+- rc = regulator_enable(hpriv->target_pwr);
+- if (rc)
+- return rc;
+- }
+-
+- rc = ahci_enable_clks(dev, hpriv);
++ rc = ahci_platform_enable_resources(hpriv);
+ if (rc)
+- goto disable_regulator;
++ return rc;
+
+ if (pdata && pdata->resume) {
+ rc = pdata->resume(dev);
+ if (rc)
+- goto disable_unprepare_clk;
++ goto disable_resources;
+ }
+
+ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(host);
+ if (rc)
+- goto disable_unprepare_clk;
++ goto disable_resources;
+
+ ahci_init_controller(host);
+ }
+@@ -411,11 +452,8 @@ static int ahci_resume(struct device *dev)
+
+ return 0;
+
+-disable_unprepare_clk:
+- ahci_disable_clks(hpriv);
+-disable_regulator:
+- if (hpriv->target_pwr)
+- regulator_disable(hpriv->target_pwr);
++disable_resources:
++ ahci_platform_disable_resources(hpriv);
+
+ return rc;
+ }
+diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
+index 769d065..b674b01 100644
+--- a/include/linux/ahci_platform.h
++++ b/include/linux/ahci_platform.h
+@@ -33,5 +33,7 @@ struct ahci_platform_data {
+
+ int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
++int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
++void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
+
+ #endif /* _AHCI_PLATFORM_H */
+--
+2.0.3
+
+From 88972833cba7a6dad8e9a1c9b43ab02fc274e4fd Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 20 Jan 2014 14:58:04 +0100
+Subject: [PATCH] ahci-platform: "Library-ise" ahci_probe functionality
+
+ahci_probe consists of 3 steps:
+1) Get resources (get mmio, clks, regulator)
+2) Enable resources, handled by ahci_platform_enable_resouces
+3) The more or less standard ahci-host controller init sequence
+
+This commit refactors step 1 and 3 into separate functions, so the platform
+drivers for AHCI implementations which need a specific order in step 2,
+and / or need to do some custom register poking at some time, can re-use
+ahci-platform.c code without needing to copy and paste it.
+
+Note that ahci_platform_init_host's prototype takes the 3 non function
+members of ahci_platform_data as arguments, the idea is that drivers using
+the new exported utility functions will not use ahci_platform_data at all,
+and hopefully in the future ahci_platform_data can go away entirely.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci_platform.c | 195 ++++++++++++++++++++++++++++--------------
+ include/linux/ahci_platform.h | 14 +++
+ 2 files changed, 144 insertions(+), 65 deletions(-)
+
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 6ebbc17..7f3f2ac 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -201,64 +201,64 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+ }
+ EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
+
+-static void ahci_put_clks(struct ahci_host_priv *hpriv)
++static void ahci_platform_put_resources(struct device *dev, void *res)
+ {
++ struct ahci_host_priv *hpriv = res;
+ int c;
+
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+ }
+
+-static int ahci_probe(struct platform_device *pdev)
++/**
++ * ahci_platform_get_resources - Get platform resources
++ * @pdev: platform device to get resources for
++ *
++ * This function allocates an ahci_host_priv struct, and gets the
++ * following resources, storing a reference to them inside the returned
++ * struct:
++ *
++ * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
++ * 2) regulator for controlling the targets power (optional)
++ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
++ * or for non devicetree enabled platforms a single clock
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
++ */
++struct ahci_host_priv *ahci_platform_get_resources(
++ struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+- struct ahci_platform_data *pdata = dev_get_platdata(dev);
+- const struct platform_device_id *id = platform_get_device_id(pdev);
+- struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
+- const struct ata_port_info *ppi[] = { &pi, NULL };
+ struct ahci_host_priv *hpriv;
+- struct ata_host *host;
+- struct resource *mem;
+ struct clk *clk;
+- int irq;
+- int n_ports;
+- int i;
+- int rc;
++ int i, rc = -ENOMEM;
+
+- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (!mem) {
+- dev_err(dev, "no mmio space\n");
+- return -EINVAL;
+- }
++ if (!devres_open_group(dev, NULL, GFP_KERNEL))
++ return ERR_PTR(-ENOMEM);
+
+- irq = platform_get_irq(pdev, 0);
+- if (irq <= 0) {
+- dev_err(dev, "no irq\n");
+- return -EINVAL;
+- }
++ hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
++ GFP_KERNEL);
++ if (!hpriv)
++ goto err_out;
+
+- if (pdata && pdata->ata_port_info)
+- pi = *pdata->ata_port_info;
++ devres_add(dev, hpriv);
+
+- hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
+- if (!hpriv) {
+- dev_err(dev, "can't alloc ahci_host_priv\n");
+- return -ENOMEM;
+- }
+-
+- hpriv->flags |= (unsigned long)pi.private_data;
+-
+- hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
++ hpriv->mmio = devm_ioremap_resource(dev,
++ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ if (!hpriv->mmio) {
+- dev_err(dev, "can't map %pR\n", mem);
+- return -ENOMEM;
++ dev_err(dev, "no mmio space\n");
++ goto err_out;
+ }
+
+ hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
+ if (IS_ERR(hpriv->target_pwr)) {
+ rc = PTR_ERR(hpriv->target_pwr);
+ if (rc == -EPROBE_DEFER)
+- return -EPROBE_DEFER;
++ goto err_out;
+ hpriv->target_pwr = NULL;
+ }
+
+@@ -277,33 +277,62 @@ static int ahci_probe(struct platform_device *pdev)
+ if (IS_ERR(clk)) {
+ rc = PTR_ERR(clk);
+ if (rc == -EPROBE_DEFER)
+- goto free_clk;
++ goto err_out;
+ break;
+ }
+ hpriv->clks[i] = clk;
+ }
+
+- rc = ahci_platform_enable_resources(hpriv);
+- if (rc)
+- goto free_clk;
++ devres_remove_group(dev, NULL);
++ return hpriv;
+
+- /*
+- * Some platforms might need to prepare for mmio region access,
+- * which could be done in the following init call. So, the mmio
+- * region shouldn't be accessed before init (if provided) has
+- * returned successfully.
+- */
+- if (pdata && pdata->init) {
+- rc = pdata->init(dev, hpriv->mmio);
+- if (rc)
+- goto disable_resources;
+- }
++err_out:
++ devres_release_group(dev, NULL);
++ return ERR_PTR(rc);
++}
++EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
++
++/**
++ * ahci_platform_init_host - Bring up an ahci-platform host
++ * @pdev: platform device pointer for the host
++ * @hpriv: ahci-host private data for the host
++ * @pi_template: template for the ata_port_info to use
++ * @force_port_map: param passed to ahci_save_initial_config
++ * @mask_port_map: param passed to ahci_save_initial_config
++ *
++ * This function does all the usual steps needed to bring up an
++ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
++ * must be initialized / enabled before calling this.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_init_host(struct platform_device *pdev,
++ struct ahci_host_priv *hpriv,
++ const struct ata_port_info *pi_template,
++ unsigned int force_port_map,
++ unsigned int mask_port_map)
++{
++ struct device *dev = &pdev->dev;
++ struct ata_port_info pi = *pi_template;
++ const struct ata_port_info *ppi[] = { &pi, NULL };
++ struct ata_host *host;
++ int i, irq, n_ports, rc;
+
+- ahci_save_initial_config(dev, hpriv,
+- pdata ? pdata->force_port_map : 0,
+- pdata ? pdata->mask_port_map : 0);
++ irq = platform_get_irq(pdev, 0);
++ if (irq <= 0) {
++ dev_err(dev, "no irq\n");
++ return -EINVAL;
++ }
+
+ /* prepare host */
++ hpriv->flags |= (unsigned long)pi.private_data;
++
++ ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
++
+ if (hpriv->cap & HOST_CAP_NCQ)
+ pi.flags |= ATA_FLAG_NCQ;
+
+@@ -320,10 +349,8 @@ static int ahci_probe(struct platform_device *pdev)
+ n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
+
+ host = ata_host_alloc_pinfo(dev, ppi, n_ports);
+- if (!host) {
+- rc = -ENOMEM;
+- goto pdata_exit;
+- }
++ if (!host)
++ return -ENOMEM;
+
+ host->private_data = hpriv;
+
+@@ -338,7 +365,8 @@ static int ahci_probe(struct platform_device *pdev)
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+- ata_port_desc(ap, "mmio %pR", mem);
++ ata_port_desc(ap, "mmio %pR",
++ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
+
+ /* set enclosure management message type */
+@@ -352,13 +380,53 @@ static int ahci_probe(struct platform_device *pdev)
+
+ rc = ahci_reset_controller(host);
+ if (rc)
+- goto pdata_exit;
++ return rc;
+
+ ahci_init_controller(host);
+ ahci_print_info(host, "platform");
+
+- rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
+- &ahci_platform_sht);
++ return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
++ &ahci_platform_sht);
++}
++EXPORT_SYMBOL_GPL(ahci_platform_init_host);
++
++static int ahci_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct ahci_platform_data *pdata = dev_get_platdata(dev);
++ const struct platform_device_id *id = platform_get_device_id(pdev);
++ const struct ata_port_info *pi_template;
++ struct ahci_host_priv *hpriv;
++ int rc;
++
++ hpriv = ahci_platform_get_resources(pdev);
++ if (IS_ERR(hpriv))
++ return PTR_ERR(hpriv);
++
++ rc = ahci_platform_enable_resources(hpriv);
++ if (rc)
++ return rc;
++
++ /*
++ * Some platforms might need to prepare for mmio region access,
++ * which could be done in the following init call. So, the mmio
++ * region shouldn't be accessed before init (if provided) has
++ * returned successfully.
++ */
++ if (pdata && pdata->init) {
++ rc = pdata->init(dev, hpriv->mmio);
++ if (rc)
++ goto disable_resources;
++ }
++
++ if (pdata && pdata->ata_port_info)
++ pi_template = pdata->ata_port_info;
++ else
++ pi_template = &ahci_port_info[id ? id->driver_data : 0];
++
++ rc = ahci_platform_init_host(pdev, hpriv, pi_template,
++ pdata ? pdata->force_port_map : 0,
++ pdata ? pdata->mask_port_map : 0);
+ if (rc)
+ goto pdata_exit;
+
+@@ -368,8 +436,6 @@ static int ahci_probe(struct platform_device *pdev)
+ pdata->exit(dev);
+ disable_resources:
+ ahci_platform_disable_resources(hpriv);
+-free_clk:
+- ahci_put_clks(hpriv);
+ return rc;
+ }
+
+@@ -383,7 +449,6 @@ static void ahci_host_stop(struct ata_host *host)
+ pdata->exit(dev);
+
+ ahci_platform_disable_resources(hpriv);
+- ahci_put_clks(hpriv);
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
+index b674b01..b80c51c 100644
+--- a/include/linux/ahci_platform.h
++++ b/include/linux/ahci_platform.h
+@@ -20,7 +20,14 @@
+ struct device;
+ struct ata_port_info;
+ struct ahci_host_priv;
++struct platform_device;
+
++/*
++ * Note ahci_platform_data is deprecated, it is only kept around for use
++ * by the old da850 and spear13xx ahci code.
++ * New drivers should instead declare their own platform_driver struct, and
++ * use ahci_platform* functions in their own probe, suspend and resume methods.
++ */
+ struct ahci_platform_data {
+ int (*init)(struct device *dev, void __iomem *addr);
+ void (*exit)(struct device *dev);
+@@ -35,5 +42,12 @@ int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
+ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
+ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
+ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
++struct ahci_host_priv *ahci_platform_get_resources(
++ struct platform_device *pdev);
++int ahci_platform_init_host(struct platform_device *pdev,
++ struct ahci_host_priv *hpriv,
++ const struct ata_port_info *pi_template,
++ unsigned int force_port_map,
++ unsigned int mask_port_map);
+
+ #endif /* _AHCI_PLATFORM_H */
+--
+2.0.3
+
+From dffde1e107b4360a4ff6b3aec3693e8b3b4a1bd0 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Mon, 20 Jan 2014 15:52:07 +0100
+Subject: [PATCH] ahci-platform: "Library-ise" suspend / resume functionality
+
+Split suspend / resume code into host suspend / resume functionality and
+resource enable / disabling phases, and export the new suspend_ / resume_host
+functions.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci_platform.c | 109 ++++++++++++++++++++++++++++++++++++------
+ include/linux/ahci_platform.h | 5 ++
+ 2 files changed, 99 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 7f3f2ac..bdadec1 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -452,14 +452,26 @@ static void ahci_host_stop(struct ata_host *host)
+ }
+
+ #ifdef CONFIG_PM_SLEEP
+-static int ahci_suspend(struct device *dev)
++/**
++ * ahci_platform_suspend_host - Suspend an ahci-platform host
++ * @dev: device pointer for the host
++ *
++ * This function does all the usual steps needed to suspend an
++ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
++ * must be disabled after calling this.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_suspend_host(struct device *dev)
+ {
+- struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->mmio;
+ u32 ctl;
+- int rc;
+
+ if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
+ dev_err(dev, "firmware update required for suspend/resume\n");
+@@ -476,7 +488,64 @@ static int ahci_suspend(struct device *dev)
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+
+- rc = ata_host_suspend(host, PMSG_SUSPEND);
++ return ata_host_suspend(host, PMSG_SUSPEND);
++}
++EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
++
++/**
++ * ahci_platform_resume_host - Resume an ahci-platform host
++ * @dev: device pointer for the host
++ *
++ * This function does all the usual steps needed to resume an
++ * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
++ * must be initialized / enabled before calling this.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_resume_host(struct device *dev)
++{
++ struct ata_host *host = dev_get_drvdata(dev);
++ int rc;
++
++ if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
++ rc = ahci_reset_controller(host);
++ if (rc)
++ return rc;
++
++ ahci_init_controller(host);
++ }
++
++ ata_host_resume(host);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
++
++/**
++ * ahci_platform_suspend - Suspend an ahci-platform device
++ * @dev: the platform device to suspend
++ *
++ * This function suspends the host associated with the device, followed
++ * by disabling all the resources of the device.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_suspend(struct device *dev)
++{
++ struct ahci_platform_data *pdata = dev_get_platdata(dev);
++ struct ata_host *host = dev_get_drvdata(dev);
++ struct ahci_host_priv *hpriv = host->private_data;
++ int rc;
++
++ rc = ahci_platform_suspend_host(dev);
+ if (rc)
+ return rc;
+
+@@ -487,8 +556,22 @@ static int ahci_suspend(struct device *dev)
+
+ return 0;
+ }
++EXPORT_SYMBOL_GPL(ahci_platform_suspend);
+
+-static int ahci_resume(struct device *dev)
++/**
++ * ahci_platform_resume - Resume an ahci-platform device
++ * @dev: the platform device to resume
++ *
++ * This function enables all the resources of the device followed by
++ * resuming the host associated with the device.
++ *
++ * LOCKING:
++ * None.
++ *
++ * RETURNS:
++ * 0 on success otherwise a negative error code
++ */
++int ahci_platform_resume(struct device *dev)
+ {
+ struct ahci_platform_data *pdata = dev_get_platdata(dev);
+ struct ata_host *host = dev_get_drvdata(dev);
+@@ -505,15 +588,9 @@ static int ahci_resume(struct device *dev)
+ goto disable_resources;
+ }
+
+- if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
+- rc = ahci_reset_controller(host);
+- if (rc)
+- goto disable_resources;
+-
+- ahci_init_controller(host);
+- }
+-
+- ata_host_resume(host);
++ rc = ahci_platform_resume_host(dev);
++ if (rc)
++ goto disable_resources;
+
+ return 0;
+
+@@ -522,9 +599,11 @@ static int ahci_resume(struct device *dev)
+
+ return rc;
+ }
++EXPORT_SYMBOL_GPL(ahci_platform_resume);
+ #endif
+
+-static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
++static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
++ ahci_platform_resume);
+
+ static const struct of_device_id ahci_of_match[] = {
+ { .compatible = "snps,spear-ahci", },
+diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
+index b80c51c..542f268 100644
+--- a/include/linux/ahci_platform.h
++++ b/include/linux/ahci_platform.h
+@@ -50,4 +50,9 @@ int ahci_platform_init_host(struct platform_device *pdev,
+ unsigned int force_port_map,
+ unsigned int mask_port_map);
+
++int ahci_platform_suspend_host(struct device *dev);
++int ahci_platform_resume_host(struct device *dev);
++int ahci_platform_suspend(struct device *dev);
++int ahci_platform_resume(struct device *dev);
++
+ #endif /* _AHCI_PLATFORM_H */
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/191-ahci-add-sunxi-driver.patch b/target/linux/sunxi/patches-3.14/191-ahci-add-sunxi-driver.patch
new file mode 100644
index 0000000000..51f5ec4686
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/191-ahci-add-sunxi-driver.patch
@@ -0,0 +1,352 @@
+From 49270be12ed66b6aff84292f63c16ed77a62e8a6 Mon Sep 17 00:00:00 2001
+From: Olliver Schinagl <oliver@schinagl.nl>
+Date: Sat, 18 Jan 2014 15:00:45 +0100
+Subject: [PATCH] ARM: sunxi: Add support for Allwinner SUNXi SoCs sata to
+ ahci_platform
+
+This patch adds support for the ahci sata controler found on Allwinner A10
+and A20 SoCs to the ahci_platform driver.
+
+Orignally written by Olliver Schinagl using the approach of having a platform
+device which probe method creates a new child platform device which gets
+driven by ahci_platform.c, as done by ahci_imx.c .
+
+Refactored by Hans de Goede to add most of the non sunxi specific functionality
+to ahci_platform.c and use a platform_data pointer from of_device_id for the
+sunxi specific bits.
+
+Signed-off-by: Olliver Schinagl <oliver@schinagl.nl>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ .../devicetree/bindings/ata/ahci-platform.txt | 15 +-
+ drivers/ata/Kconfig | 9 +
+ drivers/ata/Makefile | 1 +
+ drivers/ata/ahci_sunxi.c | 249 +++++++++++++++++++++
+ 4 files changed, 271 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/ata/ahci_sunxi.c
+
+diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+index 1ac807f..499bfed 100644
+--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
++++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
+@@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
+ Each SATA controller should have its own node.
+
+ Required properties:
+-- compatible : compatible list, contains "snps,spear-ahci"
++- compatible : compatible list, one of "snps,spear-ahci",
++ "snps,exynos5440-ahci", "ibm,476gtr-ahci", or
++ "allwinner,sun4i-a10-ahci"
+ - interrupts : <interrupt mapping for SATA IRQ>
+ - reg : <registers mapping>
+
+@@ -13,10 +15,17 @@ Optional properties:
+ - clocks : a list of phandle + clock specifier pairs
+ - target-supply : regulator for SATA target power
+
+-Example:
++Examples:
+ sata@ffe08000 {
+ compatible = "snps,spear-ahci";
+ reg = <0xffe08000 0x1000>;
+ interrupts = <115>;
+-
+ };
++
++ ahci: sata@01c18000 {
++ compatible = "allwinner,sun4i-a10-ahci";
++ reg = <0x01c18000 0x1000>;
++ interrupts = <56>;
++ clocks = <&pll6 0>, <&ahb_gates 25>;
++ target-supply = <&reg_ahci_5v>;
++ };
+diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
+index 868429a4..10a9c25 100644
+--- a/drivers/ata/Kconfig
++++ b/drivers/ata/Kconfig
+@@ -106,6 +106,15 @@ config AHCI_IMX
+
+ If unsure, say N.
+
++config AHCI_SUNXI
++ tristate "Allwinner sunxi AHCI SATA support"
++ depends on ARCH_SUNXI && SATA_AHCI_PLATFORM
++ help
++ This option enables support for the Allwinner sunxi SoC's
++ onboard AHCI SATA.
++
++ If unsure, say N.
++
+ config SATA_FSL
+ tristate "Freescale 3.0Gbps SATA support"
+ depends on FSL_SOC
+diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
+index 46518c6..246050b 100644
+--- a/drivers/ata/Makefile
++++ b/drivers/ata/Makefile
+@@ -11,6 +11,7 @@ obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
+ obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
+ obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
+ obj-$(CONFIG_AHCI_IMX) += ahci_imx.o
++obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o
+
+ # SFF w/ custom DMA
+ obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
+new file mode 100644
+index 0000000..001f7dfc
+--- /dev/null
++++ b/drivers/ata/ahci_sunxi.c
+@@ -0,0 +1,249 @@
++/*
++ * Allwinner sunxi AHCI SATA platform driver
++ * Copyright 2013 Olliver Schinagl <oliver@schinagl.nl>
++ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
++ * Based on code from Allwinner Technology Co., Ltd. <www.allwinnertech.com>,
++ * Daniel Wang <danielwang@allwinnertech.com>
++ *
++ * 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.
++ */
++
++#include <linux/ahci_platform.h>
++#include <linux/clk.h>
++#include <linux/errno.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include "ahci.h"
++
++#define AHCI_BISTAFR 0x00a0
++#define AHCI_BISTCR 0x00a4
++#define AHCI_BISTFCTR 0x00a8
++#define AHCI_BISTSR 0x00ac
++#define AHCI_BISTDECR 0x00b0
++#define AHCI_DIAGNR0 0x00b4
++#define AHCI_DIAGNR1 0x00b8
++#define AHCI_OOBR 0x00bc
++#define AHCI_PHYCS0R 0x00c0
++#define AHCI_PHYCS1R 0x00c4
++#define AHCI_PHYCS2R 0x00c8
++#define AHCI_TIMER1MS 0x00e0
++#define AHCI_GPARAM1R 0x00e8
++#define AHCI_GPARAM2R 0x00ec
++#define AHCI_PPARAMR 0x00f0
++#define AHCI_TESTR 0x00f4
++#define AHCI_VERSIONR 0x00f8
++#define AHCI_IDR 0x00fc
++#define AHCI_RWCR 0x00fc
++#define AHCI_P0DMACR 0x0170
++#define AHCI_P0PHYCR 0x0178
++#define AHCI_P0PHYSR 0x017c
++
++static void sunxi_clrbits(void __iomem *reg, u32 clr_val)
++{
++ u32 reg_val;
++
++ reg_val = readl(reg);
++ reg_val &= ~(clr_val);
++ writel(reg_val, reg);
++}
++
++static void sunxi_setbits(void __iomem *reg, u32 set_val)
++{
++ u32 reg_val;
++
++ reg_val = readl(reg);
++ reg_val |= set_val;
++ writel(reg_val, reg);
++}
++
++static void sunxi_clrsetbits(void __iomem *reg, u32 clr_val, u32 set_val)
++{
++ u32 reg_val;
++
++ reg_val = readl(reg);
++ reg_val &= ~(clr_val);
++ reg_val |= set_val;
++ writel(reg_val, reg);
++}
++
++static u32 sunxi_getbits(void __iomem *reg, u8 mask, u8 shift)
++{
++ return (readl(reg) >> shift) & mask;
++}
++
++static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
++{
++ u32 reg_val;
++ int timeout;
++
++ /* This magic is from the original code */
++ writel(0, reg_base + AHCI_RWCR);
++ mdelay(5);
++
++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
++ (0x7 << 24),
++ (0x5 << 24) | BIT(23) | BIT(18));
++ sunxi_clrsetbits(reg_base + AHCI_PHYCS1R,
++ (0x3 << 16) | (0x1f << 8) | (0x3 << 6),
++ (0x2 << 16) | (0x6 << 8) | (0x2 << 6));
++ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(28) | BIT(15));
++ sunxi_clrbits(reg_base + AHCI_PHYCS1R, BIT(19));
++ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
++ (0x7 << 20), (0x3 << 20));
++ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
++ (0x1f << 5), (0x19 << 5));
++ mdelay(5);
++
++ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
++
++ timeout = 250; /* Power up takes aprox 50 us */
++ do {
++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS0R, 0x7, 28);
++ if (reg_val == 0x02)
++ break;
++
++ if (--timeout == 0) {
++ dev_err(dev, "PHY power up failed.\n");
++ return -EIO;
++ }
++ udelay(1);
++ } while (1);
++
++ sunxi_setbits(reg_base + AHCI_PHYCS2R, (0x1 << 24));
++
++ timeout = 100; /* Calibration takes aprox 10 us */
++ do {
++ reg_val = sunxi_getbits(reg_base + AHCI_PHYCS2R, 0x1, 24);
++ if (reg_val == 0x00)
++ break;
++
++ if (--timeout == 0) {
++ dev_err(dev, "PHY calibration failed.\n");
++ return -EIO;
++ }
++ udelay(1);
++ } while (1);
++
++ mdelay(15);
++
++ writel(0x7, reg_base + AHCI_RWCR);
++
++ return 0;
++}
++
++static void ahci_sunxi_start_engine(struct ata_port *ap)
++{
++ void __iomem *port_mmio = ahci_port_base(ap);
++ struct ahci_host_priv *hpriv = ap->host->private_data;
++
++ /* Setup DMA before DMA start */
++ sunxi_clrsetbits(hpriv->mmio + AHCI_P0DMACR, 0x0000ff00, 0x00004400);
++
++ /* Start DMA */
++ sunxi_setbits(port_mmio + PORT_CMD, PORT_CMD_START);
++}
++
++static const struct ata_port_info ahci_sunxi_port_info = {
++ AHCI_HFLAGS(AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
++ AHCI_HFLAG_NO_PMP | AHCI_HFLAG_YES_NCQ),
++ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NCQ,
++ .pio_mask = ATA_PIO4,
++ .udma_mask = ATA_UDMA6,
++ .port_ops = &ahci_platform_ops,
++};
++
++static int ahci_sunxi_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct ahci_host_priv *hpriv;
++ int rc;
++
++ hpriv = ahci_platform_get_resources(pdev);
++ if (IS_ERR(hpriv))
++ return PTR_ERR(hpriv);
++
++ hpriv->start_engine = ahci_sunxi_start_engine;
++
++ rc = ahci_platform_enable_resources(hpriv);
++ if (rc)
++ return rc;
++
++ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
++ if (rc)
++ goto disable_resources;
++
++ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info, 0, 0);
++ if (rc)
++ goto disable_resources;
++
++ return 0;
++
++disable_resources:
++ ahci_platform_disable_resources(hpriv);
++ return rc;
++}
++
++#ifdef CONFIG_PM_SLEEP
++int ahci_sunxi_resume(struct device *dev)
++{
++ struct ata_host *host = dev_get_drvdata(dev);
++ struct ahci_host_priv *hpriv = host->private_data;
++ int rc;
++
++ rc = ahci_platform_enable_resources(hpriv);
++ if (rc)
++ return rc;
++
++ rc = ahci_sunxi_phy_init(dev, hpriv->mmio);
++ if (rc)
++ goto disable_resources;
++
++ rc = ahci_platform_resume_host(dev);
++ if (rc)
++ goto disable_resources;
++
++ return 0;
++
++disable_resources:
++ ahci_platform_disable_resources(hpriv);
++ return rc;
++}
++#endif
++
++static SIMPLE_DEV_PM_OPS(ahci_sunxi_pm_ops, ahci_platform_suspend,
++ ahci_sunxi_resume);
++
++static const struct of_device_id ahci_sunxi_of_match[] = {
++ { .compatible = "allwinner,sun4i-a10-ahci", },
++ { },
++};
++MODULE_DEVICE_TABLE(of, ahci_sunxi_of_match);
++
++static struct platform_driver ahci_sunxi_driver = {
++ .probe = ahci_sunxi_probe,
++ .remove = ata_platform_remove_one,
++ .driver = {
++ .name = "ahci-sunxi",
++ .owner = THIS_MODULE,
++ .of_match_table = ahci_sunxi_of_match,
++ .pm = &ahci_sunxi_pm_ops,
++ },
++};
++module_platform_driver(ahci_sunxi_driver);
++
++MODULE_DESCRIPTION("Allwinner sunxi AHCI SATA driver");
++MODULE_AUTHOR("Olliver Schinagl <oliver@schinagl.nl>");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/192-ahci-platform-changes.patch b/target/linux/sunxi/patches-3.14/192-ahci-platform-changes.patch
new file mode 100644
index 0000000000..3c567f82a4
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/192-ahci-platform-changes.patch
@@ -0,0 +1,305 @@
+From a52ae09871d171d6771b4bef2d4c56dd435e740f Mon Sep 17 00:00:00 2001
+From: Roger Quadros <rogerq@ti.com>
+Date: Mon, 20 Jan 2014 16:32:33 +0200
+Subject: [PATCH] ata: ahci_platform: Add DT compatible for Synopsis DWC AHCI
+ controller
+
+Add compatible string "snps,dwc-ahci", which should be used
+for Synopsis Designware SATA cores. e.g. on TI OMAP5 and DRA7 platforms.
+
+Signed-off-by: Roger Quadros <rogerq@ti.com>
+Reviewed-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci_platform.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index bdadec1..d7e55ba 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -609,6 +609,7 @@ static const struct of_device_id ahci_of_match[] = {
+ { .compatible = "snps,spear-ahci", },
+ { .compatible = "snps,exynos5440-ahci", },
+ { .compatible = "ibm,476gtr-ahci", },
++ { .compatible = "snps,dwc-ahci", },
+ {},
+ };
+ MODULE_DEVICE_TABLE(of, ahci_of_match);
+--
+2.0.3
+
+From 2be39fa6b6531bd083c766999345adc348b14c77 Mon Sep 17 00:00:00 2001
+From: Roger Quadros <rogerq@ti.com>
+Date: Mon, 27 Jan 2014 16:41:18 +0200
+Subject: [PATCH] ata: ahci_platform: Manage SATA PHY
+
+Some platforms have a PHY hooked up to the
+SATA controller. The PHY needs to be initialized
+and powered up for SATA to work. We do that
+using the PHY framework.
+
+CC: Balaji T K <balajitk@ti.com>
+Signed-off-by: Roger Quadros <rogerq@ti.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci.h | 2 ++
+ drivers/ata/ahci_platform.c | 47 +++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 47 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index bf8100c..3ab7ac9 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -37,6 +37,7 @@
+
+ #include <linux/clk.h>
+ #include <linux/libata.h>
++#include <linux/phy/phy.h>
+ #include <linux/regulator/consumer.h>
+
+ /* Enclosure Management Control */
+@@ -325,6 +326,7 @@ struct ahci_host_priv {
+ u32 em_msg_type; /* EM message type */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
++ struct phy *phy; /* If platform uses phy */
+ void *plat_data; /* Other platform data */
+ /*
+ * Optional ahci_start_engine override, if not set this gets set to the
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index d7e55ba..99d38c1 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -23,6 +23,7 @@
+ #include <linux/platform_device.h>
+ #include <linux/libata.h>
+ #include <linux/ahci_platform.h>
++#include <linux/phy/phy.h>
+ #include "ahci.h"
+
+ static void ahci_host_stop(struct ata_host *host);
+@@ -147,6 +148,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
+ * the following order:
+ * 1) Regulator
+ * 2) Clocks (through ahci_platform_enable_clks)
++ * 3) Phy
+ *
+ * If resource enabling fails at any point the previous enabled
+ * resources are disabled in reverse order.
+@@ -171,8 +173,23 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
+ if (rc)
+ goto disable_regulator;
+
++ if (hpriv->phy) {
++ rc = phy_init(hpriv->phy);
++ if (rc)
++ goto disable_clks;
++
++ rc = phy_power_on(hpriv->phy);
++ if (rc) {
++ phy_exit(hpriv->phy);
++ goto disable_clks;
++ }
++ }
++
+ return 0;
+
++disable_clks:
++ ahci_platform_disable_clks(hpriv);
++
+ disable_regulator:
+ if (hpriv->target_pwr)
+ regulator_disable(hpriv->target_pwr);
+@@ -186,14 +203,20 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
+ *
+ * This function disables all ahci_platform managed resources in
+ * the following order:
+- * 1) Clocks (through ahci_platform_disable_clks)
+- * 2) Regulator
++ * 1) Phy
++ * 2) Clocks (through ahci_platform_disable_clks)
++ * 3) Regulator
+ *
+ * LOCKING:
+ * None.
+ */
+ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
+ {
++ if (hpriv->phy) {
++ phy_power_off(hpriv->phy);
++ phy_exit(hpriv->phy);
++ }
++
+ ahci_platform_disable_clks(hpriv);
+
+ if (hpriv->target_pwr)
+@@ -222,6 +245,7 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
+ * 2) regulator for controlling the targets power (optional)
+ * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
+ * or for non devicetree enabled platforms a single clock
++ * 4) phy (optional)
+ *
+ * LOCKING:
+ * None.
+@@ -283,6 +307,25 @@ struct ahci_host_priv *ahci_platform_get_resources(
+ hpriv->clks[i] = clk;
+ }
+
++ hpriv->phy = devm_phy_get(dev, "sata-phy");
++ if (IS_ERR(hpriv->phy)) {
++ rc = PTR_ERR(hpriv->phy);
++ switch (rc) {
++ case -ENODEV:
++ case -ENOSYS:
++ /* continue normally */
++ hpriv->phy = NULL;
++ break;
++
++ case -EPROBE_DEFER:
++ goto err_out;
++
++ default:
++ dev_err(dev, "couldn't get sata-phy\n");
++ goto err_out;
++ }
++ }
++
+ devres_remove_group(dev, NULL);
+ return hpriv;
+
+--
+2.0.3
+
+From 22d93de35a39507bcdf0c62c5e1fab0625f7c6f6 Mon Sep 17 00:00:00 2001
+From: Roger Quadros <rogerq@ti.com>
+Date: Wed, 9 Oct 2013 15:08:59 +0300
+Subject: [PATCH] ata: ahci_platform: runtime resume the device before use
+
+On OMAP platforms the device needs to be runtime resumed before
+it can be accessed. The OMAP HWMOD framework takes care of
+enabling the module and its resources based on the
+device's runtime PM state.
+
+In this patch we runtime resume during .probe() and runtime suspend
+after .remove().
+
+We also update the runtime PM state during .resume().
+
+CC: Balaji T K <balajitk@ti.com>
+Signed-off-by: Roger Quadros <rogerq@ti.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci.h | 1 +
+ drivers/ata/ahci_platform.c | 15 +++++++++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
+index 3ab7ac9..51af275b 100644
+--- a/drivers/ata/ahci.h
++++ b/drivers/ata/ahci.h
+@@ -324,6 +324,7 @@ struct ahci_host_priv {
+ u32 em_loc; /* enclosure management location */
+ u32 em_buf_sz; /* EM buffer size in byte */
+ u32 em_msg_type; /* EM message type */
++ bool got_runtime_pm; /* Did we do pm_runtime_get? */
+ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
+ struct regulator *target_pwr; /* Optional */
+ struct phy *phy; /* If platform uses phy */
+diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
+index 99d38c1..75698a4 100644
+--- a/drivers/ata/ahci_platform.c
++++ b/drivers/ata/ahci_platform.c
+@@ -24,6 +24,7 @@
+ #include <linux/libata.h>
+ #include <linux/ahci_platform.h>
+ #include <linux/phy/phy.h>
++#include <linux/pm_runtime.h>
+ #include "ahci.h"
+
+ static void ahci_host_stop(struct ata_host *host);
+@@ -229,6 +230,11 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
+ struct ahci_host_priv *hpriv = res;
+ int c;
+
++ if (hpriv->got_runtime_pm) {
++ pm_runtime_put_sync(dev);
++ pm_runtime_disable(dev);
++ }
++
+ for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
+ clk_put(hpriv->clks[c]);
+ }
+@@ -326,6 +332,10 @@ struct ahci_host_priv *ahci_platform_get_resources(
+ }
+ }
+
++ pm_runtime_enable(dev);
++ pm_runtime_get_sync(dev);
++ hpriv->got_runtime_pm = true;
++
+ devres_remove_group(dev, NULL);
+ return hpriv;
+
+@@ -635,6 +645,11 @@ int ahci_platform_resume(struct device *dev)
+ if (rc)
+ goto disable_resources;
+
++ /* We resumed so update PM runtime state */
++ pm_runtime_disable(dev);
++ pm_runtime_set_active(dev);
++ pm_runtime_enable(dev);
++
+ return 0;
+
+ disable_resources:
+--
+2.0.3
+
+From 22cccaf7a29b2a9d8a1440d089f399a6d2432b81 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 23 Feb 2014 11:37:17 +0100
+Subject: [PATCH] ahci_sunxi: Use msleep instead of mdelay
+
+ahci_sunxi_phy_init is called from the probe and resume code paths, and
+sleeping is safe in both, so use msleep instead of mdelay.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/ata/ahci_sunxi.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
+index 001f7dfc..d1bf3f7 100644
+--- a/drivers/ata/ahci_sunxi.c
++++ b/drivers/ata/ahci_sunxi.c
+@@ -90,7 +90,7 @@ static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+
+ /* This magic is from the original code */
+ writel(0, reg_base + AHCI_RWCR);
+- mdelay(5);
++ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS1R, BIT(19));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS0R,
+@@ -105,7 +105,7 @@ static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+ (0x7 << 20), (0x3 << 20));
+ sunxi_clrsetbits(reg_base + AHCI_PHYCS2R,
+ (0x1f << 5), (0x19 << 5));
+- mdelay(5);
++ msleep(5);
+
+ sunxi_setbits(reg_base + AHCI_PHYCS0R, (0x1 << 19));
+
+@@ -137,7 +137,7 @@ static int ahci_sunxi_phy_init(struct device *dev, void __iomem *reg_base)
+ udelay(1);
+ } while (1);
+
+- mdelay(15);
++ msleep(15);
+
+ writel(0x7, reg_base + AHCI_RWCR);
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/195-1-ohci-plat-changes.patch b/target/linux/sunxi/patches-3.14/195-1-ohci-plat-changes.patch
new file mode 100644
index 0000000000..2fb1928888
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/195-1-ohci-plat-changes.patch
@@ -0,0 +1,471 @@
+From 49ff47db168655cac5213cf5dd1844b08fb9823c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 5 Jan 2014 14:42:39 +0100
+Subject: [PATCH] ohci-platform: Add support for devicetree instantiation
+
+Add support for ohci-platform instantiation from devicetree, including
+optionally getting clks and a phy from devicetree, and enabling / disabling
+those on power_on / off.
+
+This should allow using ohci-platform from devicetree in various cases.
+Specifically after this commit it can be used for the ohci controller found
+on Allwinner sunxi SoCs.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+---
+ Documentation/devicetree/bindings/usb/usb-ohci.txt | 22 +++
+ drivers/usb/host/ohci-platform.c | 162 ++++++++++++++++++---
+ 2 files changed, 162 insertions(+), 22 deletions(-)
+ create mode 100644 Documentation/devicetree/bindings/usb/usb-ohci.txt
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+new file mode 100644
+index 0000000..6ba38d9
+--- /dev/null
++++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+@@ -0,0 +1,22 @@
++USB OHCI controllers
++
++Required properties:
++- compatible : "usb-ohci"
++- reg : ohci controller register range (address and length)
++- interrupts : ohci controller interrupt
++
++Optional properties:
++- clocks : a list of phandle + clock specifier pairs
++- phys : phandle + phy specifier pair
++- phy-names : "usb"
++
++Example:
++
++ ohci0: usb@01c14400 {
++ compatible = "allwinner,sun4i-a10-ohci", "usb-ohci";
++ reg = <0x01c14400 0x100>;
++ interrupts = <64>;
++ clocks = <&usb_clk 6>, <&ahb_gates 2>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ };
+diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
+index 68f674c..49304dd 100644
+--- a/drivers/usb/host/ohci-platform.c
++++ b/drivers/usb/host/ohci-platform.c
+@@ -3,6 +3,7 @@
+ *
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Derived from the OCHI-SSB driver
+ * Derived from the OHCI-PCI driver
+@@ -14,11 +15,14 @@
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
++#include <linux/clk.h>
++#include <linux/dma-mapping.h>
+ #include <linux/hrtimer.h>
+ #include <linux/io.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/err.h>
++#include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/usb/ohci_pdriver.h>
+ #include <linux/usb.h>
+@@ -27,6 +31,13 @@
+ #include "ohci.h"
+
+ #define DRIVER_DESC "OHCI generic platform driver"
++#define OHCI_MAX_CLKS 3
++#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
++
++struct ohci_platform_priv {
++ struct clk *clks[OHCI_MAX_CLKS];
++ struct phy *phy;
++};
+
+ static const char hcd_name[] = "ohci-platform";
+
+@@ -48,11 +59,67 @@ static int ohci_platform_reset(struct usb_hcd *hcd)
+ return ohci_setup(hcd);
+ }
+
++static int ohci_platform_power_on(struct platform_device *dev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
++ int clk, ret;
++
++ for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
++ ret = clk_prepare_enable(priv->clks[clk]);
++ if (ret)
++ goto err_disable_clks;
++ }
++
++ if (priv->phy) {
++ ret = phy_init(priv->phy);
++ if (ret)
++ goto err_disable_clks;
++
++ ret = phy_power_on(priv->phy);
++ if (ret)
++ goto err_exit_phy;
++ }
++
++ return 0;
++
++err_exit_phy:
++ phy_exit(priv->phy);
++err_disable_clks:
++ while (--clk >= 0)
++ clk_disable_unprepare(priv->clks[clk]);
++
++ return ret;
++}
++
++static void ohci_platform_power_off(struct platform_device *dev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
++ int clk;
++
++ if (priv->phy) {
++ phy_power_off(priv->phy);
++ phy_exit(priv->phy);
++ }
++
++ for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
++ if (priv->clks[clk])
++ clk_disable_unprepare(priv->clks[clk]);
++}
++
+ static struct hc_driver __read_mostly ohci_platform_hc_driver;
+
+ static const struct ohci_driver_overrides platform_overrides __initconst = {
+- .product_desc = "Generic Platform OHCI controller",
+- .reset = ohci_platform_reset,
++ .product_desc = "Generic Platform OHCI controller",
++ .reset = ohci_platform_reset,
++ .extra_priv_size = sizeof(struct ohci_platform_priv),
++};
++
++static struct usb_ohci_pdata ohci_platform_defaults = {
++ .power_on = ohci_platform_power_on,
++ .power_suspend = ohci_platform_power_off,
++ .power_off = ohci_platform_power_off,
+ };
+
+ static int ohci_platform_probe(struct platform_device *dev)
+@@ -60,17 +127,23 @@ static int ohci_platform_probe(struct platform_device *dev)
+ struct usb_hcd *hcd;
+ struct resource *res_mem;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+- int irq;
+- int err = -ENOMEM;
+-
+- if (!pdata) {
+- WARN_ON(1);
+- return -ENODEV;
+- }
++ struct ohci_platform_priv *priv;
++ int err, irq, clk = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
++ /*
++ * Use reasonable defaults so platforms don't have to provide these
++ * with DT probing on ARM.
++ */
++ if (!pdata)
++ pdata = &ohci_platform_defaults;
++
++ err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
++ if (err)
++ return err;
++
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no irq provided");
+@@ -83,17 +156,40 @@ static int ohci_platform_probe(struct platform_device *dev)
+ return -ENXIO;
+ }
+
++ hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
++ dev_name(&dev->dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ platform_set_drvdata(dev, hcd);
++ dev->dev.platform_data = pdata;
++ priv = hcd_to_ohci_priv(hcd);
++
++ if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
++ priv->phy = devm_phy_get(&dev->dev, "usb");
++ if (IS_ERR(priv->phy)) {
++ err = PTR_ERR(priv->phy);
++ if (err == -EPROBE_DEFER)
++ goto err_put_hcd;
++ priv->phy = NULL;
++ }
++
++ for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
++ priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
++ if (IS_ERR(priv->clks[clk])) {
++ err = PTR_ERR(priv->clks[clk]);
++ if (err == -EPROBE_DEFER)
++ goto err_put_clks;
++ priv->clks[clk] = NULL;
++ break;
++ }
++ }
++ }
++
+ if (pdata->power_on) {
+ err = pdata->power_on(dev);
+ if (err < 0)
+- return err;
+- }
+-
+- hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
+- dev_name(&dev->dev));
+- if (!hcd) {
+- err = -ENOMEM;
+- goto err_power;
++ goto err_put_clks;
+ }
+
+ hcd->rsrc_start = res_mem->start;
+@@ -102,11 +198,11 @@ static int ohci_platform_probe(struct platform_device *dev)
+ hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
+ if (IS_ERR(hcd->regs)) {
+ err = PTR_ERR(hcd->regs);
+- goto err_put_hcd;
++ goto err_power;
+ }
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (err)
+- goto err_put_hcd;
++ goto err_power;
+
+ device_wakeup_enable(hcd->self.controller);
+
+@@ -114,11 +210,17 @@ static int ohci_platform_probe(struct platform_device *dev)
+
+ return err;
+
+-err_put_hcd:
+- usb_put_hcd(hcd);
+ err_power:
+ if (pdata->power_off)
+ pdata->power_off(dev);
++err_put_clks:
++ while (--clk >= 0)
++ clk_put(priv->clks[clk]);
++err_put_hcd:
++ if (pdata == &ohci_platform_defaults)
++ dev->dev.platform_data = NULL;
++
++ usb_put_hcd(hcd);
+
+ return err;
+ }
+@@ -127,13 +229,22 @@ static int ohci_platform_remove(struct platform_device *dev)
+ {
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
++ struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
++ int clk;
+
+ usb_remove_hcd(hcd);
+- usb_put_hcd(hcd);
+
+ if (pdata->power_off)
+ pdata->power_off(dev);
+
++ for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
++ clk_put(priv->clks[clk]);
++
++ usb_put_hcd(hcd);
++
++ if (pdata == &ohci_platform_defaults)
++ dev->dev.platform_data = NULL;
++
+ return 0;
+ }
+
+@@ -180,6 +291,12 @@ static int ohci_platform_resume(struct device *dev)
+ #define ohci_platform_resume NULL
+ #endif /* CONFIG_PM */
+
++static const struct of_device_id ohci_platform_ids[] = {
++ { .compatible = "usb-ohci", },
++ { }
++};
++MODULE_DEVICE_TABLE(of, ohci_platform_ids);
++
+ static const struct platform_device_id ohci_platform_table[] = {
+ { "ohci-platform", 0 },
+ { }
+@@ -200,6 +317,7 @@ static struct platform_driver ohci_platform_driver = {
+ .owner = THIS_MODULE,
+ .name = "ohci-platform",
+ .pm = &ohci_platform_pm_ops,
++ .of_match_table = ohci_platform_ids,
+ }
+ };
+
+--
+2.0.3
+
+From 8c4b97ea8b66e0fc8bdf648675e6889ce48c5ea7 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 21 Jan 2014 16:05:47 +0100
+Subject: [PATCH] ohci-platform: Add support for controllers with big-endian
+ regs / descriptors
+
+Note this commit uses the same devicetree booleans for this as the ones
+already existing in the usb-ehci bindings, see:
+Documentation/devicetree/bindings/usb/usb-ehci.txt
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/devicetree/bindings/usb/usb-ohci.txt | 3 +++
+ drivers/usb/host/ohci-platform.c | 27 ++++++++++++++++++++++
+ 2 files changed, 30 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+index 6ba38d9..6933b0c 100644
+--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+@@ -6,6 +6,9 @@ Required properties:
+ - interrupts : ohci controller interrupt
+
+ Optional properties:
++- big-endian-regs : boolean, set this for hcds with big-endian registers
++- big-endian-desc : boolean, set this for hcds with big-endian descriptors
++- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
+ - clocks : a list of phandle + clock specifier pairs
+ - phys : phandle + phy specifier pair
+ - phy-names : "usb"
+diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
+index 49304dd..e2c28fd 100644
+--- a/drivers/usb/host/ohci-platform.c
++++ b/drivers/usb/host/ohci-platform.c
+@@ -128,6 +128,7 @@ static int ohci_platform_probe(struct platform_device *dev)
+ struct resource *res_mem;
+ struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ohci_platform_priv *priv;
++ struct ohci_hcd *ohci;
+ int err, irq, clk = 0;
+
+ if (usb_disabled())
+@@ -164,8 +165,34 @@ static int ohci_platform_probe(struct platform_device *dev)
+ platform_set_drvdata(dev, hcd);
+ dev->dev.platform_data = pdata;
+ priv = hcd_to_ohci_priv(hcd);
++ ohci = hcd_to_ohci(hcd);
+
+ if (pdata == &ohci_platform_defaults && dev->dev.of_node) {
++ if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
++ ohci->flags |= OHCI_QUIRK_BE_MMIO;
++
++ if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
++ ohci->flags |= OHCI_QUIRK_BE_DESC;
++
++ if (of_property_read_bool(dev->dev.of_node, "big-endian"))
++ ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
++
++#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
++ if (ohci->flags & OHCI_QUIRK_BE_MMIO) {
++ dev_err(&dev->dev,
++ "Error big-endian-regs not compiled in\n");
++ err = -EINVAL;
++ goto err_put_hcd;
++ }
++#endif
++#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
++ if (ohci->flags & OHCI_QUIRK_BE_DESC) {
++ dev_err(&dev->dev,
++ "Error big-endian-desc not compiled in\n");
++ err = -EINVAL;
++ goto err_put_hcd;
++ }
++#endif
+ priv->phy = devm_phy_get(&dev->dev, "usb");
+ if (IS_ERR(priv->phy)) {
+ err = PTR_ERR(priv->phy);
+--
+2.0.3
+
+From ddf77eb2ec72a3676dabe17baf6e3b32ce0542e5 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Feb 2014 11:27:29 +0100
+Subject: [PATCH] ohci-platform: Change compatible string from usb-ohci to
+ generic-ohci
+
+The initial versions of the devicetree enablement patches for ohci-platform
+used "ohci-platform" as compatible string. However this was disliked by various
+reviewers because the platform bus is a Linux invention and devicetree is
+supposed to be OS agnostic. After much discussion I gave up and went with
+the generic usb-ohci as requested.
+
+In retro-spect I should have chosen something different, the dts files for many
+existing boards already claim to be compatible with "usb-ohci", ie they have:
+
+ compatible = "ti,ohci-omap3", "usb-ohci";
+
+In theory this should not be a problem since the "ti,ohci-omap3" entry takes
+presedence, but in practice using a conflicting compatible string is an issue,
+because it makes which driver gets used depend on driver registration order.
+
+This patch changes the compatible string claimed by ohci-platform to
+"generic-ohci", avoiding the driver registration / module loading ordering
+problems.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/devicetree/bindings/usb/usb-ohci.txt | 4 ++--
+ drivers/usb/host/ohci-platform.c | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+index 6933b0c..45f67d9 100644
+--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
+@@ -1,7 +1,7 @@
+ USB OHCI controllers
+
+ Required properties:
+-- compatible : "usb-ohci"
++- compatible : "generic-ohci"
+ - reg : ohci controller register range (address and length)
+ - interrupts : ohci controller interrupt
+
+@@ -16,7 +16,7 @@ Optional properties:
+ Example:
+
+ ohci0: usb@01c14400 {
+- compatible = "allwinner,sun4i-a10-ohci", "usb-ohci";
++ compatible = "allwinner,sun4i-a10-ohci", "generic-ohci";
+ reg = <0x01c14400 0x100>;
+ interrupts = <64>;
+ clocks = <&usb_clk 6>, <&ahb_gates 2>;
+diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
+index e2c28fd..b6ca0b2 100644
+--- a/drivers/usb/host/ohci-platform.c
++++ b/drivers/usb/host/ohci-platform.c
+@@ -319,7 +319,7 @@ static int ohci_platform_resume(struct device *dev)
+ #endif /* CONFIG_PM */
+
+ static const struct of_device_id ohci_platform_ids[] = {
+- { .compatible = "usb-ohci", },
++ { .compatible = "generic-ohci", },
+ { }
+ };
+ MODULE_DEVICE_TABLE(of, ohci_platform_ids);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/195-2-ehci-plat-changes.patch b/target/linux/sunxi/patches-3.14/195-2-ehci-plat-changes.patch
new file mode 100644
index 0000000000..b8ee130c4a
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/195-2-ehci-plat-changes.patch
@@ -0,0 +1,552 @@
+From 738b350437abfca820dae226549ecf4fb100fa30 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 5 Jan 2014 00:04:02 +0100
+Subject: [PATCH] ehci-platform: Add support for clks and phy passed through
+ devicetree
+
+Currently ehci-platform is only used in combination with devicetree when used
+with some Via socs. By extending it to (optionally) get clks and a phy from
+devicetree, and enabling / disabling those on power_on / off, it can be used
+more generically. Specifically after this commit it can be used for the
+ehci controller on Allwinner sunxi SoCs.
+
+Since ehci-platform is intended to handle any generic enough non pci ehci
+device, add a "usb-ehci" compatibility string.
+
+There already is a usb-ehci device-tree bindings document, update this
+with clks and phy bindings info.
+
+Although actually quite generic so far the via,vt8500 compatibilty string
+had its own bindings document. Somehow we even ended up with 2 of them. Since
+these provide no extra information over the generic usb-ehci documentation,
+this patch removes them.
+
+The ehci-ppc-of.c driver also claims the usb-ehci compatibility string,
+even though it mostly is ibm,usb-ehci-440epx specific. ehci-platform.c is
+not needed on ppc platforms, so add a !PPC_OF dependency to it to avoid
+2 drivers claiming the same compatibility string getting build on ppc.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Alan Stern <stern@rowland.harvard.edu>
+---
+ Documentation/devicetree/bindings/usb/usb-ehci.txt | 25 +++-
+ .../devicetree/bindings/usb/via,vt8500-ehci.txt | 15 ---
+ .../devicetree/bindings/usb/vt8500-ehci.txt | 12 --
+ drivers/usb/host/Kconfig | 1 +
+ drivers/usb/host/ehci-platform.c | 147 +++++++++++++++++----
+ 5 files changed, 142 insertions(+), 58 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
+ delete mode 100644 Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
+index fa18612..2c1aeeb 100644
+--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
+@@ -7,13 +7,14 @@ Required properties:
+ (debug-port or other) can be also specified here, but only after
+ definition of standard EHCI registers.
+ - interrupts : one EHCI interrupt should be described here.
+-If device registers are implemented in big endian mode, the device
+-node should have "big-endian-regs" property.
+-If controller implementation operates with big endian descriptors,
+-"big-endian-desc" property should be specified.
+-If both big endian registers and descriptors are used by the controller
+-implementation, "big-endian" property can be specified instead of having
+-both "big-endian-regs" and "big-endian-desc".
++
++Optional properties:
++ - big-endian-regs : boolean, set this for hcds with big-endian registers
++ - big-endian-desc : boolean, set this for hcds with big-endian descriptors
++ - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
++ - clocks : a list of phandle + clock specifier pairs
++ - phys : phandle + phy specifier pair
++ - phy-names : "usb"
+
+ Example (Sequoia 440EPx):
+ ehci@e0000300 {
+@@ -23,3 +24,13 @@ Example (Sequoia 440EPx):
+ reg = <0 e0000300 90 0 e0000390 70>;
+ big-endian;
+ };
++
++Example (Allwinner sun4i A10 SoC):
++ ehci0: usb@01c14000 {
++ compatible = "allwinner,sun4i-a10-ehci", "usb-ehci";
++ reg = <0x01c14000 0x100>;
++ interrupts = <39>;
++ clocks = <&ahb_gates 1>;
++ phys = <&usbphy 1>;
++ phy-names = "usb";
++ };
+diff --git a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
+deleted file mode 100644
+index 17b3ad1..0000000
+--- a/Documentation/devicetree/bindings/usb/via,vt8500-ehci.txt
++++ /dev/null
+@@ -1,15 +0,0 @@
+-VIA/Wondermedia VT8500 EHCI Controller
+------------------------------------------------------
+-
+-Required properties:
+-- compatible : "via,vt8500-ehci"
+-- reg : Should contain 1 register ranges(address and length)
+-- interrupts : ehci controller interrupt
+-
+-Example:
+-
+- ehci@d8007900 {
+- compatible = "via,vt8500-ehci";
+- reg = <0xd8007900 0x200>;
+- interrupts = <43>;
+- };
+diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
+deleted file mode 100644
+index 5fb8fd6..0000000
+--- a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
++++ /dev/null
+@@ -1,12 +0,0 @@
+-VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
+-
+-Required properties:
+- - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
+- - reg: Address range of the ehci registers. size should be 0x200
+- - interrupts: Should contain the ehci interrupt.
+-
+-usb: ehci@D8007100 {
+- compatible = "wm,prizm-ehci", "usb-ehci";
+- reg = <0xD8007100 0x200>;
+- interrupts = <1>;
+-};
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index a9707da..e28cbe0 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -255,6 +255,7 @@ config USB_EHCI_ATH79
+
+ config USB_EHCI_HCD_PLATFORM
+ tristate "Generic EHCI driver for a platform device"
++ depends on !PPC_OF
+ default n
+ ---help---
+ Adds an EHCI host driver for a generic platform device, which
+diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
+index 01536cf..5ebd0b7 100644
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -3,6 +3,7 @@
+ *
+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
+ * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Derived from the ohci-ssb driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+@@ -18,6 +19,7 @@
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
++#include <linux/clk.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/err.h>
+ #include <linux/kernel.h>
+@@ -25,6 +27,7 @@
+ #include <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/of.h>
++#include <linux/phy/phy.h>
+ #include <linux/platform_device.h>
+ #include <linux/usb.h>
+ #include <linux/usb/hcd.h>
+@@ -33,6 +36,13 @@
+ #include "ehci.h"
+
+ #define DRIVER_DESC "EHCI generic platform driver"
++#define EHCI_MAX_CLKS 3
++#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv)
++
++struct ehci_platform_priv {
++ struct clk *clks[EHCI_MAX_CLKS];
++ struct phy *phy;
++};
+
+ static const char hcd_name[] = "ehci-platform";
+
+@@ -64,38 +74,90 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
+ return 0;
+ }
+
++static int ehci_platform_power_on(struct platform_device *dev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
++ int clk, ret;
++
++ for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
++ ret = clk_prepare_enable(priv->clks[clk]);
++ if (ret)
++ goto err_disable_clks;
++ }
++
++ if (priv->phy) {
++ ret = phy_init(priv->phy);
++ if (ret)
++ goto err_disable_clks;
++
++ ret = phy_power_on(priv->phy);
++ if (ret)
++ goto err_exit_phy;
++ }
++
++ return 0;
++
++err_exit_phy:
++ phy_exit(priv->phy);
++err_disable_clks:
++ while (--clk >= 0)
++ clk_disable_unprepare(priv->clks[clk]);
++
++ return ret;
++}
++
++static void ehci_platform_power_off(struct platform_device *dev)
++{
++ struct usb_hcd *hcd = platform_get_drvdata(dev);
++ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
++ int clk;
++
++ if (priv->phy) {
++ phy_power_off(priv->phy);
++ phy_exit(priv->phy);
++ }
++
++ for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
++ if (priv->clks[clk])
++ clk_disable_unprepare(priv->clks[clk]);
++}
++
+ static struct hc_driver __read_mostly ehci_platform_hc_driver;
+
+ static const struct ehci_driver_overrides platform_overrides __initconst = {
+- .reset = ehci_platform_reset,
++ .reset = ehci_platform_reset,
++ .extra_priv_size = sizeof(struct ehci_platform_priv),
+ };
+
+-static struct usb_ehci_pdata ehci_platform_defaults;
++static struct usb_ehci_pdata ehci_platform_defaults = {
++ .power_on = ehci_platform_power_on,
++ .power_suspend = ehci_platform_power_off,
++ .power_off = ehci_platform_power_off,
++};
+
+ static int ehci_platform_probe(struct platform_device *dev)
+ {
+ struct usb_hcd *hcd;
+ struct resource *res_mem;
+- struct usb_ehci_pdata *pdata;
+- int irq;
+- int err;
++ struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
++ struct ehci_platform_priv *priv;
++ int err, irq, clk = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ /*
+- * use reasonable defaults so platforms don't have to provide these.
+- * with DT probing on ARM, none of these are set.
++ * Use reasonable defaults so platforms don't have to provide these
++ * with DT probing on ARM.
+ */
+- if (!dev_get_platdata(&dev->dev))
+- dev->dev.platform_data = &ehci_platform_defaults;
++ if (!pdata)
++ pdata = &ehci_platform_defaults;
+
+ err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
+ if (err)
+ return err;
+
+- pdata = dev_get_platdata(&dev->dev);
+-
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no irq provided");
+@@ -107,17 +169,40 @@ static int ehci_platform_probe(struct platform_device *dev)
+ return -ENXIO;
+ }
+
++ hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
++ dev_name(&dev->dev));
++ if (!hcd)
++ return -ENOMEM;
++
++ platform_set_drvdata(dev, hcd);
++ dev->dev.platform_data = pdata;
++ priv = hcd_to_ehci_priv(hcd);
++
++ if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
++ priv->phy = devm_phy_get(&dev->dev, "usb");
++ if (IS_ERR(priv->phy)) {
++ err = PTR_ERR(priv->phy);
++ if (err == -EPROBE_DEFER)
++ goto err_put_hcd;
++ priv->phy = NULL;
++ }
++
++ for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
++ priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
++ if (IS_ERR(priv->clks[clk])) {
++ err = PTR_ERR(priv->clks[clk]);
++ if (err == -EPROBE_DEFER)
++ goto err_put_clks;
++ priv->clks[clk] = NULL;
++ break;
++ }
++ }
++ }
++
+ if (pdata->power_on) {
+ err = pdata->power_on(dev);
+ if (err < 0)
+- return err;
+- }
+-
+- hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
+- dev_name(&dev->dev));
+- if (!hcd) {
+- err = -ENOMEM;
+- goto err_power;
++ goto err_put_clks;
+ }
+
+ hcd->rsrc_start = res_mem->start;
+@@ -126,22 +211,28 @@ static int ehci_platform_probe(struct platform_device *dev)
+ hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
+ if (IS_ERR(hcd->regs)) {
+ err = PTR_ERR(hcd->regs);
+- goto err_put_hcd;
++ goto err_power;
+ }
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (err)
+- goto err_put_hcd;
++ goto err_power;
+
+ device_wakeup_enable(hcd->self.controller);
+ platform_set_drvdata(dev, hcd);
+
+ return err;
+
+-err_put_hcd:
+- usb_put_hcd(hcd);
+ err_power:
+ if (pdata->power_off)
+ pdata->power_off(dev);
++err_put_clks:
++ while (--clk >= 0)
++ clk_put(priv->clks[clk]);
++err_put_hcd:
++ if (pdata == &ehci_platform_defaults)
++ dev->dev.platform_data = NULL;
++
++ usb_put_hcd(hcd);
+
+ return err;
+ }
+@@ -150,13 +241,19 @@ static int ehci_platform_remove(struct platform_device *dev)
+ {
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
++ struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
++ int clk;
+
+ usb_remove_hcd(hcd);
+- usb_put_hcd(hcd);
+
+ if (pdata->power_off)
+ pdata->power_off(dev);
+
++ for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
++ clk_put(priv->clks[clk]);
++
++ usb_put_hcd(hcd);
++
+ if (pdata == &ehci_platform_defaults)
+ dev->dev.platform_data = NULL;
+
+@@ -207,8 +304,10 @@ static int ehci_platform_resume(struct device *dev)
+ static const struct of_device_id vt8500_ehci_ids[] = {
+ { .compatible = "via,vt8500-ehci", },
+ { .compatible = "wm,prizm-ehci", },
++ { .compatible = "usb-ehci", },
+ {}
+ };
++MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
+
+ static const struct platform_device_id ehci_platform_table[] = {
+ { "ehci-platform", 0 },
+--
+2.0.3
+
+From 91fc5f6e5e90d412a6778efbe05e5306a1df5032 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 21 Jan 2014 16:20:53 +0100
+Subject: [PATCH] ehci-platform: Add support for controllers with big-endian
+ regs / descriptors
+
+This uses the already documented devicetree booleans for this, see:
+Documentation/devicetree/bindings/usb/usb-ehci.txt
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/usb/host/ehci-platform.c | 33 +++++++++++++++++++++++++++++++--
+ 1 file changed, 31 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
+index 5ebd0b7..8fde649 100644
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -55,8 +55,10 @@ static int ehci_platform_reset(struct usb_hcd *hcd)
+
+ hcd->has_tt = pdata->has_tt;
+ ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
+- ehci->big_endian_desc = pdata->big_endian_desc;
+- ehci->big_endian_mmio = pdata->big_endian_mmio;
++ if (pdata->big_endian_desc)
++ ehci->big_endian_desc = 1;
++ if (pdata->big_endian_mmio)
++ ehci->big_endian_mmio = 1;
+ ehci->ignore_oc = pdata->ignore_oc;
+
+ if (pdata->pre_setup) {
+@@ -142,6 +144,7 @@ static int ehci_platform_probe(struct platform_device *dev)
+ struct resource *res_mem;
+ struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
+ struct ehci_platform_priv *priv;
++ struct ehci_hcd *ehci;
+ int err, irq, clk = 0;
+
+ if (usb_disabled())
+@@ -177,8 +180,34 @@ static int ehci_platform_probe(struct platform_device *dev)
+ platform_set_drvdata(dev, hcd);
+ dev->dev.platform_data = pdata;
+ priv = hcd_to_ehci_priv(hcd);
++ ehci = hcd_to_ehci(hcd);
+
+ if (pdata == &ehci_platform_defaults && dev->dev.of_node) {
++ if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
++ ehci->big_endian_mmio = 1;
++
++ if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
++ ehci->big_endian_desc = 1;
++
++ if (of_property_read_bool(dev->dev.of_node, "big-endian"))
++ ehci->big_endian_mmio = ehci->big_endian_desc = 1;
++
++#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
++ if (ehci->big_endian_mmio) {
++ dev_err(&dev->dev,
++ "Error big-endian-regs not compiled in\n");
++ err = -EINVAL;
++ goto err_put_hcd;
++ }
++#endif
++#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
++ if (ehci->big_endian_desc) {
++ dev_err(&dev->dev,
++ "Error big-endian-desc not compiled in\n");
++ err = -EINVAL;
++ goto err_put_hcd;
++ }
++#endif
+ priv->phy = devm_phy_get(&dev->dev, "usb");
+ if (IS_ERR(priv->phy)) {
+ err = PTR_ERR(priv->phy);
+--
+2.0.3
+
+From 4a1ce69fa8c4595483493cd7df21c66dbcca1307 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Feb 2014 11:46:13 +0100
+Subject: [PATCH] ehci-platform: Change compatible string from usb-ehci to
+ generic-ehci
+
+The initial versions of the devicetree enablement patches for ehci-platform
+used "ehci-platform" as compatible string. However this was disliked by various
+reviewers because the platform bus is a Linux invention and devicetree is
+supposed to be OS agnostic. After much discussion I gave up, added a:
+"depends on !PPC_OF" to Kconfig to avoid a known conflict with PPC-OF platforms
+and went with the generic usb-ehci as requested.
+
+In retro-spect I should have chosen something different, the dts files for many
+existing boards already claim to be compatible with "usb-ehci", ie they have:
+
+ compatible = "ti,ehci-omap", "usb-ehci";
+
+In theory this should not be a problem since the "ti,ehci-omap" entry takes
+presedence, but in practice using a conflicting compatible string is an issue,
+because it makes which driver gets used depend on driver registration order.
+
+This patch changes the compatible string claimed by ehci-platform to
+"generic-ehci", avoiding the driver registration / module loading ordering
+problems, and removes the "depends on !PPC_OF" workaround.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/devicetree/bindings/usb/usb-ehci.txt | 4 ++--
+ drivers/usb/host/Kconfig | 1 -
+ drivers/usb/host/ehci-platform.c | 2 +-
+ 3 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt
+index 2c1aeeb..ff151ec 100644
+--- a/Documentation/devicetree/bindings/usb/usb-ehci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-ehci.txt
+@@ -1,7 +1,7 @@
+ USB EHCI controllers
+
+ Required properties:
+- - compatible : should be "usb-ehci".
++ - compatible : should be "generic-ehci".
+ - reg : should contain at least address and length of the standard EHCI
+ register set for the device. Optional platform-dependent registers
+ (debug-port or other) can be also specified here, but only after
+@@ -27,7 +27,7 @@ Example (Sequoia 440EPx):
+
+ Example (Allwinner sun4i A10 SoC):
+ ehci0: usb@01c14000 {
+- compatible = "allwinner,sun4i-a10-ehci", "usb-ehci";
++ compatible = "allwinner,sun4i-a10-ehci", "generic-ehci";
+ reg = <0x01c14000 0x100>;
+ interrupts = <39>;
+ clocks = <&ahb_gates 1>;
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index e28cbe0..a9707da 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -255,7 +255,6 @@ config USB_EHCI_ATH79
+
+ config USB_EHCI_HCD_PLATFORM
+ tristate "Generic EHCI driver for a platform device"
+- depends on !PPC_OF
+ default n
+ ---help---
+ Adds an EHCI host driver for a generic platform device, which
+diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
+index 8fde649..1178730 100644
+--- a/drivers/usb/host/ehci-platform.c
++++ b/drivers/usb/host/ehci-platform.c
+@@ -333,7 +333,7 @@ static int ehci_platform_resume(struct device *dev)
+ static const struct of_device_id vt8500_ehci_ids[] = {
+ { .compatible = "via,vt8500-ehci", },
+ { .compatible = "wm,prizm-ehci", },
+- { .compatible = "usb-ehci", },
++ { .compatible = "generic-ehci", },
+ {}
+ };
+ MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/195-3-uhci-plat-changes.patch b/target/linux/sunxi/patches-3.14/195-3-uhci-plat-changes.patch
new file mode 100644
index 0000000000..d9ce1fc119
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/195-3-uhci-plat-changes.patch
@@ -0,0 +1,83 @@
+From 2adf0917bc9d6db8d957d56c8289a623be4027b6 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Feb 2014 17:41:48 +0100
+Subject: [PATCH] uhci-platform: Change compatible string from platform-uhci to
+ generic-uhci
+
+This brings the uhci-platform bindings in sync with what we've done for
+the ohci- and ehci-platform drivers. As discussed there using platform as a
+prefix is a bit weird as the platform bus is a Linux specific thing and
+the bindings are supposed to be OS agnostic.
+
+Note that the old platform-uhci compatible string is kept around for, well,
+compatibility reasons.
+
+While at it rename the bindings txt file to match the name of all the
+other ?hci-platform bindings docs.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/devicetree/bindings/usb/platform-uhci.txt | 15 ---------------
+ Documentation/devicetree/bindings/usb/usb-uhci.txt | 15 +++++++++++++++
+ drivers/usb/host/uhci-platform.c | 1 +
+ 3 files changed, 16 insertions(+), 15 deletions(-)
+ delete mode 100644 Documentation/devicetree/bindings/usb/platform-uhci.txt
+ create mode 100644 Documentation/devicetree/bindings/usb/usb-uhci.txt
+
+diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt
+deleted file mode 100644
+index a4fb071..0000000
+--- a/Documentation/devicetree/bindings/usb/platform-uhci.txt
++++ /dev/null
+@@ -1,15 +0,0 @@
+-Generic Platform UHCI Controller
+------------------------------------------------------
+-
+-Required properties:
+-- compatible : "platform-uhci"
+-- reg : Should contain 1 register ranges(address and length)
+-- interrupts : UHCI controller interrupt
+-
+-Example:
+-
+- uhci@d8007b00 {
+- compatible = "platform-uhci";
+- reg = <0xd8007b00 0x200>;
+- interrupts = <43>;
+- };
+diff --git a/Documentation/devicetree/bindings/usb/usb-uhci.txt b/Documentation/devicetree/bindings/usb/usb-uhci.txt
+new file mode 100644
+index 0000000..2981334
+--- /dev/null
++++ b/Documentation/devicetree/bindings/usb/usb-uhci.txt
+@@ -0,0 +1,15 @@
++Generic Platform UHCI Controller
++-----------------------------------------------------
++
++Required properties:
++- compatible : "generic-uhci" (deprecated: "platform-uhci")
++- reg : Should contain 1 register ranges(address and length)
++- interrupts : UHCI controller interrupt
++
++Example:
++
++ uhci@d8007b00 {
++ compatible = "generic-uhci";
++ reg = <0xd8007b00 0x200>;
++ interrupts = <43>;
++ };
+diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
+index 44e6c9d..01833ab 100644
+--- a/drivers/usb/host/uhci-platform.c
++++ b/drivers/usb/host/uhci-platform.c
+@@ -148,6 +148,7 @@ static void uhci_hcd_platform_shutdown(struct platform_device *op)
+ }
+
+ static const struct of_device_id platform_uhci_ids[] = {
++ { .compatible = "generic-uhci", },
+ { .compatible = "platform-uhci", },
+ {}
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/195-4-xhci-plat-changes.patch b/target/linux/sunxi/patches-3.14/195-4-xhci-plat-changes.patch
new file mode 100644
index 0000000000..81dc4d4642
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/195-4-xhci-plat-changes.patch
@@ -0,0 +1,56 @@
+From 8fd033e1b6cdd30c32762ef1c5e2216226dd61e1 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Feb 2014 17:50:51 +0100
+Subject: [PATCH] xhci-platform: Change compatible string from xhci-platform to
+ generic-xhci
+
+This brings the xhci-platform bindings in sync with what we've done for
+the ohci- and ehci-platform drivers. As discussed there using platform as a
+postfix is a bit weird as the platform bus is a Linux specific thing and
+the bindings are supposed to be OS agnostic.
+
+Note that the old xhci-platform compatible string is kept around for, well,
+compatibility reasons.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ Documentation/devicetree/bindings/usb/usb-xhci.txt | 4 ++--
+ drivers/usb/host/xhci-plat.c | 1 +
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt
+index 5752df0..90f8f60 100644
+--- a/Documentation/devicetree/bindings/usb/usb-xhci.txt
++++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt
+@@ -1,14 +1,14 @@
+ USB xHCI controllers
+
+ Required properties:
+- - compatible: should be "xhci-platform".
++ - compatible: should be "generic-xhci" (deprecated: "xhci-platform").
+ - reg: should contain address and length of the standard XHCI
+ register set for the device.
+ - interrupts: one XHCI interrupt should be described here.
+
+ Example:
+ usb@f0931000 {
+- compatible = "xhci-platform";
++ compatible = "generic-xhci";
+ reg = <0xf0931000 0x8c8>;
+ interrupts = <0x0 0x4e 0x0>;
+ };
+diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
+index 8abda5c..8affef9 100644
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -226,6 +226,7 @@ static const struct dev_pm_ops xhci_plat_pm_ops = {
+
+ #ifdef CONFIG_OF
+ static const struct of_device_id usb_xhci_of_match[] = {
++ { .compatible = "generic-xhci" },
+ { .compatible = "xhci-platform" },
+ { },
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/196-usb-add-sunxi-phy-driver.patch b/target/linux/sunxi/patches-3.14/196-usb-add-sunxi-phy-driver.patch
new file mode 100644
index 0000000000..eee697709a
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/196-usb-add-sunxi-phy-driver.patch
@@ -0,0 +1,423 @@
+From 56feaa546c5ce4152fe14f725e9fc6b85f8a565b Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 4 Jan 2014 23:56:17 +0100
+Subject: [PATCH] PHY: sunxi: Add driver for sunxi usb phy
+
+The Allwinner A1x / A2x SoCs have 2 or 3 usb phys which are all accessed
+through a single set of registers. Besides this there are also some other
+phy related bits which need poking, which are per phy, but shared between the
+ohci and ehci controllers, so these are also controlled from this new phy
+driver.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ .../devicetree/bindings/phy/sun4i-usb-phy.txt | 26 ++
+ drivers/phy/Kconfig | 11 +
+ drivers/phy/Makefile | 1 +
+ drivers/phy/phy-sun4i-usb.c | 331 +++++++++++++++++++++
+ 4 files changed, 369 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+ create mode 100644 drivers/phy/phy-sun4i-usb.c
+
+diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+new file mode 100644
+index 0000000..a82361b
+--- /dev/null
++++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
+@@ -0,0 +1,26 @@
++Allwinner sun4i USB PHY
++-----------------------
++
++Required properties:
++- compatible : should be one of "allwinner,sun4i-a10-usb-phy",
++ "allwinner,sun5i-a13-usb-phy" or "allwinner,sun7i-a20-usb-phy"
++- reg : a list of offset + length pairs
++- reg-names : "phy_ctrl", "pmu1" and for sun4i or sun7i "pmu2"
++- #phy-cells : from the generic phy bindings, must be 1
++- clocks : phandle + clock specifier for the phy clock
++- clock-names : "usb_phy"
++- resets : a list of phandle + reset specifier pairs
++- reset-names : "usb0_reset", "usb1_reset" and for sun4i or sun7i "usb2_reset"
++
++Example:
++ usbphy: phy@0x01c13400 {
++ #phy-cells = <1>;
++ compatible = "allwinner,sun4i-a10-usb-phy";
++ /* phy base regs, phy1 pmu reg, phy2 pmu reg */
++ reg = <0x01c13400 0x10 0x01c14800 0x4 0x01c1c800 0x4>;
++ reg-names = "phy_ctrl", "pmu1", "pmu2";
++ clocks = <&usb_clk 8>;
++ clock-names = "usb_phy";
++ resets = <&usb_clk 1>, <&usb_clk 2>;
++ reset-names = "usb1_reset", "usb2_reset";
++ };
+diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
+index c7a551c..66f7c4e 100644
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -65,4 +65,15 @@ config BCM_KONA_USB2_PHY
+ help
+ Enable this to support the Broadcom Kona USB 2.0 PHY.
+
++config PHY_SUN4I_USB
++ tristate "Allwinner sunxi SoC USB PHY driver"
++ depends on ARCH_SUNXI && HAS_IOMEM && OF
++ select GENERIC_PHY
++ help
++ Enable this to support the transceiver that is part of Allwinner
++ sunxi SoCs.
++
++ This driver controls the entire USB PHY block, both the USB OTG
++ parts, as well as the 2 regular USB 2 host PHYs.
++
+ endmenu
+diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
+index b57c253..9d4f8bb 100644
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -9,3 +9,4 @@ obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
+ obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
+ obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o
+ obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o
++obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o
+diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c
+new file mode 100644
+index 0000000..e6e6c4b
+--- /dev/null
++++ b/drivers/phy/phy-sun4i-usb.c
+@@ -0,0 +1,331 @@
++/*
++ * Allwinner sun4i USB phy driver
++ *
++ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * Based on code from
++ * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
++ *
++ * Modelled after: Samsung S5P/EXYNOS SoC series MIPI CSIS/DSIM DPHY driver
++ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
++ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/phy/phy.h>
++#include <linux/platform_device.h>
++#include <linux/regulator/consumer.h>
++#include <linux/reset.h>
++
++#define REG_ISCR 0x00
++#define REG_PHYCTL 0x04
++#define REG_PHYBIST 0x08
++#define REG_PHYTUNE 0x0c
++
++#define PHYCTL_DATA BIT(7)
++
++#define SUNXI_AHB_ICHR8_EN BIT(10)
++#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
++#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
++#define SUNXI_ULPI_BYPASS_EN BIT(0)
++
++/* Common Control Bits for Both PHYs */
++#define PHY_PLL_BW 0x03
++#define PHY_RES45_CAL_EN 0x0c
++
++/* Private Control Bits for Each PHY */
++#define PHY_TX_AMPLITUDE_TUNE 0x20
++#define PHY_TX_SLEWRATE_TUNE 0x22
++#define PHY_VBUSVALID_TH_SEL 0x25
++#define PHY_PULLUP_RES_SEL 0x27
++#define PHY_OTG_FUNC_EN 0x28
++#define PHY_VBUS_DET_EN 0x29
++#define PHY_DISCON_TH_SEL 0x2a
++
++#define MAX_PHYS 3
++
++struct sun4i_usb_phy_data {
++ struct clk *clk;
++ void __iomem *base;
++ struct mutex mutex;
++ int num_phys;
++ u32 disc_thresh;
++ struct sun4i_usb_phy {
++ struct phy *phy;
++ void __iomem *pmu;
++ struct regulator *vbus;
++ struct reset_control *reset;
++ int index;
++ } phys[MAX_PHYS];
++};
++
++#define to_sun4i_usb_phy_data(phy) \
++ container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
++
++static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
++ int len)
++{
++ struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
++ u32 temp, usbc_bit = BIT(phy->index * 2);
++ int i;
++
++ mutex_lock(&phy_data->mutex);
++
++ for (i = 0; i < len; i++) {
++ temp = readl(phy_data->base + REG_PHYCTL);
++
++ /* clear the address portion */
++ temp &= ~(0xff << 8);
++
++ /* set the address */
++ temp |= ((addr + i) << 8);
++ writel(temp, phy_data->base + REG_PHYCTL);
++
++ /* set the data bit and clear usbc bit*/
++ temp = readb(phy_data->base + REG_PHYCTL);
++ if (data & 0x1)
++ temp |= PHYCTL_DATA;
++ else
++ temp &= ~PHYCTL_DATA;
++ temp &= ~usbc_bit;
++ writeb(temp, phy_data->base + REG_PHYCTL);
++
++ /* pulse usbc_bit */
++ temp = readb(phy_data->base + REG_PHYCTL);
++ temp |= usbc_bit;
++ writeb(temp, phy_data->base + REG_PHYCTL);
++
++ temp = readb(phy_data->base + REG_PHYCTL);
++ temp &= ~usbc_bit;
++ writeb(temp, phy_data->base + REG_PHYCTL);
++
++ data >>= 1;
++ }
++ mutex_unlock(&phy_data->mutex);
++}
++
++static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)
++{
++ u32 bits, reg_value;
++
++ if (!phy->pmu)
++ return;
++
++ bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |
++ SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN;
++
++ reg_value = readl(phy->pmu);
++
++ if (enable)
++ reg_value |= bits;
++ else
++ reg_value &= ~bits;
++
++ writel(reg_value, phy->pmu);
++}
++
++static int sun4i_usb_phy_init(struct phy *_phy)
++{
++ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
++ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
++ int ret;
++
++ ret = clk_prepare_enable(data->clk);
++ if (ret)
++ return ret;
++
++ ret = reset_control_deassert(phy->reset);
++ if (ret) {
++ clk_disable_unprepare(data->clk);
++ return ret;
++ }
++
++ /* Adjust PHY's magnitude and rate */
++ sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
++
++ /* Disconnect threshold adjustment */
++ sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, data->disc_thresh, 2);
++
++ sun4i_usb_phy_passby(phy, 1);
++
++ return 0;
++}
++
++static int sun4i_usb_phy_exit(struct phy *_phy)
++{
++ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
++ struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
++
++ sun4i_usb_phy_passby(phy, 0);
++ reset_control_assert(phy->reset);
++ clk_disable_unprepare(data->clk);
++
++ return 0;
++}
++
++static int sun4i_usb_phy_power_on(struct phy *_phy)
++{
++ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
++ int ret = 0;
++
++ if (phy->vbus)
++ ret = regulator_enable(phy->vbus);
++
++ return ret;
++}
++
++static int sun4i_usb_phy_power_off(struct phy *_phy)
++{
++ struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
++
++ if (phy->vbus)
++ regulator_disable(phy->vbus);
++
++ return 0;
++}
++
++static struct phy_ops sun4i_usb_phy_ops = {
++ .init = sun4i_usb_phy_init,
++ .exit = sun4i_usb_phy_exit,
++ .power_on = sun4i_usb_phy_power_on,
++ .power_off = sun4i_usb_phy_power_off,
++ .owner = THIS_MODULE,
++};
++
++static struct phy *sun4i_usb_phy_xlate(struct device *dev,
++ struct of_phandle_args *args)
++{
++ struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
++
++ if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
++ return ERR_PTR(-ENODEV);
++
++ return data->phys[args->args[0]].phy;
++}
++
++static int sun4i_usb_phy_probe(struct platform_device *pdev)
++{
++ struct sun4i_usb_phy_data *data;
++ struct device *dev = &pdev->dev;
++ struct device_node *np = dev->of_node;
++ void __iomem *pmu = NULL;
++ struct phy_provider *phy_provider;
++ struct reset_control *reset;
++ struct regulator *vbus;
++ struct resource *res;
++ struct phy *phy;
++ char name[16];
++ int i;
++
++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ mutex_init(&data->mutex);
++
++ if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy"))
++ data->num_phys = 2;
++ else
++ data->num_phys = 3;
++
++ if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy"))
++ data->disc_thresh = 3;
++ else
++ data->disc_thresh = 2;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
++ data->base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(data->base))
++ return PTR_ERR(data->base);
++
++ data->clk = devm_clk_get(dev, "usb_phy");
++ if (IS_ERR(data->clk)) {
++ dev_err(dev, "could not get usb_phy clock\n");
++ return PTR_ERR(data->clk);
++ }
++
++ /* Skip 0, 0 is the phy for otg which is not yet supported. */
++ for (i = 1; i < data->num_phys; i++) {
++ snprintf(name, sizeof(name), "usb%d_vbus", i);
++ vbus = devm_regulator_get_optional(dev, name);
++ if (IS_ERR(vbus)) {
++ if (PTR_ERR(vbus) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++ vbus = NULL;
++ }
++
++ snprintf(name, sizeof(name), "usb%d_reset", i);
++ reset = devm_reset_control_get(dev, name);
++ if (IS_ERR(reset)) {
++ dev_err(dev, "failed to get reset %s\n", name);
++ return PTR_ERR(reset);
++ }
++
++ if (i) { /* No pmu for usbc0 */
++ snprintf(name, sizeof(name), "pmu%d", i);
++ res = platform_get_resource_byname(pdev,
++ IORESOURCE_MEM, name);
++ pmu = devm_ioremap_resource(dev, res);
++ if (IS_ERR(pmu))
++ return PTR_ERR(pmu);
++ }
++
++ phy = devm_phy_create(dev, &sun4i_usb_phy_ops, NULL);
++ if (IS_ERR(phy)) {
++ dev_err(dev, "failed to create PHY %d\n", i);
++ return PTR_ERR(phy);
++ }
++
++ data->phys[i].phy = phy;
++ data->phys[i].pmu = pmu;
++ data->phys[i].vbus = vbus;
++ data->phys[i].reset = reset;
++ data->phys[i].index = i;
++ phy_set_drvdata(phy, &data->phys[i]);
++ }
++
++ dev_set_drvdata(dev, data);
++ phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
++ if (IS_ERR(phy_provider))
++ return PTR_ERR(phy_provider);
++
++ return 0;
++}
++
++static const struct of_device_id sun4i_usb_phy_of_match[] = {
++ { .compatible = "allwinner,sun4i-a10-usb-phy" },
++ { .compatible = "allwinner,sun5i-a13-usb-phy" },
++ { .compatible = "allwinner,sun7i-a20-usb-phy" },
++ { },
++};
++MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
++
++static struct platform_driver sun4i_usb_phy_driver = {
++ .probe = sun4i_usb_phy_probe,
++ .driver = {
++ .of_match_table = sun4i_usb_phy_of_match,
++ .name = "sun4i-usb-phy",
++ .owner = THIS_MODULE,
++ }
++};
++module_platform_driver(sun4i_usb_phy_driver);
++
++MODULE_DESCRIPTION("Allwinner sun4i USB phy driver");
++MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
++MODULE_LICENSE("GPL v2");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/200-mmc-add-driver.patch b/target/linux/sunxi/patches-3.14/200-mmc-add-driver.patch
new file mode 100644
index 0000000000..985b8b7947
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/200-mmc-add-driver.patch
@@ -0,0 +1,1163 @@
+From a2fb45195f1b90058e96e09892c071ef4207b593 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= <david.lanzendoerfer@o2s.ch>
+Date: Sat, 22 Feb 2014 09:13:55 +0100
+Subject: [PATCH] ARM: sunxi: Add driver for SD/MMC hosts found on Allwinner
+ sunxi SoCs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is based on the driver Allwinner ships in their Android kernel sources.
+
+Initial porting to upstream kernels done by David Lanzendörfer, additional
+fixes and cleanups by Hans de Goede.
+
+It uses dma in bus-master mode using a built-in designware idmac controller,
+which is identical to the one found in the mmc-dw hosts.
+The rest of the host is not identical to mmc-dw.
+
+Signed-off-by: David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ drivers/mmc/host/Kconfig | 7 +
+ drivers/mmc/host/Makefile | 2 +
+ drivers/mmc/host/sunxi-mmc.c | 853 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/host/sunxi-mmc.h | 238 ++++++++++++
+ 4 files changed, 1100 insertions(+)
+ create mode 100644 drivers/mmc/host/sunxi-mmc.c
+ create mode 100644 drivers/mmc/host/sunxi-mmc.h
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 1384f67..7caf266 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -689,3 +689,10 @@ config MMC_REALTEK_PCI
+ help
+ Say Y here to include driver code to support SD/MMC card interface
+ of Realtek PCI-E card reader
++
++config MMC_SUNXI
++ tristate "Allwinner sunxi SD/MMC Host Controller support"
++ depends on ARCH_SUNXI
++ help
++ This selects support for the SD/MMC Host Controller on
++ Allwinner sunxi SoCs.
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index 3483b6b..f3c7c243 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -54,6 +54,8 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
+
+ obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
+
++obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
++
+ obj-$(CONFIG_MMC_SDHCI_PLTFM) += sdhci-pltfm.o
+ obj-$(CONFIG_MMC_SDHCI_CNS3XXX) += sdhci-cns3xxx.o
+ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o
+diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
+new file mode 100644
+index 0000000..a16abd2
+--- /dev/null
++++ b/drivers/mmc/host/sunxi-mmc.c
+@@ -0,0 +1,853 @@
++/*
++ * Driver for sunxi SD/MMC host controllers
++ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
++ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
++ * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
++ * (C) Copyright 2013-2014 David Lanzendörfer <david.lanzendoerfer@o2s.ch>
++ * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++
++#include <linux/clk.h>
++#include <linux/clk-private.h>
++#include <linux/clk/sunxi.h>
++
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++#include <linux/scatterlist.h>
++#include <linux/dma-mapping.h>
++#include <linux/slab.h>
++#include <linux/regulator/consumer.h>
++
++#include <linux/of_address.h>
++#include <linux/of_gpio.h>
++#include <linux/of_platform.h>
++
++#include <linux/mmc/host.h>
++#include <linux/mmc/sd.h>
++#include <linux/mmc/sdio.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/core.h>
++#include <linux/mmc/card.h>
++#include <linux/mmc/slot-gpio.h>
++
++#include "sunxi-mmc.h"
++
++static int sunxi_mmc_init_host(struct mmc_host *mmc)
++{
++ u32 rval;
++ struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
++ int ret;
++
++ ret = clk_prepare_enable(smc_host->clk_ahb);
++ if (ret) {
++ dev_err(mmc_dev(smc_host->mmc), "AHB clk err %d\n", ret);
++ return ret;
++ }
++ ret = clk_prepare_enable(smc_host->clk_mod);
++ if (ret) {
++ dev_err(mmc_dev(smc_host->mmc), "MOD clk err %d\n", ret);
++ clk_disable_unprepare(smc_host->clk_ahb);
++ return ret;
++ }
++
++ /* reset controller */
++ rval = mci_readl(smc_host, REG_GCTRL) | SDXC_HARDWARE_RESET;
++ mci_writel(smc_host, REG_GCTRL, rval);
++
++ mci_writel(smc_host, REG_FTRGL, 0x20070008);
++ mci_writel(smc_host, REG_TMOUT, 0xffffffff);
++ mci_writel(smc_host, REG_IMASK, smc_host->sdio_imask);
++ mci_writel(smc_host, REG_RINTR, 0xffffffff);
++ mci_writel(smc_host, REG_DBGC, 0xdeb);
++ mci_writel(smc_host, REG_FUNS, 0xceaa0000);
++ mci_writel(smc_host, REG_DLBA, smc_host->sg_dma);
++ rval = mci_readl(smc_host, REG_GCTRL)|SDXC_INTERRUPT_ENABLE_BIT;
++ rval &= ~SDXC_ACCESS_DONE_DIRECT;
++ mci_writel(smc_host, REG_GCTRL, rval);
++
++ return 0;
++}
++
++static void sunxi_mmc_exit_host(struct sunxi_mmc_host *smc_host)
++{
++ mci_writel(smc_host, REG_GCTRL, SDXC_HARDWARE_RESET);
++ clk_disable_unprepare(smc_host->clk_ahb);
++ clk_disable_unprepare(smc_host->clk_mod);
++}
++
++/* /\* UHS-I Operation Modes */
++/* * DS 25MHz 12.5MB/s 3.3V */
++/* * HS 50MHz 25MB/s 3.3V */
++/* * SDR12 25MHz 12.5MB/s 1.8V */
++/* * SDR25 50MHz 25MB/s 1.8V */
++/* * SDR50 100MHz 50MB/s 1.8V */
++/* * SDR104 208MHz 104MB/s 1.8V */
++/* * DDR50 50MHz 50MB/s 1.8V */
++/* * MMC Operation Modes */
++/* * DS 26MHz 26MB/s 3/1.8/1.2V */
++/* * HS 52MHz 52MB/s 3/1.8/1.2V */
++/* * HSDDR 52MHz 104MB/s 3/1.8/1.2V */
++/* * HS200 200MHz 200MB/s 1.8/1.2V */
++/* * */
++/* * Spec. Timing */
++/* * SD3.0 */
++/* * Fcclk Tcclk Fsclk Tsclk Tis Tih odly RTis RTih */
++/* * 400K 2.5us 24M 41ns 5ns 5ns 1 2209ns 41ns */
++/* * 25M 40ns 600M 1.67ns 5ns 5ns 3 14.99ns 5.01ns */
++/* * 50M 20ns 600M 1.67ns 6ns 2ns 3 14.99ns 5.01ns */
++/* * 50MDDR 20ns 600M 1.67ns 6ns 0.8ns 2 6.67ns 3.33ns */
++/* * 104M 9.6ns 600M 1.67ns 3ns 0.8ns 1 7.93ns 1.67ns */
++/* * 208M 4.8ns 600M 1.67ns 1.4ns 0.8ns 1 3.33ns 1.67ns */
++
++/* * 25M 40ns 300M 3.33ns 5ns 5ns 2 13.34ns 6.66ns */
++/* * 50M 20ns 300M 3.33ns 6ns 2ns 2 13.34ns 6.66ns */
++/* * 50MDDR 20ns 300M 3.33ns 6ns 0.8ns 1 6.67ns 3.33ns */
++/* * 104M 9.6ns 300M 3.33ns 3ns 0.8ns 0 7.93ns 1.67ns */
++/* * 208M 4.8ns 300M 3.33ns 1.4ns 0.8ns 0 3.13ns 1.67ns */
++
++/* * eMMC4.5 */
++/* * 400K 2.5us 24M 41ns 3ns 3ns 1 2209ns 41ns */
++/* * 25M 40ns 600M 1.67ns 3ns 3ns 3 14.99ns 5.01ns */
++/* * 50M 20ns 600M 1.67ns 3ns 3ns 3 14.99ns 5.01ns */
++/* * 50MDDR 20ns 600M 1.67ns 2.5ns 2.5ns 2 6.67ns 3.33ns */
++/* * 200M 5ns 600M 1.67ns 1.4ns 0.8ns 1 3.33ns 1.67ns */
++/* *\/ */
++
++static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
++ struct mmc_data *data)
++{
++ struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
++ struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
++ int i, max_len = (1 << host->idma_des_size_bits);
++
++ for (i = 0; i < data->sg_len; i++) {
++ pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
++ SDXC_IDMAC_DES0_DIC;
++
++ if (data->sg[i].length == max_len)
++ pdes[i].buf_size = 0; /* 0 == max_len */
++ else
++ pdes[i].buf_size = data->sg[i].length;
++
++ pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
++ pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
++ }
++
++ pdes[0].config |= SDXC_IDMAC_DES0_FD;
++ pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
++
++ wmb(); /* Ensure idma_des hit main mem before we start the idmac */
++}
++
++static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
++{
++ if (data->flags & MMC_DATA_WRITE)
++ return DMA_TO_DEVICE;
++ else
++ return DMA_FROM_DEVICE;
++}
++
++static int sunxi_mmc_prepare_dma(struct sunxi_mmc_host *smc_host,
++ struct mmc_data *data)
++{
++ u32 dma_len;
++ u32 i;
++ u32 temp;
++ struct scatterlist *sg;
++
++ dma_len = dma_map_sg(mmc_dev(smc_host->mmc), data->sg, data->sg_len,
++ sunxi_mmc_get_dma_dir(data));
++ if (dma_len == 0) {
++ dev_err(mmc_dev(smc_host->mmc), "dma_map_sg failed\n");
++ return -ENOMEM;
++ }
++
++ for_each_sg(data->sg, sg, data->sg_len, i) {
++ if (sg->offset & 3 || sg->length & 3) {
++ dev_err(mmc_dev(smc_host->mmc),
++ "unaligned scatterlist: os %x length %d\n",
++ sg->offset, sg->length);
++ return -EINVAL;
++ }
++ }
++
++ sunxi_mmc_init_idma_des(smc_host, data);
++
++ temp = mci_readl(smc_host, REG_GCTRL);
++ temp |= SDXC_DMA_ENABLE_BIT;
++ mci_writel(smc_host, REG_GCTRL, temp);
++ temp |= SDXC_DMA_RESET;
++ mci_writel(smc_host, REG_GCTRL, temp);
++ mci_writel(smc_host, REG_DMAC, SDXC_IDMAC_SOFT_RESET);
++
++ if (!(data->flags & MMC_DATA_WRITE))
++ mci_writel(smc_host, REG_IDIE, SDXC_IDMAC_RECEIVE_INTERRUPT);
++
++ mci_writel(smc_host, REG_DMAC, SDXC_IDMAC_FIX_BURST | SDXC_IDMAC_IDMA_ON);
++
++ return 0;
++}
++
++static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
++ struct mmc_request *req)
++{
++ u32 cmd_val = SDXC_START | SDXC_RESP_EXPIRE | SDXC_STOP_ABORT_CMD
++ | SDXC_CHECK_RESPONSE_CRC | MMC_STOP_TRANSMISSION;
++ u32 ri = 0;
++ unsigned long expire = jiffies + msecs_to_jiffies(1000);
++
++ mci_writel(host, REG_CARG, 0);
++ mci_writel(host, REG_CMDR, cmd_val);
++
++ do {
++ ri = mci_readl(host, REG_RINTR);
++ } while (!(ri & (SDXC_COMMAND_DONE | SDXC_INTERRUPT_ERROR_BIT)) &&
++ time_before(jiffies, expire));
++
++ if (ri & SDXC_INTERRUPT_ERROR_BIT) {
++ dev_err(mmc_dev(host->mmc), "send stop command failed\n");
++ if (req->stop)
++ req->stop->resp[0] = -ETIMEDOUT;
++ } else {
++ if (req->stop)
++ req->stop->resp[0] = mci_readl(host, REG_RESP0);
++ }
++
++ mci_writel(host, REG_RINTR, 0xffff);
++}
++
++static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *smc_host)
++{
++ struct mmc_command *cmd = smc_host->mrq->cmd;
++ struct mmc_data *data = smc_host->mrq->data;
++
++ /* For some cmds timeout is normal with sd/mmc cards */
++ if ((smc_host->int_sum & SDXC_INTERRUPT_ERROR_BIT) == SDXC_RESP_TIMEOUT &&
++ (cmd->opcode == SD_IO_SEND_OP_COND || cmd->opcode == SD_IO_RW_DIRECT))
++ return;
++
++ dev_err(mmc_dev(smc_host->mmc),
++ "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
++ smc_host->mmc->index, cmd->opcode,
++ data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
++ smc_host->int_sum & SDXC_RESP_ERROR ? " RE" : "",
++ smc_host->int_sum & SDXC_RESP_CRC_ERROR ? " RCE" : "",
++ smc_host->int_sum & SDXC_DATA_CRC_ERROR ? " DCE" : "",
++ smc_host->int_sum & SDXC_RESP_TIMEOUT ? " RTO" : "",
++ smc_host->int_sum & SDXC_DATA_TIMEOUT ? " DTO" : "",
++ smc_host->int_sum & SDXC_FIFO_RUN_ERROR ? " FE" : "",
++ smc_host->int_sum & SDXC_HARD_WARE_LOCKED ? " HL" : "",
++ smc_host->int_sum & SDXC_START_BIT_ERROR ? " SBE" : "",
++ smc_host->int_sum & SDXC_END_BIT_ERROR ? " EBE" : ""
++ );
++}
++
++static void sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
++{
++ struct mmc_request *mrq;
++ unsigned long iflags;
++
++ spin_lock_irqsave(&host->lock, iflags);
++
++ mrq = host->mrq;
++ if (!mrq) {
++ spin_unlock_irqrestore(&host->lock, iflags);
++ dev_err(mmc_dev(host->mmc), "no request to finalize\n");
++ return;
++ }
++
++ if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT) {
++ sunxi_mmc_dump_errinfo(host);
++ mrq->cmd->error = -ETIMEDOUT;
++ if (mrq->data)
++ mrq->data->error = -ETIMEDOUT;
++ if (mrq->stop)
++ mrq->stop->error = -ETIMEDOUT;
++ } else {
++ if (mrq->cmd->flags & MMC_RSP_136) {
++ mrq->cmd->resp[0] = mci_readl(host, REG_RESP3);
++ mrq->cmd->resp[1] = mci_readl(host, REG_RESP2);
++ mrq->cmd->resp[2] = mci_readl(host, REG_RESP1);
++ mrq->cmd->resp[3] = mci_readl(host, REG_RESP0);
++ } else {
++ mrq->cmd->resp[0] = mci_readl(host, REG_RESP0);
++ }
++ if (mrq->data)
++ mrq->data->bytes_xfered =
++ mrq->data->blocks * mrq->data->blksz;
++ }
++
++ if (mrq->data) {
++ struct mmc_data *data = mrq->data;
++ u32 temp;
++
++ mci_writel(host, REG_IDST, 0x337);
++ mci_writel(host, REG_DMAC, 0);
++ temp = mci_readl(host, REG_GCTRL);
++ mci_writel(host, REG_GCTRL, temp|SDXC_DMA_RESET);
++ temp &= ~SDXC_DMA_ENABLE_BIT;
++ mci_writel(host, REG_GCTRL, temp);
++ temp |= SDXC_FIFO_RESET;
++ mci_writel(host, REG_GCTRL, temp);
++ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
++ sunxi_mmc_get_dma_dir(data));
++ }
++
++ mci_writel(host, REG_RINTR, 0xffff);
++
++ dev_dbg(mmc_dev(host->mmc), "req done, resp %08x %08x %08x %08x\n",
++ mrq->cmd->resp[0], mrq->cmd->resp[1],
++ mrq->cmd->resp[2], mrq->cmd->resp[3]);
++
++ host->mrq = NULL;
++ host->int_sum = 0;
++ host->wait_dma = 0;
++
++ spin_unlock_irqrestore(&host->lock, iflags);
++
++ if (mrq->data && mrq->data->error) {
++ dev_err(mmc_dev(host->mmc),
++ "data error, sending stop command\n");
++ sunxi_mmc_send_manual_stop(host, mrq);
++ }
++
++ mmc_request_done(host->mmc, mrq);
++}
++
++static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
++{
++ struct sunxi_mmc_host *host = dev_id;
++ u32 finalize = 0;
++ u32 sdio_int = 0;
++ u32 msk_int;
++ u32 idma_int;
++
++ spin_lock(&host->lock);
++
++ idma_int = mci_readl(host, REG_IDST);
++ msk_int = mci_readl(host, REG_MISTA);
++
++ dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
++ host->mrq, msk_int, idma_int);
++
++ if (host->mrq) {
++ if (idma_int & SDXC_IDMAC_RECEIVE_INTERRUPT)
++ host->wait_dma = 0;
++
++ host->int_sum |= msk_int;
++
++ /* Wait for COMMAND_DONE on RESPONSE_TIMEOUT before finishing the req */
++ if ((host->int_sum & SDXC_RESP_TIMEOUT) &&
++ !(host->int_sum & SDXC_COMMAND_DONE))
++ mci_writel(host, REG_IMASK,
++ host->sdio_imask | SDXC_COMMAND_DONE);
++ else if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT)
++ finalize = 1; /* Don't wait for dma on error */
++ else if (host->int_sum & SDXC_INTERRUPT_DONE_BIT && !host->wait_dma)
++ finalize = 1; /* Done */
++
++ if (finalize) {
++ mci_writel(host, REG_IMASK, host->sdio_imask);
++ mci_writel(host, REG_IDIE, 0);
++ }
++ }
++
++ if (msk_int & SDXC_SDIO_INTERRUPT)
++ sdio_int = 1;
++
++ mci_writel(host, REG_RINTR, msk_int);
++ mci_writel(host, REG_IDST, idma_int);
++
++ spin_unlock(&host->lock);
++
++ if (finalize)
++ tasklet_schedule(&host->tasklet);
++
++ if (sdio_int)
++ mmc_signal_sdio_irq(host->mmc);
++
++ return IRQ_HANDLED;
++}
++
++static void sunxi_mmc_tasklet(unsigned long data)
++{
++ struct sunxi_mmc_host *smc_host = (struct sunxi_mmc_host *) data;
++ sunxi_mmc_finalize_request(smc_host);
++}
++
++static void sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
++{
++ unsigned long expire = jiffies + msecs_to_jiffies(2000);
++ u32 rval;
++
++ rval = mci_readl(host, REG_CLKCR);
++ rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON);
++
++ if (oclk_en)
++ rval |= SDXC_CARD_CLOCK_ON;
++
++ mci_writel(host, REG_CLKCR, rval);
++
++ rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER;
++ if (host->voltage_switching)
++ rval |= SDXC_VOLTAGE_SWITCH;
++ mci_writel(host, REG_CMDR, rval);
++
++ do {
++ rval = mci_readl(host, REG_CMDR);
++ } while (time_before(jiffies, expire) && (rval & SDXC_START));
++
++ if (rval & SDXC_START) {
++ dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
++ host->ferror = 1;
++ }
++}
++
++struct sunxi_mmc_clk_dly mmc_clk_dly[MMC_CLK_MOD_NUM] = {
++ { MMC_CLK_400K, 0, 7 },
++ { MMC_CLK_25M, 0, 5 },
++ { MMC_CLK_50M, 3, 5 },
++ { MMC_CLK_50MDDR, 2, 4 },
++ { MMC_CLK_50MDDR_8BIT, 2, 4 },
++ { MMC_CLK_100M, 1, 4 },
++ { MMC_CLK_200M, 1, 4 },
++};
++
++static void sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *smc_host,
++ unsigned int rate)
++{
++ u32 newrate;
++ u32 src_clk;
++ u32 oclk_dly;
++ u32 sclk_dly;
++ u32 temp;
++ struct sunxi_mmc_clk_dly *dly = NULL;
++ struct clk_hw *hw = __clk_get_hw(smc_host->clk_mod);
++
++ newrate = clk_round_rate(smc_host->clk_mod, rate);
++ if (smc_host->clk_mod_rate == newrate) {
++ dev_dbg(mmc_dev(smc_host->mmc), "clk already %d, rounded %d\n",
++ rate, newrate);
++ return;
++ }
++
++ dev_dbg(mmc_dev(smc_host->mmc), "setting clk to %d, rounded %d\n",
++ rate, newrate);
++
++ /* setting clock rate */
++ clk_disable(smc_host->clk_mod);
++ clk_set_rate(smc_host->clk_mod, newrate);
++ clk_enable(smc_host->clk_mod);
++ smc_host->clk_mod_rate = newrate = clk_get_rate(smc_host->clk_mod);
++ dev_dbg(mmc_dev(smc_host->mmc), "clk is now %d\n", newrate);
++
++ sunxi_mmc_oclk_onoff(smc_host, 0);
++ /* clear internal divider */
++ temp = mci_readl(smc_host, REG_CLKCR);
++ temp &= ~0xff;
++ mci_writel(smc_host, REG_CLKCR, temp);
++
++ /* determine delays */
++ if (rate <= 400000) {
++ dly = &mmc_clk_dly[MMC_CLK_400K];
++ } else if (rate <= 25000000) {
++ dly = &mmc_clk_dly[MMC_CLK_25M];
++ } else if (rate <= 50000000) {
++ if (smc_host->ddr) {
++ if (smc_host->bus_width == 8)
++ dly = &mmc_clk_dly[MMC_CLK_50MDDR_8BIT];
++ else
++ dly = &mmc_clk_dly[MMC_CLK_50MDDR];
++ } else {
++ dly = &mmc_clk_dly[MMC_CLK_50M];
++ }
++ } else if (rate <= 104000000) {
++ dly = &mmc_clk_dly[MMC_CLK_100M];
++ } else if (rate <= 208000000) {
++ dly = &mmc_clk_dly[MMC_CLK_200M];
++ } else {
++ dly = &mmc_clk_dly[MMC_CLK_50M];
++ }
++
++ oclk_dly = dly->oclk_dly;
++ sclk_dly = dly->sclk_dly;
++
++ src_clk = clk_get_rate(clk_get_parent(smc_host->clk_mod));
++
++ if (src_clk >= 300000000 && src_clk <= 400000000) {
++ if (oclk_dly)
++ oclk_dly--;
++ if (sclk_dly)
++ sclk_dly--;
++ }
++
++ clk_sunxi_mmc_phase_control(hw, sclk_dly, oclk_dly);
++ sunxi_mmc_oclk_onoff(smc_host, 1);
++
++ /* oclk_onoff sets various irq status bits, clear these */
++ mci_writel(smc_host, REG_RINTR,
++ mci_readl(smc_host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT);
++}
++
++static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++ struct sunxi_mmc_host *host = mmc_priv(mmc);
++ u32 temp;
++ s32 err;
++
++ /* Set the power state */
++ switch (ios->power_mode) {
++ case MMC_POWER_ON:
++ break;
++
++ case MMC_POWER_UP:
++ if (!IS_ERR(host->vmmc)) {
++ mmc_regulator_set_ocr(host->mmc, host->vmmc, ios->vdd);
++ udelay(200);
++ }
++
++ err = sunxi_mmc_init_host(mmc);
++ if (err) {
++ host->ferror = 1;
++ return;
++ }
++ enable_irq(host->irq);
++
++ dev_dbg(mmc_dev(host->mmc), "power on!\n");
++ host->ferror = 0;
++ break;
++
++ case MMC_POWER_OFF:
++ dev_dbg(mmc_dev(host->mmc), "power off!\n");
++ disable_irq(host->irq);
++ sunxi_mmc_exit_host(host);
++ if (!IS_ERR(host->vmmc))
++ mmc_regulator_set_ocr(host->mmc, host->vmmc, 0);
++ host->ferror = 0;
++ break;
++ }
++
++ /* set bus width */
++ switch (ios->bus_width) {
++ case MMC_BUS_WIDTH_1:
++ mci_writel(host, REG_WIDTH, SDXC_WIDTH1);
++ host->bus_width = 1;
++ break;
++ case MMC_BUS_WIDTH_4:
++ mci_writel(host, REG_WIDTH, SDXC_WIDTH4);
++ host->bus_width = 4;
++ break;
++ case MMC_BUS_WIDTH_8:
++ mci_writel(host, REG_WIDTH, SDXC_WIDTH8);
++ host->bus_width = 8;
++ break;
++ }
++
++ /* set ddr mode */
++ temp = mci_readl(host, REG_GCTRL);
++ if (ios->timing == MMC_TIMING_UHS_DDR50) {
++ temp |= SDXC_DDR_MODE;
++ host->ddr = 1;
++ } else {
++ temp &= ~SDXC_DDR_MODE;
++ host->ddr = 0;
++ }
++ mci_writel(host, REG_GCTRL, temp);
++
++ /* set up clock */
++ if (ios->clock && ios->power_mode) {
++ dev_dbg(mmc_dev(host->mmc), "ios->clock: %d\n", ios->clock);
++ sunxi_mmc_clk_set_rate(host, ios->clock);
++ usleep_range(50000, 55000);
++ }
++}
++
++static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
++{
++ struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
++ unsigned long flags;
++ u32 imask;
++
++ spin_lock_irqsave(&smc_host->lock, flags);
++
++ imask = mci_readl(smc_host, REG_IMASK);
++ if (enable) {
++ smc_host->sdio_imask = SDXC_SDIO_INTERRUPT;
++ imask |= SDXC_SDIO_INTERRUPT;
++ } else {
++ smc_host->sdio_imask = 0;
++ imask &= ~SDXC_SDIO_INTERRUPT;
++ }
++ mci_writel(smc_host, REG_IMASK, imask);
++ spin_unlock_irqrestore(&smc_host->lock, flags);
++}
++
++static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
++{
++ struct sunxi_mmc_host *smc_host = mmc_priv(mmc);
++ mci_writel(smc_host, REG_HWRST, 0);
++ udelay(10);
++ mci_writel(smc_host, REG_HWRST, 1);
++ udelay(300);
++}
++
++static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++ struct sunxi_mmc_host *host = mmc_priv(mmc);
++ struct mmc_command *cmd = mrq->cmd;
++ struct mmc_data *data = mrq->data;
++ unsigned long iflags;
++ u32 imask = SDXC_INTERRUPT_ERROR_BIT;
++ u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f);
++ u32 byte_cnt = 0;
++ int ret;
++
++ if (!mmc_gpio_get_cd(mmc) || host->ferror) {
++ dev_dbg(mmc_dev(host->mmc), "no medium present\n");
++ mrq->cmd->error = -ENOMEDIUM;
++ mmc_request_done(mmc, mrq);
++ return;
++ }
++
++ if (data) {
++ byte_cnt = data->blksz * data->blocks;
++ mci_writel(host, REG_BLKSZ, data->blksz);
++ mci_writel(host, REG_BCNTR, byte_cnt);
++ ret = sunxi_mmc_prepare_dma(host, data);
++ if (ret < 0) {
++ dev_err(mmc_dev(host->mmc), "prepare DMA failed\n");
++ cmd->error = ret;
++ cmd->data->error = ret;
++ mmc_request_done(host->mmc, mrq);
++ return;
++ }
++ }
++
++ if (cmd->opcode == MMC_GO_IDLE_STATE) {
++ cmd_val |= SDXC_SEND_INIT_SEQUENCE;
++ imask |= SDXC_COMMAND_DONE;
++ }
++
++ if (cmd->opcode == SD_SWITCH_VOLTAGE) {
++ cmd_val |= SDXC_VOLTAGE_SWITCH;
++ imask |= SDXC_VOLTAGE_CHANGE_DONE;
++ host->voltage_switching = 1;
++ sunxi_mmc_oclk_onoff(host, 1);
++ }
++
++ if (cmd->flags & MMC_RSP_PRESENT) {
++ cmd_val |= SDXC_RESP_EXPIRE;
++ if (cmd->flags & MMC_RSP_136)
++ cmd_val |= SDXC_LONG_RESPONSE;
++ if (cmd->flags & MMC_RSP_CRC)
++ cmd_val |= SDXC_CHECK_RESPONSE_CRC;
++
++ if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
++ cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER;
++ if (cmd->data->flags & MMC_DATA_STREAM) {
++ imask |= SDXC_AUTO_COMMAND_DONE;
++ cmd_val |= SDXC_SEQUENCE_MODE | SDXC_SEND_AUTO_STOP;
++ }
++ if (cmd->data->stop) {
++ imask |= SDXC_AUTO_COMMAND_DONE;
++ cmd_val |= SDXC_SEND_AUTO_STOP;
++ } else
++ imask |= SDXC_DATA_OVER;
++
++ if (cmd->data->flags & MMC_DATA_WRITE)
++ cmd_val |= SDXC_WRITE;
++ else
++ host->wait_dma = 1;
++ } else
++ imask |= SDXC_COMMAND_DONE;
++ } else
++ imask |= SDXC_COMMAND_DONE;
++
++ dev_dbg(mmc_dev(host->mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
++ cmd_val & 0x3f, cmd_val, cmd->arg, imask,
++ mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
++
++ spin_lock_irqsave(&host->lock, iflags);
++ host->mrq = mrq;
++ mci_writel(host, REG_IMASK, host->sdio_imask | imask);
++ spin_unlock_irqrestore(&host->lock, iflags);
++
++ mci_writel(host, REG_CARG, cmd->arg);
++ mci_writel(host, REG_CMDR, cmd_val);
++}
++
++static const struct of_device_id sunxi_mmc_of_match[] = {
++ { .compatible = "allwinner,sun4i-a10-mmc", },
++ { .compatible = "allwinner,sun5i-a13-mmc", },
++ { /* sentinel */ }
++};
++MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
++
++static struct mmc_host_ops sunxi_mmc_ops = {
++ .request = sunxi_mmc_request,
++ .set_ios = sunxi_mmc_set_ios,
++ .get_ro = mmc_gpio_get_ro,
++ .get_cd = mmc_gpio_get_cd,
++ .enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
++ .hw_reset = sunxi_mmc_hw_reset,
++};
++
++static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
++ struct platform_device *pdev)
++{
++ struct device_node *np = pdev->dev.of_node;
++ int ret;
++
++ if (of_device_is_compatible(np, "allwinner,sun4i-a10-mmc"))
++ host->idma_des_size_bits = 13;
++ else
++ host->idma_des_size_bits = 16;
++
++ host->vmmc = devm_regulator_get_optional(&pdev->dev, "vmmc");
++ if (IS_ERR(host->vmmc) && PTR_ERR(host->vmmc) == -EPROBE_DEFER)
++ return -EPROBE_DEFER;
++
++ host->reg_base = devm_ioremap_resource(&pdev->dev,
++ platform_get_resource(pdev, IORESOURCE_MEM, 0));
++ if (IS_ERR(host->reg_base))
++ return PTR_ERR(host->reg_base);
++
++ host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(host->clk_ahb)) {
++ dev_err(&pdev->dev, "Could not get ahb clock\n");
++ return PTR_ERR(host->clk_ahb);
++ }
++
++ host->clk_mod = devm_clk_get(&pdev->dev, "mod");
++ if (IS_ERR(host->clk_mod)) {
++ dev_err(&pdev->dev, "Could not get mod clock\n");
++ return PTR_ERR(host->clk_mod);
++ }
++
++ /* Make sure the controller is in a sane state before enabling irqs */
++ ret = sunxi_mmc_init_host(host->mmc);
++ if (ret)
++ return ret;
++
++ host->irq = platform_get_irq(pdev, 0);
++ ret = devm_request_irq(&pdev->dev, host->irq, sunxi_mmc_irq, 0,
++ "sunxi-mmc", host);
++ if (ret == 0)
++ disable_irq(host->irq);
++
++ /* And put it back in reset */
++ sunxi_mmc_exit_host(host);
++
++ return ret;
++}
++
++static int sunxi_mmc_probe(struct platform_device *pdev)
++{
++ struct sunxi_mmc_host *host;
++ struct mmc_host *mmc;
++ int ret;
++
++ mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
++ if (!mmc) {
++ dev_err(&pdev->dev, "mmc alloc host failed\n");
++ return -ENOMEM;
++ }
++
++ host = mmc_priv(mmc);
++ host->mmc = mmc;
++ spin_lock_init(&host->lock);
++ tasklet_init(&host->tasklet, sunxi_mmc_tasklet, (unsigned long)host);
++
++ ret = sunxi_mmc_resource_request(host, pdev);
++ if (ret)
++ goto error_free_host;
++
++ host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
++ &host->sg_dma, GFP_KERNEL);
++ if (!host->sg_cpu) {
++ dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
++ ret = -ENOMEM;
++ goto error_free_host;
++ }
++
++ mmc->ops = &sunxi_mmc_ops;
++ mmc->max_blk_count = 8192;
++ mmc->max_blk_size = 4096;
++ mmc->max_segs = PAGE_SIZE / sizeof(struct sunxi_idma_des);
++ mmc->max_seg_size = (1 << host->idma_des_size_bits);
++ mmc->max_req_size = mmc->max_seg_size * mmc->max_segs;
++ /* 400kHz ~ 50MHz */
++ mmc->f_min = 400000;
++ mmc->f_max = 50000000;
++ /* available voltages */
++ if (!IS_ERR(host->vmmc))
++ mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vmmc);
++ else
++ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++
++ mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
++ MMC_CAP_SDIO_IRQ;
++ mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
++
++ ret = mmc_of_parse(mmc);
++ if (ret)
++ goto error_free_dma;
++
++ ret = mmc_add_host(mmc);
++ if (ret)
++ goto error_free_dma;
++
++ dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
++ platform_set_drvdata(pdev, mmc);
++ return 0;
++
++error_free_dma:
++ dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
++error_free_host:
++ mmc_free_host(mmc);
++ return ret;
++}
++
++static int sunxi_mmc_remove(struct platform_device *pdev)
++{
++ struct mmc_host *mmc = platform_get_drvdata(pdev);
++ struct sunxi_mmc_host *host = mmc_priv(mmc);
++
++ mmc_remove_host(mmc);
++ sunxi_mmc_exit_host(host);
++ tasklet_disable(&host->tasklet);
++ dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
++ mmc_free_host(mmc);
++
++ return 0;
++}
++
++static struct platform_driver sunxi_mmc_driver = {
++ .driver = {
++ .name = "sunxi-mmc",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(sunxi_mmc_of_match),
++ },
++ .probe = sunxi_mmc_probe,
++ .remove = sunxi_mmc_remove,
++};
++module_platform_driver(sunxi_mmc_driver);
++
++MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("David Lanzendörfer <david.lanzendoerfer@o2s.ch>");
++MODULE_ALIAS("platform:sunxi-mmc");
+diff --git a/drivers/mmc/host/sunxi-mmc.h b/drivers/mmc/host/sunxi-mmc.h
+new file mode 100644
+index 0000000..84bab99
+--- /dev/null
++++ b/drivers/mmc/host/sunxi-mmc.h
+@@ -0,0 +1,238 @@
++/*
++ * Driver for sunxi SD/MMC host controllers
++ * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
++ * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
++ * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
++ * (C) Copyright 2013-2014 David Lanzendörfer <david.lanzendoerfer@o2s.ch>
++ * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ */
++
++#ifndef __SUNXI_MMC_H__
++#define __SUNXI_MMC_H__
++
++/* register offset definitions */
++#define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */
++#define SDXC_REG_CLKCR (0x04) /* SMC Clock Control Register */
++#define SDXC_REG_TMOUT (0x08) /* SMC Time Out Register */
++#define SDXC_REG_WIDTH (0x0C) /* SMC Bus Width Register */
++#define SDXC_REG_BLKSZ (0x10) /* SMC Block Size Register */
++#define SDXC_REG_BCNTR (0x14) /* SMC Byte Count Register */
++#define SDXC_REG_CMDR (0x18) /* SMC Command Register */
++#define SDXC_REG_CARG (0x1C) /* SMC Argument Register */
++#define SDXC_REG_RESP0 (0x20) /* SMC Response Register 0 */
++#define SDXC_REG_RESP1 (0x24) /* SMC Response Register 1 */
++#define SDXC_REG_RESP2 (0x28) /* SMC Response Register 2 */
++#define SDXC_REG_RESP3 (0x2C) /* SMC Response Register 3 */
++#define SDXC_REG_IMASK (0x30) /* SMC Interrupt Mask Register */
++#define SDXC_REG_MISTA (0x34) /* SMC Masked Interrupt Status Register */
++#define SDXC_REG_RINTR (0x38) /* SMC Raw Interrupt Status Register */
++#define SDXC_REG_STAS (0x3C) /* SMC Status Register */
++#define SDXC_REG_FTRGL (0x40) /* SMC FIFO Threshold Watermark Registe */
++#define SDXC_REG_FUNS (0x44) /* SMC Function Select Register */
++#define SDXC_REG_CBCR (0x48) /* SMC CIU Byte Count Register */
++#define SDXC_REG_BBCR (0x4C) /* SMC BIU Byte Count Register */
++#define SDXC_REG_DBGC (0x50) /* SMC Debug Enable Register */
++#define SDXC_REG_HWRST (0x78) /* SMC Card Hardware Reset for Register */
++#define SDXC_REG_DMAC (0x80) /* SMC IDMAC Control Register */
++#define SDXC_REG_DLBA (0x84) /* SMC IDMAC Descriptor List Base Addre */
++#define SDXC_REG_IDST (0x88) /* SMC IDMAC Status Register */
++#define SDXC_REG_IDIE (0x8C) /* SMC IDMAC Interrupt Enable Register */
++#define SDXC_REG_CHDA (0x90)
++#define SDXC_REG_CBDA (0x94)
++
++#define mci_readl(host, reg) \
++ readl((host)->reg_base + SDXC_##reg)
++#define mci_writel(host, reg, value) \
++ writel((value), (host)->reg_base + SDXC_##reg)
++
++/* global control register bits */
++#define SDXC_SOFT_RESET BIT(0)
++#define SDXC_FIFO_RESET BIT(1)
++#define SDXC_DMA_RESET BIT(2)
++#define SDXC_HARDWARE_RESET (SDXC_SOFT_RESET|SDXC_FIFO_RESET|SDXC_DMA_RESET)
++#define SDXC_INTERRUPT_ENABLE_BIT BIT(4)
++#define SDXC_DMA_ENABLE_BIT BIT(5)
++#define SDXC_DEBOUNCE_ENABLE_BIT BIT(8)
++#define SDXC_POSEDGE_LATCH_DATA BIT(9)
++#define SDXC_DDR_MODE BIT(10)
++#define SDXC_MEMORY_ACCESS_DONE BIT(29)
++#define SDXC_ACCESS_DONE_DIRECT BIT(30)
++#define SDXC_ACCESS_BY_AHB BIT(31)
++#define SDXC_ACCESS_BY_DMA (0U << 31)
++/* clock control bits */
++#define SDXC_CARD_CLOCK_ON BIT(16)
++#define SDXC_LOW_POWER_ON BIT(17)
++/* bus width */
++#define SDXC_WIDTH1 (0)
++#define SDXC_WIDTH4 (1)
++#define SDXC_WIDTH8 (2)
++/* smc command bits */
++#define SDXC_RESP_EXPIRE BIT(6)
++#define SDXC_LONG_RESPONSE BIT(7)
++#define SDXC_CHECK_RESPONSE_CRC BIT(8)
++#define SDXC_DATA_EXPIRE BIT(9)
++#define SDXC_WRITE BIT(10)
++#define SDXC_SEQUENCE_MODE BIT(11)
++#define SDXC_SEND_AUTO_STOP BIT(12)
++#define SDXC_WAIT_PRE_OVER BIT(13)
++#define SDXC_STOP_ABORT_CMD BIT(14)
++#define SDXC_SEND_INIT_SEQUENCE BIT(15)
++#define SDXC_UPCLK_ONLY BIT(21)
++#define SDXC_READ_CEATA_DEV BIT(22)
++#define SDXC_CCS_EXPIRE BIT(23)
++#define SDXC_ENABLE_BIT_BOOT BIT(24)
++#define SDXC_ALT_BOOT_OPTIONS BIT(25)
++#define SDXC_BOOT_ACK_EXPIRE BIT(26)
++#define SDXC_BOOT_ABORT BIT(27)
++#define SDXC_VOLTAGE_SWITCH BIT(28)
++#define SDXC_USE_HOLD_REGISTER BIT(29)
++#define SDXC_START BIT(31)
++/* interrupt bits */
++#define SDXC_RESP_ERROR BIT(1)
++#define SDXC_COMMAND_DONE BIT(2)
++#define SDXC_DATA_OVER BIT(3)
++#define SDXC_TX_DATA_REQUEST BIT(4)
++#define SDXC_RX_DATA_REQUEST BIT(5)
++#define SDXC_RESP_CRC_ERROR BIT(6)
++#define SDXC_DATA_CRC_ERROR BIT(7)
++#define SDXC_RESP_TIMEOUT BIT(8)
++#define SDXC_DATA_TIMEOUT BIT(9)
++#define SDXC_VOLTAGE_CHANGE_DONE BIT(10)
++#define SDXC_FIFO_RUN_ERROR BIT(11)
++#define SDXC_HARD_WARE_LOCKED BIT(12)
++#define SDXC_START_BIT_ERROR BIT(13)
++#define SDXC_AUTO_COMMAND_DONE BIT(14)
++#define SDXC_END_BIT_ERROR BIT(15)
++#define SDXC_SDIO_INTERRUPT BIT(16)
++#define SDXC_CARD_INSERT BIT(30)
++#define SDXC_CARD_REMOVE BIT(31)
++#define SDXC_INTERRUPT_ERROR_BIT (SDXC_RESP_ERROR | SDXC_RESP_CRC_ERROR | \
++ SDXC_DATA_CRC_ERROR | SDXC_RESP_TIMEOUT | \
++ SDXC_DATA_TIMEOUT | SDXC_FIFO_RUN_ERROR | \
++ SDXC_HARD_WARE_LOCKED | SDXC_START_BIT_ERROR | \
++ SDXC_END_BIT_ERROR) /* 0xbbc2 */
++#define SDXC_INTERRUPT_DONE_BIT (SDXC_AUTO_COMMAND_DONE | SDXC_DATA_OVER | \
++ SDXC_COMMAND_DONE | SDXC_VOLTAGE_CHANGE_DONE)
++/* status */
++#define SDXC_RXWL_FLAG BIT(0)
++#define SDXC_TXWL_FLAG BIT(1)
++#define SDXC_FIFO_EMPTY BIT(2)
++#define SDXC_FIFO_FULL BIT(3)
++#define SDXC_CARD_PRESENT BIT(8)
++#define SDXC_CARD_DATA_BUSY BIT(9)
++#define SDXC_DATA_FSM_BUSY BIT(10)
++#define SDXC_DMA_REQUEST BIT(31)
++#define SDXC_FIFO_SIZE (16)
++/* Function select */
++#define SDXC_CEATA_ON (0xceaaU << 16)
++#define SDXC_SEND_IRQ_RESPONSE BIT(0)
++#define SDXC_SDIO_READ_WAIT BIT(1)
++#define SDXC_ABORT_READ_DATA BIT(2)
++#define SDXC_SEND_CCSD BIT(8)
++#define SDXC_SEND_AUTO_STOPCCSD BIT(9)
++#define SDXC_CEATA_DEV_INTERRUPT_ENABLE_BIT BIT(10)
++/* IDMA controller bus mod bit field */
++#define SDXC_IDMAC_SOFT_RESET BIT(0)
++#define SDXC_IDMAC_FIX_BURST BIT(1)
++#define SDXC_IDMAC_IDMA_ON BIT(7)
++#define SDXC_IDMAC_REFETCH_DES BIT(31)
++/* IDMA status bit field */
++#define SDXC_IDMAC_TRANSMIT_INTERRUPT BIT(0)
++#define SDXC_IDMAC_RECEIVE_INTERRUPT BIT(1)
++#define SDXC_IDMAC_FATAL_BUS_ERROR BIT(2)
++#define SDXC_IDMAC_DESTINATION_INVALID BIT(4)
++#define SDXC_IDMAC_CARD_ERROR_SUM BIT(5)
++#define SDXC_IDMAC_NORMAL_INTERRUPT_SUM BIT(8)
++#define SDXC_IDMAC_ABNORMAL_INTERRUPT_SUM BIT(9)
++#define SDXC_IDMAC_HOST_ABORT_INTERRUPT_TX BIT(10)
++#define SDXC_IDMAC_HOST_ABORT_INTERRUPT_RX BIT(10)
++#define SDXC_IDMAC_IDLE (0U << 13)
++#define SDXC_IDMAC_SUSPEND (1U << 13)
++#define SDXC_IDMAC_DESC_READ (2U << 13)
++#define SDXC_IDMAC_DESC_CHECK (3U << 13)
++#define SDXC_IDMAC_READ_REQUEST_WAIT (4U << 13)
++#define SDXC_IDMAC_WRITE_REQUEST_WAIT (5U << 13)
++#define SDXC_IDMAC_READ (6U << 13)
++#define SDXC_IDMAC_WRITE (7U << 13)
++#define SDXC_IDMAC_DESC_CLOSE (8U << 13)
++
++/*
++* If the idma-des-size-bits of property is ie 13, bufsize bits are:
++* Bits 0-12: buf1 size
++* Bits 13-25: buf2 size
++* Bits 26-31: not used
++* Since we only ever set buf1 size, we can simply store it directly.
++*/
++#define SDXC_IDMAC_DES0_DIC BIT(1) /* disable interrupt on completion */
++#define SDXC_IDMAC_DES0_LD BIT(2) /* last descriptor */
++#define SDXC_IDMAC_DES0_FD BIT(3) /* first descriptor */
++#define SDXC_IDMAC_DES0_CH BIT(4) /* chain mode */
++#define SDXC_IDMAC_DES0_ER BIT(5) /* end of ring */
++#define SDXC_IDMAC_DES0_CES BIT(30) /* card error summary */
++#define SDXC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */
++
++struct sunxi_idma_des {
++ u32 config;
++ u32 buf_size;
++ u32 buf_addr_ptr1;
++ u32 buf_addr_ptr2;
++};
++
++struct sunxi_mmc_host {
++ struct mmc_host *mmc;
++ struct regulator *vmmc;
++
++ /* IO mapping base */
++ void __iomem *reg_base;
++
++ spinlock_t lock;
++ struct tasklet_struct tasklet;
++
++ /* clock management */
++ struct clk *clk_ahb;
++ struct clk *clk_mod;
++
++ /* ios information */
++ u32 clk_mod_rate;
++ u32 bus_width;
++ u32 idma_des_size_bits;
++ u32 ddr;
++ u32 voltage_switching;
++
++ /* irq */
++ int irq;
++ u32 int_sum;
++ u32 sdio_imask;
++
++ /* flags */
++ u32 power_on:1;
++ u32 wait_dma:1;
++
++ dma_addr_t sg_dma;
++ void *sg_cpu;
++
++ struct mmc_request *mrq;
++ u32 ferror;
++};
++
++#define MMC_CLK_400K 0
++#define MMC_CLK_25M 1
++#define MMC_CLK_50M 2
++#define MMC_CLK_50MDDR 3
++#define MMC_CLK_50MDDR_8BIT 4
++#define MMC_CLK_100M 5
++#define MMC_CLK_200M 6
++#define MMC_CLK_MOD_NUM 7
++
++struct sunxi_mmc_clk_dly {
++ u32 mode;
++ u32 oclk_dly;
++ u32 sclk_dly;
++};
++
++#endif
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/201-dt-sun4i-add-mmc-nodes_NEED_REFRESH.patch b/target/linux/sunxi/patches-3.14/201-dt-sun4i-add-mmc-nodes_NEED_REFRESH.patch
new file mode 100644
index 0000000000..a6261cda8e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/201-dt-sun4i-add-mmc-nodes_NEED_REFRESH.patch
@@ -0,0 +1,195 @@
+From b66989fe7a41e1093b1f825967ab29963e06cccd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= <david.lanzendoerfer@o2s.ch>
+Date: Sat, 15 Feb 2014 14:02:51 +0100
+Subject: [PATCH] ARM: dts: sun4i: Add support for mmc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-a1000.dts | 8 +++++
+ arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 8 +++++
+ arch/arm/boot/dts/sun4i-a10.dtsi | 58 ++++++++++++++++++++++++++++++
+ 3 files changed, 74 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
+index fa746aea..68b687e 100644
+diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+index 4684cbe..13088f0 100644
+--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+@@ -34,6 +34,14 @@
+ };
+ };
+
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 27dc6ee..7014518 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -377,6 +377,50 @@
+ #size-cells = <0>;
+ };
+
++ mmc0: mmc@01c0f000 {
++ compatible = "allwinner,sun4i-a10-mmc";
++ reg = <0x01c0f000 0x1000>;
++ clocks = <&ahb_gates 8>, <&mmc0_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <32>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc1: mmc@01c10000 {
++ compatible = "allwinner,sun4i-a10-mmc";
++ reg = <0x01c10000 0x1000>;
++ clocks = <&ahb_gates 9>, <&mmc1_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <33>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc2: mmc@01c11000 {
++ compatible = "allwinner,sun4i-a10-mmc";
++ reg = <0x01c11000 0x1000>;
++ clocks = <&ahb_gates 10>, <&mmc2_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <34>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc3: mmc@01c12000 {
++ compatible = "allwinner,sun4i-a10-mmc";
++ reg = <0x01c12000 0x1000>;
++ clocks = <&ahb_gates 11>, <&mmc3_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <35>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
+ usbphy: phy@01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun4i-a10-usb-phy";
+@@ -529,6 +573,20 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ mmc0_pins_a: mmc0@0 {
++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
++ allwinner,function = "mmc0";
++ allwinner,drive = <2>;
++ allwinner,pull = <0>;
++ };
++
++ mmc0_cd_pin_reference_design: mmc0_cd_pin@0 {
++ allwinner,pins = "PH1";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <1>;
++ };
+ };
+
+ timer@01c20c00 {
+--
+2.0.3
+
+From c0b8d688678e4a652895ce5f0cd48917a9a4f6ba Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 11 Jan 2014 04:33:23 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add mmc node to a few more boards
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-hackberry.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-inet97fv2.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 8 ++++++++
+ arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-pcduino.dts | 8 ++++++++
+ 5 files changed, 43 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+index d7c17e4..a4b05d6 100644
+diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+index fe9272e..b73a070 100644
+diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+index dd84a9e3..c906171 100644
+--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
++++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+@@ -20,6 +20,14 @@
+ compatible = "pineriver,mini-xplus", "allwinner,sun4i-a10";
+
+ soc@01c00000 {
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+index 66cf0c7..e5a2765 100644
+--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
++++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+@@ -33,6 +33,15 @@
+ };
+ };
+
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ cd-mode = <1>;
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+index 255b47e..2820229 100644
+--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
++++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+@@ -34,6 +34,14 @@
+ };
+ };
+
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/202-dt-sun5i-add-mmc-nodes.patch b/target/linux/sunxi/patches-3.14/202-dt-sun5i-add-mmc-nodes.patch
new file mode 100644
index 0000000000..1f4b23c24c
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/202-dt-sun5i-add-mmc-nodes.patch
@@ -0,0 +1,138 @@
+From 7afa5fb704679e84c59e5ad25bbdf7605844c5ca Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= <david.lanzendoerfer@o2s.ch>
+Date: Sat, 15 Feb 2014 14:02:29 +0100
+Subject: [PATCH] ARM: dts: sun5i: Add support for mmc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts | 30 +++++++++++++++
+ arch/arm/boot/dts/sun5i-a10s.dtsi | 47 ++++++++++++++++++++++++
+ arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts | 15 ++++++++
+ arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 15 ++++++++
+ arch/arm/boot/dts/sun5i-a13.dtsi | 29 +++++++++++++++
+ 5 files changed, 136 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+index 23611b7..5bc25c7 100644
+diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
+index f34e0d8..8ba1ed7 100644
+diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+index 11169d5..700f688 100644
+--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+@@ -21,6 +21,14 @@
+ compatible = "olimex,a13-olinuxino-micro", "allwinner,sun5i-a13";
+
+ soc@01c00000 {
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_olinuxinom>;
++ cd-gpios = <&pio 6 0 0>; /* PG0 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+@@ -35,6 +43,13 @@
+ };
+
+ pinctrl@01c20800 {
++ mmc0_cd_pin_olinuxinom: mmc0_cd_pin@0 {
++ allwinner,pins = "PG0";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <1>;
++ };
++
+ led_pins_olinuxinom: led_pins@0 {
+ allwinner,pins = "PG9";
+ allwinner,function = "gpio_out";
+diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+index 7a9187b..177196c 100644
+--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
++++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+@@ -20,6 +20,14 @@
+ compatible = "olimex,a13-olinuxino", "allwinner,sun5i-a13";
+
+ soc@01c00000 {
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_olinuxino>;
++ cd-gpios = <&pio 6 0 0>; /* PG0 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+@@ -34,6 +42,13 @@
+ };
+
+ pinctrl@01c20800 {
++ mmc0_cd_pin_olinuxino: mmc0_cd_pin@0 {
++ allwinner,pins = "PG0";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <1>;
++ };
++
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PG9";
+ allwinner,function = "gpio_out";
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 0e9c239..6fc84a4 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -320,6 +320,28 @@
+ #size-cells = <0>;
+ };
+
++ mmc0: mmc@01c0f000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c0f000 0x1000>;
++ clocks = <&ahb_gates 8>, <&mmc0_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <32>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc2: mmc@01c11000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c11000 0x1000>;
++ clocks = <&ahb_gates 10>, <&mmc2_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <34>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
+ usbphy: phy@01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun5i-a13-usb-phy";
+@@ -415,6 +437,13 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ mmc0_pins_a: mmc0@0 {
++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
++ allwinner,function = "mmc0";
++ allwinner,drive = <2>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ timer@01c20c00 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/203-dt-sun7i-add-mmc-nodes.patch b/target/linux/sunxi/patches-3.14/203-dt-sun7i-add-mmc-nodes.patch
new file mode 100644
index 0000000000..daa6a91121
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/203-dt-sun7i-add-mmc-nodes.patch
@@ -0,0 +1,182 @@
+From 33654facee61ebbd88684c9cf482ec2ea41f575e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?David=20Lanzend=C3=B6rfer?= <david.lanzendoerfer@o2s.ch>
+Date: Sat, 15 Feb 2014 14:02:01 +0100
+Subject: [PATCH] ARM: dts: sun7i: Add support for mmc
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: David Lanzendörfer <david.lanzendoerfer@o2s.ch>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 8 +++
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 8 +++
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 23 +++++++++
+ arch/arm/boot/dts/sun7i-a20.dtsi | 65 +++++++++++++++++++++++++
+ 4 files changed, 104 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+index 68de89f..cd9d3c2 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+@@ -20,6 +20,14 @@
+ compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index cb25d3c..66bb3ef 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -20,6 +20,14 @@
+ compatible = "cubietech,cubietruck", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index eeadf76..822cbe2 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -31,6 +31,22 @@
+ status = "okay";
+ };
+
++ mmc0: mmc@01c0f000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc0_pins_a>;
++ pinctrl-1 = <&mmc0_cd_pin_reference_design>;
++ cd-gpios = <&pio 7 1 0>; /* PH1 */
++ status = "okay";
++ };
++
++ mmc3: mmc@01c12000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc3_pins_a>;
++ pinctrl-1 = <&mmc3_cd_pin_olinuxinom>;
++ cd-gpios = <&pio 7 11 0>; /* PH11 */
++ status = "okay";
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+@@ -65,6 +81,13 @@
+ };
+
+ pinctrl@01c20800 {
++ mmc3_cd_pin_olinuxinom: mmc3_cd_pin@0 {
++ allwinner,pins = "PH11";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <1>;
++ };
++
+ led_pins_olinuxino: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 4cc2f5f..1d9b314 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -439,6 +439,50 @@
+ #size-cells = <0>;
+ };
+
++ mmc0: mmc@01c0f000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c0f000 0x1000>;
++ clocks = <&ahb_gates 8>, <&mmc0_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <0 32 4>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc1: mmc@01c10000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c10000 0x1000>;
++ clocks = <&ahb_gates 9>, <&mmc1_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <0 33 4>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc2: mmc@01c11000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c11000 0x1000>;
++ clocks = <&ahb_gates 10>, <&mmc2_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <0 34 4>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
++ mmc3: mmc@01c12000 {
++ compatible = "allwinner,sun5i-a13-mmc";
++ reg = <0x01c12000 0x1000>;
++ clocks = <&ahb_gates 11>, <&mmc3_clk>;
++ clock-names = "ahb", "mod";
++ interrupts = <0 35 4>;
++ bus-width = <4>;
++ cd-inverted;
++ status = "disabled";
++ };
++
+ usbphy: phy@01c13400 {
+ #phy-cells = <1>;
+ compatible = "allwinner,sun7i-a20-usb-phy";
+@@ -645,6 +689,27 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ mmc0_pins_a: mmc0@0 {
++ allwinner,pins = "PF0","PF1","PF2","PF3","PF4","PF5";
++ allwinner,function = "mmc0";
++ allwinner,drive = <2>;
++ allwinner,pull = <0>;
++ };
++
++ mmc0_cd_pin_reference_design: mmc0_cd_pin@0 {
++ allwinner,pins = "PH1";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <1>;
++ };
++
++ mmc3_pins_a: mmc3@0 {
++ allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
++ allwinner,function = "mmc3";
++ allwinner,drive = <2>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ timer@01c20c00 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/205-nmi-add-driver.patch b/target/linux/sunxi/patches-3.14/205-nmi-add-driver.patch
new file mode 100644
index 0000000000..2e23f94998
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/205-nmi-add-driver.patch
@@ -0,0 +1,247 @@
+From b9ad0253e6c68ac3d37fd2ed8ed9bf8a334e4b65 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Sat, 15 Mar 2014 14:40:59 +0100
+Subject: [PATCH] ARM: sun7i/sun6i: irqchip: Add irqchip driver for NMI
+ controller
+
+Allwinner A20/A31 SoCs have special registers to control / (un)mask /
+acknowledge NMI. This NMI controller is separated and independent from GIC.
+This patch adds a new irqchip to manage NMI.
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-sunxi-nmi.c | 208 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 209 insertions(+)
+ create mode 100644 drivers/irqchip/irq-sunxi-nmi.c
+
+diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
+index 5194afb..1c0c151 100644
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -12,6 +12,7 @@ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+ obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o
+ obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o
+ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
++obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
+ obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
+ obj-$(CONFIG_ARM_GIC) += irq-gic.o
+ obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
+diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
+new file mode 100644
+index 0000000..12f547a
+--- /dev/null
++++ b/drivers/irqchip/irq-sunxi-nmi.c
+@@ -0,0 +1,208 @@
++/*
++ * Allwinner A20/A31 SoCs NMI IRQ chip driver.
++ *
++ * Carlo Caione <carlo.caione@gmail.com>
++ *
++ * This file is licensed under the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#include <linux/bitops.h>
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/irqdomain.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/of_platform.h>
++#include <linux/irqchip/chained_irq.h>
++#include "irqchip.h"
++
++#define SUNXI_NMI_SRC_TYPE_MASK 0x00000003
++
++enum {
++ SUNXI_SRC_TYPE_LEVEL_LOW = 0,
++ SUNXI_SRC_TYPE_EDGE_FALLING,
++ SUNXI_SRC_TYPE_LEVEL_HIGH,
++ SUNXI_SRC_TYPE_EDGE_RISING,
++};
++
++struct sunxi_sc_nmi_reg_offs {
++ u32 ctrl;
++ u32 pend;
++ u32 enable;
++};
++
++static struct sunxi_sc_nmi_reg_offs sun7i_reg_offs = {
++ .ctrl = 0x00,
++ .pend = 0x04,
++ .enable = 0x08,
++};
++
++static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
++ .ctrl = 0x00,
++ .pend = 0x04,
++ .enable = 0x34,
++};
++
++static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
++ u32 val)
++{
++ irq_reg_writel(val, gc->reg_base + off);
++}
++
++static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
++{
++ return irq_reg_readl(gc->reg_base + off);
++}
++
++static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
++{
++ struct irq_domain *domain = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_get_chip(irq);
++ unsigned int virq = irq_find_mapping(domain, 0);
++
++ chained_irq_enter(chip, desc);
++ generic_handle_irq(virq);
++ chained_irq_exit(chip, desc);
++}
++
++static int sunxi_sc_nmi_set_type(struct irq_data *data, unsigned int flow_type)
++{
++ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data);
++ struct irq_chip_type *ct = gc->chip_types;
++ u32 src_type_reg;
++ u32 ctrl_off = ct->regs.type;
++ unsigned int src_type;
++ unsigned int i;
++
++ irq_gc_lock(gc);
++
++ switch (flow_type & IRQF_TRIGGER_MASK) {
++ case IRQ_TYPE_EDGE_FALLING:
++ src_type = SUNXI_SRC_TYPE_EDGE_FALLING;
++ break;
++ case IRQ_TYPE_EDGE_RISING:
++ src_type = SUNXI_SRC_TYPE_EDGE_RISING;
++ break;
++ case IRQ_TYPE_LEVEL_HIGH:
++ src_type = SUNXI_SRC_TYPE_LEVEL_HIGH;
++ break;
++ case IRQ_TYPE_NONE:
++ case IRQ_TYPE_LEVEL_LOW:
++ src_type = SUNXI_SRC_TYPE_LEVEL_LOW;
++ break;
++ default:
++ irq_gc_unlock(gc);
++ pr_err("%s: Cannot assign multiple trigger modes to IRQ %d.\n",
++ __func__, data->irq);
++ return -EBADR;
++ }
++
++ irqd_set_trigger_type(data, flow_type);
++ irq_setup_alt_chip(data, flow_type);
++
++ for (i = 0; i <= gc->num_ct; i++, ct++)
++ if (ct->type & flow_type)
++ ctrl_off = ct->regs.type;
++
++ src_type_reg = sunxi_sc_nmi_read(gc, ctrl_off);
++ src_type_reg &= ~SUNXI_NMI_SRC_TYPE_MASK;
++ src_type_reg |= src_type;
++ sunxi_sc_nmi_write(gc, ctrl_off, src_type_reg);
++
++ irq_gc_unlock(gc);
++
++ return IRQ_SET_MASK_OK;
++}
++
++static int __init sunxi_sc_nmi_irq_init(struct device_node *node,
++ struct sunxi_sc_nmi_reg_offs *reg_offs)
++{
++ struct irq_domain *domain;
++ struct irq_chip_generic *gc;
++ unsigned int irq;
++ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
++ int ret;
++
++
++ domain = irq_domain_add_linear(node, 1, &irq_generic_chip_ops, NULL);
++ if (!domain) {
++ pr_err("%s: Could not register interrupt domain.\n", node->name);
++ return -ENOMEM;
++ }
++
++ ret = irq_alloc_domain_generic_chips(domain, 1, 2, node->name,
++ handle_fasteoi_irq, clr, 0,
++ IRQ_GC_INIT_MASK_CACHE);
++ if (ret) {
++ pr_err("%s: Could not allocate generic interrupt chip.\n",
++ node->name);
++ goto fail_irqd_remove;
++ }
++
++ irq = irq_of_parse_and_map(node, 0);
++ if (irq <= 0) {
++ pr_err("%s: unable to parse irq\n", node->name);
++ ret = -EINVAL;
++ goto fail_irqd_remove;
++ }
++
++ gc = irq_get_domain_generic_chip(domain, 0);
++ gc->reg_base = of_iomap(node, 0);
++ if (!gc->reg_base) {
++ pr_err("%s: unable to map resource\n", node->name);
++ ret = -ENOMEM;
++ goto fail_irqd_remove;
++ }
++
++ gc->chip_types[0].type = IRQ_TYPE_LEVEL_MASK;
++ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
++ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
++ gc->chip_types[0].chip.irq_eoi = irq_gc_ack_set_bit;
++ gc->chip_types[0].chip.irq_set_type = sunxi_sc_nmi_set_type;
++ gc->chip_types[0].chip.flags = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED;
++ gc->chip_types[0].regs.ack = reg_offs->pend;
++ gc->chip_types[0].regs.mask = reg_offs->enable;
++ gc->chip_types[0].regs.type = reg_offs->ctrl;
++
++ gc->chip_types[1].type = IRQ_TYPE_EDGE_BOTH;
++ gc->chip_types[1].chip.name = gc->chip_types[0].chip.name;
++ gc->chip_types[1].chip.irq_ack = irq_gc_ack_set_bit;
++ gc->chip_types[1].chip.irq_mask = irq_gc_mask_clr_bit;
++ gc->chip_types[1].chip.irq_unmask = irq_gc_mask_set_bit;
++ gc->chip_types[1].chip.irq_set_type = sunxi_sc_nmi_set_type;
++ gc->chip_types[1].regs.ack = reg_offs->pend;
++ gc->chip_types[1].regs.mask = reg_offs->enable;
++ gc->chip_types[1].regs.type = reg_offs->ctrl;
++ gc->chip_types[1].handler = handle_edge_irq;
++
++ sunxi_sc_nmi_write(gc, reg_offs->enable, 0);
++ sunxi_sc_nmi_write(gc, reg_offs->pend, 0x1);
++
++ irq_set_handler_data(irq, domain);
++ irq_set_chained_handler(irq, sunxi_sc_nmi_handle_irq);
++
++ return 0;
++
++fail_irqd_remove:
++ irq_domain_remove(domain);
++
++ return ret;
++}
++
++static int __init sun6i_sc_nmi_irq_init(struct device_node *node,
++ struct device_node *parent)
++{
++ return sunxi_sc_nmi_irq_init(node, &sun6i_reg_offs);
++}
++IRQCHIP_DECLARE(sun6i_sc_nmi, "allwinner,sun6i-a31-sc-nmi", sun6i_sc_nmi_irq_init);
++
++static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
++ struct device_node *parent)
++{
++ return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
++}
++IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/206-dt-sun67i-add-nmi-irqchip.patch b/target/linux/sunxi/patches-3.14/206-dt-sun67i-add-nmi-irqchip.patch
new file mode 100644
index 0000000000..57979ef0ce
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/206-dt-sun67i-add-nmi-irqchip.patch
@@ -0,0 +1,54 @@
+From eebb592523672ee7288b9327bd222165db638d1a Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Thu, 27 Feb 2014 20:34:21 +0100
+Subject: [PATCH] ARM: sun7i/sun6i: dts: Add NMI irqchip support
+
+This patch adds DTS entries for NMI controller as child of GIC.
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+---
+ arch/arm/boot/dts/sun6i-a31.dtsi | 8 ++++++++
+ arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
+index 8441733..74d2920 100644
+--- a/arch/arm/boot/dts/sun6i-a31.dtsi
++++ b/arch/arm/boot/dts/sun6i-a31.dtsi
+@@ -421,6 +421,14 @@
+ interrupts = <1 9 0xf04>;
+ };
+
++ nmi_intc: interrupt-controller@01f00c0c {
++ compatible = "allwinner,sun6i-a31-sc-nmi";
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ reg = <0x01f00c0c 0x38>;
++ interrupts = <0 32 4>;
++ };
++
+ cpucfg@01f01c00 {
+ compatible = "allwinner,sun6i-a31-cpuconfig";
+ reg = <0x01f01c00 0x300>;
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 4981f5e..2e66c85 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -401,6 +401,14 @@
+ #size-cells = <1>;
+ ranges;
+
++ nmi_intc: interrupt-controller@01c00030 {
++ compatible = "allwinner,sun7i-a20-sc-nmi";
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ reg = <0x01c00030 0x0c>;
++ interrupts = <0 0 4>;
++ };
++
+ spi0: spi@01c05000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c05000 0x1000>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/210-mfd-add-axp20x-pmic-driver.patch b/target/linux/sunxi/patches-3.14/210-mfd-add-axp20x-pmic-driver.patch
new file mode 100644
index 0000000000..71a3952bfa
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/210-mfd-add-axp20x-pmic-driver.patch
@@ -0,0 +1,517 @@
+From 509326e0138b762067904c0c60f818e9bdba4cd4 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Sat, 1 Mar 2014 17:45:46 +0100
+Subject: [PATCH] mfd: AXP20x: Add mfd driver for AXP20x PMIC
+
+This patch introduces the preliminary support for PMICs X-Powers AXP202
+and AXP209. The AXP209 and AXP202 are the PMUs (Power Management Unit)
+used by A10, A13 and A20 SoCs and developed by X-Powers, a sister company
+of Allwinner.
+
+The core enables support for two subsystems:
+- PEK (Power Enable Key)
+- Regulators
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 +
+ drivers/mfd/Kconfig | 12 ++
+ drivers/mfd/Makefile | 1 +
+ drivers/mfd/axp20x.c | 250 +++++++++++++++++++++++++++++++++++++++
+ include/linux/mfd/axp20x.h | 180 ++++++++++++++++++++++++++++
+ 5 files changed, 444 insertions(+)
+ create mode 100644 drivers/mfd/axp20x.c
+ create mode 100644 include/linux/mfd/axp20x.h
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index b5df4a5..d25660d 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -55,6 +55,7 @@ CONFIG_GPIO_SYSFS=y
+ # CONFIG_HWMON is not set
+ CONFIG_WATCHDOG=y
+ CONFIG_SUNXI_WATCHDOG=y
++CONFIG_MFD_AXP20X=y
+ # CONFIG_USB_SUPPORT is not set
+ CONFIG_NEW_LEDS=y
+ CONFIG_LEDS_CLASS=y
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 49bb445..24ba61a 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -59,6 +59,18 @@ config MFD_AAT2870_CORE
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
++config MFD_AXP20X
++ bool "X-Powers AXP20X"
++ select MFD_CORE
++ select REGMAP_I2C
++ select REGMAP_IRQ
++ depends on I2C=y
++ help
++ If you say Y here you get support for the AXP20X.
++ This driver provides common support for accessing the device,
++ additional drivers must be enabled in order to use the
++ functionality of the device.
++
+ config MFD_CROS_EC
+ tristate "ChromeOS Embedded Controller"
+ select MFD_CORE
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 5aea5ef..fb773b5 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -101,6 +101,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o
+ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
+ obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
+ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
++obj-$(CONFIG_MFD_AXP20X) += axp20x.o
+
+ obj-$(CONFIG_MFD_LP3943) += lp3943.o
+ obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o
+diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
+new file mode 100644
+index 0000000..92e5b0f
+--- /dev/null
++++ b/drivers/mfd/axp20x.c
+@@ -0,0 +1,250 @@
++/*
++ * axp20x.c - mfd core driver for the X-Powers AXP202 and AXP209
++ *
++ * Author: Carlo Caione <carlo@caione.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/pm_runtime.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++#include <linux/regulator/consumer.h>
++#include <linux/mfd/axp20x.h>
++#include <linux/mfd/core.h>
++#include <linux/of_device.h>
++#include <linux/of_irq.h>
++
++#define AXP20X_OFF 0x80
++
++static const struct regmap_range axp20x_writeable_ranges[] = {
++ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
++ regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
++};
++
++static const struct regmap_range axp20x_volatile_ranges[] = {
++ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
++};
++
++static const struct regmap_access_table axp20x_writeable_table = {
++ .yes_ranges = axp20x_writeable_ranges,
++ .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges),
++};
++
++static const struct regmap_access_table axp20x_volatile_table = {
++ .yes_ranges = axp20x_volatile_ranges,
++ .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
++};
++
++static struct resource axp20x_pek_resources[] = {
++ {
++ .name = "PEK_DBR",
++ .start = AXP20X_IRQ_PEK_RIS_EDGE,
++ .end = AXP20X_IRQ_PEK_RIS_EDGE,
++ .flags = IORESOURCE_IRQ,
++ },
++ {
++ .name = "PEK_DBF",
++ .start = AXP20X_IRQ_PEK_FAL_EDGE,
++ .end = AXP20X_IRQ_PEK_FAL_EDGE,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static const struct regmap_config axp20x_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .wr_table = &axp20x_writeable_table,
++ .volatile_table = &axp20x_volatile_table,
++ .max_register = AXP20X_FG_RES,
++ .cache_type = REGCACHE_RBTREE,
++};
++
++#define AXP20X_IRQ(_irq, _off, _mask) \
++ [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
++
++static const struct regmap_irq axp20x_regmap_irqs[] = {
++ AXP20X_IRQ(ACIN_OVER_V, 0, 7),
++ AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
++ AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
++ AXP20X_IRQ(VBUS_OVER_V, 0, 4),
++ AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
++ AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
++ AXP20X_IRQ(VBUS_V_LOW, 0, 1),
++ AXP20X_IRQ(BATT_PLUGIN, 1, 7),
++ AXP20X_IRQ(BATT_REMOVAL, 1, 6),
++ AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
++ AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
++ AXP20X_IRQ(CHARG, 1, 3),
++ AXP20X_IRQ(CHARG_DONE, 1, 2),
++ AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
++ AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
++ AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
++ AXP20X_IRQ(CHARG_I_LOW, 2, 6),
++ AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
++ AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
++ AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
++ AXP20X_IRQ(PEK_SHORT, 2, 1),
++ AXP20X_IRQ(PEK_LONG, 2, 0),
++ AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
++ AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
++ AXP20X_IRQ(VBUS_VALID, 3, 5),
++ AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
++ AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
++ AXP20X_IRQ(VBUS_SESS_END, 3, 2),
++ AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
++ AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
++ AXP20X_IRQ(TIMER, 4, 7),
++ AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
++ AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
++ AXP20X_IRQ(GPIO3_INPUT, 4, 3),
++ AXP20X_IRQ(GPIO2_INPUT, 4, 2),
++ AXP20X_IRQ(GPIO1_INPUT, 4, 1),
++ AXP20X_IRQ(GPIO0_INPUT, 4, 0),
++};
++
++static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
++ .name = "axp20x_irq_chip",
++ .status_base = AXP20X_IRQ1_STATE,
++ .ack_base = AXP20X_IRQ1_STATE,
++ .mask_base = AXP20X_IRQ1_EN,
++ .num_regs = 5,
++ .irqs = axp20x_regmap_irqs,
++ .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
++ .mask_invert = true,
++ .init_ack_masked = true,
++};
++
++static struct mfd_cell axp20x_cells[] = {
++ {
++ .name = "axp20x-pek",
++ .of_compatible = "x-powers,axp20x-pek",
++ .num_resources = ARRAY_SIZE(axp20x_pek_resources),
++ .resources = axp20x_pek_resources,
++ }, {
++ .name = "axp20x-regulator",
++ },
++};
++
++const struct of_device_id axp20x_of_match[] = {
++ { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
++ { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
++ { },
++};
++
++static struct axp20x_dev *axp20x_pm_power_off;
++static void axp20x_power_off(void)
++{
++ regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
++ AXP20X_OFF);
++}
++
++static int axp20x_i2c_probe(struct i2c_client *i2c,
++ const struct i2c_device_id *id)
++{
++ struct axp20x_dev *axp20x;
++ const struct of_device_id *of_id;
++ struct device_node *node = i2c->dev.of_node;
++ int ret;
++
++ axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
++ if (!axp20x)
++ return -ENOMEM;
++
++ of_id = of_match_device(axp20x_of_match, &i2c->dev);
++ if (!of_id) {
++ dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
++ return -ENODEV;
++ }
++ axp20x->variant = (int) of_id->data;
++
++ axp20x->i2c_client = i2c;
++ axp20x->dev = &i2c->dev;
++ dev_set_drvdata(axp20x->dev, axp20x);
++
++ axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
++ if (IS_ERR(axp20x->regmap)) {
++ ret = PTR_ERR(axp20x->regmap);
++ dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
++ return ret;
++ }
++
++ axp20x->irq = i2c->irq;
++ ret = regmap_add_irq_chip(axp20x->regmap, axp20x->irq,
++ IRQF_ONESHOT | IRQF_SHARED, -1,
++ &axp20x_regmap_irq_chip,
++ &axp20x->regmap_irqc);
++ if (ret) {
++ dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
++ return ret;
++ }
++
++ ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
++ ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
++ if (ret) {
++ dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
++ goto mfd_err;
++ }
++
++ axp20x->pm_off = of_property_read_bool(node, "axp,system-power-controller");
++
++ if (axp20x->pm_off && !pm_power_off) {
++ axp20x_pm_power_off = axp20x;
++ pm_power_off = axp20x_power_off;
++ }
++
++ dev_info(&i2c->dev, "AXP20X driver loaded\n");
++
++ return 0;
++
++mfd_err:
++ regmap_del_irq_chip(axp20x->irq, axp20x->regmap_irqc);
++
++ return ret;
++}
++
++static int axp20x_i2c_remove(struct i2c_client *i2c)
++{
++ struct axp20x_dev *axp20x = i2c_get_clientdata(i2c);
++
++ if (axp20x == axp20x_pm_power_off) {
++ axp20x_pm_power_off = NULL;
++ pm_power_off = NULL;
++ }
++
++ mfd_remove_devices(axp20x->dev);
++ regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc);
++
++ return 0;
++}
++
++static const struct i2c_device_id axp20x_i2c_id[] = {
++ { "axp202", AXP202_ID },
++ { "axp209", AXP209_ID },
++ { }
++};
++MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
++
++static struct i2c_driver axp20x_i2c_driver = {
++ .driver = {
++ .name = "axp20x",
++ .owner = THIS_MODULE,
++ .of_match_table = of_match_ptr(axp20x_of_match),
++ },
++ .probe = axp20x_i2c_probe,
++ .remove = axp20x_i2c_remove,
++ .id_table = axp20x_i2c_id,
++};
++
++module_i2c_driver(axp20x_i2c_driver);
++
++MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X");
++MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
+new file mode 100644
+index 0000000..fcef32c
+--- /dev/null
++++ b/include/linux/mfd/axp20x.h
+@@ -0,0 +1,180 @@
++/*
++ * Functions to access AXP20X power management chip.
++ *
++ * Copyright (C) 2013, Carlo Caione <carlo@caione.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++#ifndef __LINUX_MFD_AXP20X_H
++#define __LINUX_MFD_AXP20X_H
++
++#define AXP202_ID 0
++#define AXP209_ID 1
++
++#define AXP20X_DATACACHE(m) (0x04 + (m))
++
++/* Power supply */
++#define AXP20X_PWR_INPUT_STATUS 0x00
++#define AXP20X_PWR_OP_MODE 0x01
++#define AXP20X_USB_OTG_STATUS 0x02
++#define AXP20X_PWR_OUT_CTRL 0x12
++#define AXP20X_DCDC2_V_OUT 0x23
++#define AXP20X_DCDC2_LDO3_V_SCAL 0x25
++#define AXP20X_DCDC3_V_OUT 0x27
++#define AXP20X_LDO24_V_OUT 0x28
++#define AXP20X_LDO3_V_OUT 0x29
++#define AXP20X_VBUS_IPSOUT_MGMT 0x30
++#define AXP20X_V_OFF 0x31
++#define AXP20X_OFF_CTRL 0x32
++#define AXP20X_CHRG_CTRL1 0x33
++#define AXP20X_CHRG_CTRL2 0x34
++#define AXP20X_CHRG_BAK_CTRL 0x35
++#define AXP20X_PEK_KEY 0x36
++#define AXP20X_DCDC_FREQ 0x37
++#define AXP20X_V_LTF_CHRG 0x38
++#define AXP20X_V_HTF_CHRG 0x39
++#define AXP20X_APS_WARN_L1 0x3a
++#define AXP20X_APS_WARN_L2 0x3b
++#define AXP20X_V_LTF_DISCHRG 0x3c
++#define AXP20X_V_HTF_DISCHRG 0x3d
++
++/* Interrupt */
++#define AXP20X_IRQ1_EN 0x40
++#define AXP20X_IRQ2_EN 0x41
++#define AXP20X_IRQ3_EN 0x42
++#define AXP20X_IRQ4_EN 0x43
++#define AXP20X_IRQ5_EN 0x44
++#define AXP20X_IRQ1_STATE 0x48
++#define AXP20X_IRQ2_STATE 0x49
++#define AXP20X_IRQ3_STATE 0x4a
++#define AXP20X_IRQ4_STATE 0x4b
++#define AXP20X_IRQ5_STATE 0x4c
++
++/* ADC */
++#define AXP20X_ACIN_V_ADC_H 0x56
++#define AXP20X_ACIN_V_ADC_L 0x57
++#define AXP20X_ACIN_I_ADC_H 0x58
++#define AXP20X_ACIN_I_ADC_L 0x59
++#define AXP20X_VBUS_V_ADC_H 0x5a
++#define AXP20X_VBUS_V_ADC_L 0x5b
++#define AXP20X_VBUS_I_ADC_H 0x5c
++#define AXP20X_VBUS_I_ADC_L 0x5d
++#define AXP20X_TEMP_ADC_H 0x5e
++#define AXP20X_TEMP_ADC_L 0x5f
++#define AXP20X_TS_IN_H 0x62
++#define AXP20X_TS_IN_L 0x63
++#define AXP20X_GPIO0_V_ADC_H 0x64
++#define AXP20X_GPIO0_V_ADC_L 0x65
++#define AXP20X_GPIO1_V_ADC_H 0x66
++#define AXP20X_GPIO1_V_ADC_L 0x67
++#define AXP20X_PWR_BATT_H 0x70
++#define AXP20X_PWR_BATT_M 0x71
++#define AXP20X_PWR_BATT_L 0x72
++#define AXP20X_BATT_V_H 0x78
++#define AXP20X_BATT_V_L 0x79
++#define AXP20X_BATT_CHRG_I_H 0x7a
++#define AXP20X_BATT_CHRG_I_L 0x7b
++#define AXP20X_BATT_DISCHRG_I_H 0x7c
++#define AXP20X_BATT_DISCHRG_I_L 0x7d
++#define AXP20X_IPSOUT_V_HIGH_H 0x7e
++#define AXP20X_IPSOUT_V_HIGH_L 0x7f
++
++/* Power supply */
++#define AXP20X_DCDC_MODE 0x80
++#define AXP20X_ADC_EN1 0x82
++#define AXP20X_ADC_EN2 0x83
++#define AXP20X_ADC_RATE 0x84
++#define AXP20X_GPIO10_IN_RANGE 0x85
++#define AXP20X_GPIO1_ADC_IRQ_RIS 0x86
++#define AXP20X_GPIO1_ADC_IRQ_FAL 0x87
++#define AXP20X_TIMER_CTRL 0x8a
++#define AXP20X_VBUS_MON 0x8b
++#define AXP20X_OVER_TMP 0x8f
++
++/* GPIO */
++#define AXP20X_GPIO0_CTRL 0x90
++#define AXP20X_LDO5_V_OUT 0x91
++#define AXP20X_GPIO1_CTRL 0x92
++#define AXP20X_GPIO2_CTRL 0x93
++#define AXP20X_GPIO20_SS 0x94
++#define AXP20X_GPIO3_CTRL 0x95
++
++/* Battery */
++#define AXP20X_CHRG_CC_31_24 0xb0
++#define AXP20X_CHRG_CC_23_16 0xb1
++#define AXP20X_CHRG_CC_15_8 0xb2
++#define AXP20X_CHRG_CC_7_0 0xb3
++#define AXP20X_DISCHRG_CC_31_24 0xb4
++#define AXP20X_DISCHRG_CC_23_16 0xb5
++#define AXP20X_DISCHRG_CC_15_8 0xb6
++#define AXP20X_DISCHRG_CC_7_0 0xb7
++#define AXP20X_CC_CTRL 0xb8
++#define AXP20X_FG_RES 0xb9
++
++/* Regulators IDs */
++enum {
++ AXP20X_LDO1 = 0,
++ AXP20X_LDO2,
++ AXP20X_LDO3,
++ AXP20X_LDO4,
++ AXP20X_LDO5,
++ AXP20X_DCDC2,
++ AXP20X_DCDC3,
++ AXP20X_REG_ID_MAX,
++};
++
++/* IRQs */
++enum {
++ AXP20X_IRQ_ACIN_OVER_V = 1,
++ AXP20X_IRQ_ACIN_PLUGIN,
++ AXP20X_IRQ_ACIN_REMOVAL,
++ AXP20X_IRQ_VBUS_OVER_V,
++ AXP20X_IRQ_VBUS_PLUGIN,
++ AXP20X_IRQ_VBUS_REMOVAL,
++ AXP20X_IRQ_VBUS_V_LOW,
++ AXP20X_IRQ_BATT_PLUGIN,
++ AXP20X_IRQ_BATT_REMOVAL,
++ AXP20X_IRQ_BATT_ENT_ACT_MODE,
++ AXP20X_IRQ_BATT_EXIT_ACT_MODE,
++ AXP20X_IRQ_CHARG,
++ AXP20X_IRQ_CHARG_DONE,
++ AXP20X_IRQ_BATT_TEMP_HIGH,
++ AXP20X_IRQ_BATT_TEMP_LOW,
++ AXP20X_IRQ_DIE_TEMP_HIGH,
++ AXP20X_IRQ_CHARG_I_LOW,
++ AXP20X_IRQ_DCDC1_V_LONG,
++ AXP20X_IRQ_DCDC2_V_LONG,
++ AXP20X_IRQ_DCDC3_V_LONG,
++ AXP20X_IRQ_PEK_SHORT = 22,
++ AXP20X_IRQ_PEK_LONG,
++ AXP20X_IRQ_N_OE_PWR_ON,
++ AXP20X_IRQ_N_OE_PWR_OFF,
++ AXP20X_IRQ_VBUS_VALID,
++ AXP20X_IRQ_VBUS_NOT_VALID,
++ AXP20X_IRQ_VBUS_SESS_VALID,
++ AXP20X_IRQ_VBUS_SESS_END,
++ AXP20X_IRQ_LOW_PWR_LVL1,
++ AXP20X_IRQ_LOW_PWR_LVL2,
++ AXP20X_IRQ_TIMER,
++ AXP20X_IRQ_PEK_RIS_EDGE,
++ AXP20X_IRQ_PEK_FAL_EDGE,
++ AXP20X_IRQ_GPIO3_INPUT,
++ AXP20X_IRQ_GPIO2_INPUT,
++ AXP20X_IRQ_GPIO1_INPUT,
++ AXP20X_IRQ_GPIO0_INPUT,
++};
++
++struct axp20x_dev {
++ struct device *dev;
++ struct i2c_client *i2c_client;
++ struct regmap *regmap;
++ struct regmap_irq_chip_data *regmap_irqc;
++ int variant;
++ int irq;
++ bool pm_off;
++};
++
++#endif /* __LINUX_MFD_AXP20X_H */
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/211-input-add-axp20x-power-enable-key-support.patch b/target/linux/sunxi/patches-3.14/211-input-add-axp20x-power-enable-key-support.patch
new file mode 100644
index 0000000000..9291dc5552
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/211-input-add-axp20x-power-enable-key-support.patch
@@ -0,0 +1,339 @@
+From 656b9ff9781aa3ffeb4231f32dfc545c92d04a12 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Sat, 1 Mar 2014 17:45:49 +0100
+Subject: [PATCH] input: misc: Add driver for AXP20x Power Enable Key
+
+This patch add support for the Power Enable Key found on MFD AXP202 and
+AXP209. Besides the basic support for the button, the driver adds two
+entries in sysfs to configure the time delay for power on/off.
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+---
+ arch/arm/configs/sunxi_defconfig | 2 +
+ drivers/input/misc/Kconfig | 11 ++
+ drivers/input/misc/Makefile | 1 +
+ drivers/input/misc/axp20x-pek.c | 265 +++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 279 insertions(+)
+ create mode 100644 drivers/input/misc/axp20x-pek.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index d25660d..3ed7023 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -40,6 +40,8 @@ CONFIG_SUN4I_EMAC=y
+ # CONFIG_NET_VENDOR_STMICRO is not set
+ # CONFIG_NET_VENDOR_WIZNET is not set
+ # CONFIG_WLAN is not set
++CONFIG_INPUT_MISC=y
++CONFIG_INPUT_AXP20X_PEK=y
+ CONFIG_SERIAL_8250=y
+ CONFIG_SERIAL_8250_CONSOLE=y
+ CONFIG_SERIAL_8250_NR_UARTS=8
+diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
+index 7904ab0..87244fb 100644
+--- a/drivers/input/misc/Kconfig
++++ b/drivers/input/misc/Kconfig
+@@ -393,6 +393,17 @@ config INPUT_RETU_PWRBUTTON
+ To compile this driver as a module, choose M here. The module will
+ be called retu-pwrbutton.
+
++config INPUT_AXP20X_PEK
++ tristate "X-Powers AXP20X power button driver"
++ depends on MFD_AXP20X
++ help
++ Say Y here if you want to enable power key reporting via the
++ AXP20X PMIC.
++
++ To compile this driver as a module, choose M here. The module will
++ be called axp20x-pek.
++
++
+ config INPUT_TWL4030_PWRBUTTON
+ tristate "TWL4030 Power button Driver"
+ depends on TWL4030_CORE
+diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
+index cda71fc..624abf5 100644
+--- a/drivers/input/misc/Makefile
++++ b/drivers/input/misc/Makefile
+@@ -50,6 +50,7 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
+ obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
+ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
+ obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
++obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
+ obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
+ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+ obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
+diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
+new file mode 100644
+index 0000000..799275d
+--- /dev/null
++++ b/drivers/input/misc/axp20x-pek.c
+@@ -0,0 +1,265 @@
++/*
++ * axp20x power button driver.
++ *
++ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
++ *
++ * This file is subject to the terms and conditions of the GNU General
++ * Public License. See the file "COPYING" in the main directory of this
++ * archive for more details.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/errno.h>
++#include <linux/irq.h>
++#include <linux/init.h>
++#include <linux/input.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/mfd/axp20x.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/regmap.h>
++#include <linux/slab.h>
++
++#define AXP20X_PEK_STARTUP_MASK (0xc0)
++#define AXP20X_PEK_SHUTDOWN_MASK (0x03)
++
++static const char const *startup_time[] = { "128mS", "3S" , "1S", "2S" };
++static const char const *shutdown_time[] = { "4S", "6S" , "8S", "10S" };
++
++struct axp20x_pek {
++ struct axp20x_dev *axp20x;
++ struct input_dev *input;
++ int irq_dbr;
++ int irq_dbf;
++};
++
++struct axp20x_pek_ext_attr {
++ const char const **str;
++ unsigned int mask;
++};
++
++static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
++ .str = startup_time,
++ .mask = AXP20X_PEK_STARTUP_MASK,
++};
++
++static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
++ .str = shutdown_time,
++ .mask = AXP20X_PEK_SHUTDOWN_MASK,
++};
++
++static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr)
++{
++ return container_of(attr, struct dev_ext_attribute, attr)->var;
++}
++
++ssize_t axp20x_show_ext_attr(struct device *dev, struct device_attribute *attr,
++ char *buf)
++{
++ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
++ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
++ unsigned int val;
++ int ret, i;
++ int cnt = 0;
++
++ ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
++ if (ret != 0)
++ return ret;
++
++ val &= axp20x_ea->mask;
++ val >>= ffs(axp20x_ea->mask) - 1;
++
++ for (i = 0; i < 4; i++) {
++ if (val == i)
++ cnt += sprintf(buf + cnt, "[%s] ", axp20x_ea->str[i]);
++ else
++ cnt += sprintf(buf + cnt, "%s ", axp20x_ea->str[i]);
++ }
++
++ cnt += sprintf(buf + cnt, "\n");
++
++ return cnt;
++}
++
++ssize_t axp20x_store_ext_attr(struct device *dev, struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
++ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
++ char val_str[20];
++ int ret, i;
++ size_t len;
++
++ val_str[sizeof(val_str) - 1] = '\0';
++ strncpy(val_str, buf, sizeof(val_str) - 1);
++ len = strlen(val_str);
++
++ if (len && val_str[len - 1] == '\n')
++ val_str[len - 1] = '\0';
++
++ for (i = 0; i < 4; i++) {
++ if (!strcmp(val_str, axp20x_ea->str[i])) {
++ ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
++ AXP20X_PEK_KEY,
++ axp20x_ea->mask, i);
++ if (ret != 0)
++ return -EINVAL;
++ return count;
++ }
++ }
++
++ return -EINVAL;
++}
++
++static struct dev_ext_attribute axp20x_dev_attr_startup = {
++ .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
++ .var = &axp20x_pek_startup_ext_attr
++};
++
++static struct dev_ext_attribute axp20x_dev_attr_shutdown = {
++ __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
++ &axp20x_pek_shutdown_ext_attr
++};
++
++static struct attribute *dev_attrs[] = {
++ &axp20x_dev_attr_startup.attr.attr,
++ &axp20x_dev_attr_shutdown.attr.attr,
++ NULL,
++};
++
++static struct attribute_group dev_attr_group = {
++ .attrs = dev_attrs,
++};
++
++static const struct attribute_group *dev_attr_groups[] = {
++ &dev_attr_group,
++ NULL,
++};
++
++static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
++{
++ struct input_dev *idev = pwr;
++ struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
++
++ if (irq == axp20x_pek->irq_dbr)
++ input_report_key(idev, KEY_POWER, true);
++ else if (irq == axp20x_pek->irq_dbf)
++ input_report_key(idev, KEY_POWER, false);
++
++ input_sync(idev);
++
++ return IRQ_HANDLED;
++}
++
++static int axp20x_pek_probe(struct platform_device *pdev)
++{
++ struct axp20x_pek *axp20x_pek;
++ struct axp20x_dev *axp20x;
++ struct input_dev *idev;
++ int error;
++
++ axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
++ GFP_KERNEL);
++ if (!axp20x_pek)
++ return -ENOMEM;
++
++ axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
++ axp20x = axp20x_pek->axp20x;
++
++ axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
++ if (axp20x_pek->irq_dbr < 0) {
++ dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
++ axp20x_pek->irq_dbr);
++ return axp20x_pek->irq_dbr;
++ }
++ axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
++ axp20x_pek->irq_dbr);
++
++ axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
++ if (axp20x_pek->irq_dbf < 0) {
++ dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
++ axp20x_pek->irq_dbf);
++ return axp20x_pek->irq_dbf;
++ }
++ axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
++ axp20x_pek->irq_dbf);
++
++ axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
++ if (!axp20x_pek->input)
++ return -ENOMEM;
++
++ idev = axp20x_pek->input;
++
++ idev->name = "axp20x-pek";
++ idev->phys = "m1kbd/input2";
++ idev->dev.parent = &pdev->dev;
++
++ input_set_capability(idev, EV_KEY, KEY_POWER);
++
++ input_set_drvdata(idev, axp20x_pek);
++
++ error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbr,
++ NULL, axp20x_pek_irq, 0,
++ "axp20x-pek-dbr", idev);
++ if (error) {
++ dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
++ axp20x_pek->irq_dbr, error);
++
++ return error;
++ }
++
++ error = devm_request_threaded_irq(&pdev->dev, axp20x_pek->irq_dbf,
++ NULL, axp20x_pek_irq, 0,
++ "axp20x-pek-dbf", idev);
++ if (error) {
++ dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
++ axp20x_pek->irq_dbf, error);
++ return error;
++ }
++
++ idev->dev.groups = dev_attr_groups;
++ error = input_register_device(idev);
++ if (error) {
++ dev_err(axp20x->dev, "Can't register input device: %d\n", error);
++ return error;
++ }
++
++ platform_set_drvdata(pdev, axp20x_pek);
++
++ return 0;
++}
++
++static int axp20x_pek_remove(struct platform_device *pdev)
++{
++ struct axp20x_pek *axp20x_pek = platform_get_drvdata(pdev);
++
++ input_unregister_device(axp20x_pek->input);
++
++ return 0;
++}
++
++static const struct of_device_id axp20x_pek_match[] = {
++ { .compatible = "x-powers,axp20x-pek", },
++ { /* sentinel */ },
++};
++MODULE_DEVICE_TABLE(of, axp20x_pek_match);
++
++static struct platform_driver axp20x_pek_driver = {
++ .probe = axp20x_pek_probe,
++ .remove = axp20x_pek_remove,
++ .driver = {
++ .name = "axp20x-pek",
++ .owner = THIS_MODULE,
++ .of_match_table = axp20x_pek_match,
++ },
++};
++module_platform_driver(axp20x_pek_driver);
++
++MODULE_DESCRIPTION("axp20x Power Button");
++MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
++MODULE_LICENSE("GPL");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/212-regulator-add-axp20x-regulator-support.patch b/target/linux/sunxi/patches-3.14/212-regulator-add-axp20x-regulator-support.patch
new file mode 100644
index 0000000000..d7f4dcfe60
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/212-regulator-add-axp20x-regulator-support.patch
@@ -0,0 +1,414 @@
+From c3af279a9031b3375d3e5a684619c1adbbe30da9 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Sat, 1 Mar 2014 17:45:51 +0100
+Subject: [PATCH] regulator: AXP20x: Add support for regulators subsystem
+
+AXP202 and AXP209 come with two synchronous step-down DC-DCs and five
+LDOs. This patch introduces basic support for those regulators.
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+---
+ arch/arm/configs/sunxi_defconfig | 1 +
+ drivers/regulator/Kconfig | 7 +
+ drivers/regulator/Makefile | 1 +
+ drivers/regulator/axp20x-regulator.c | 349 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 358 insertions(+)
+ create mode 100644 drivers/regulator/axp20x-regulator.c
+
+diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
+index 3ed7023..6e305da 100644
+--- a/arch/arm/configs/sunxi_defconfig
++++ b/arch/arm/configs/sunxi_defconfig
+@@ -72,3 +72,4 @@ CONFIG_NFS_FS=y
+ CONFIG_ROOT_NFS=y
+ CONFIG_NLS=y
+ CONFIG_PRINTK_TIME=y
++CONFIG_REGULATOR_AXP20X=y
+diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
+index 6a79328..9f3bc48 100644
+--- a/drivers/regulator/Kconfig
++++ b/drivers/regulator/Kconfig
+@@ -139,6 +139,13 @@ config REGULATOR_AS3722
+ AS3722 PMIC. This will enable support for all the software
+ controllable DCDC/LDO regulators.
+
++config REGULATOR_AXP20X
++ tristate "X-POWERS AXP20X PMIC Regulators"
++ depends on MFD_AXP20X
++ help
++ This driver provides support for the voltage regulators on the
++ AXP20X PMIC.
++
+ config REGULATOR_DA903X
+ tristate "Dialog Semiconductor DA9030/DA9034 regulators"
+ depends on PMIC_DA903X
+diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
+index 979f9dd..1dd084a 100644
+--- a/drivers/regulator/Makefile
++++ b/drivers/regulator/Makefile
+@@ -20,6 +20,7 @@ obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
+ obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
+ obj-$(CONFIG_REGULATOR_AS3711) += as3711-regulator.o
+ obj-$(CONFIG_REGULATOR_AS3722) += as3722-regulator.o
++obj-$(CONFIG_REGULATOR_AXP20X) += axp20x-regulator.o
+ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
+ obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
+ obj-$(CONFIG_REGULATOR_DA9055) += da9055-regulator.o
+diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
+new file mode 100644
+index 0000000..9072f2f
+--- /dev/null
++++ b/drivers/regulator/axp20x-regulator.c
+@@ -0,0 +1,349 @@
++/*
++ * axp20x regulators driver.
++ *
++ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
++ *
++ * This file is subject to the terms and conditions of the GNU General
++ * Public License. See the file "COPYING" in the main directory of this
++ * archive for more details.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/err.h>
++#include <linux/platform_device.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/regulator/driver.h>
++#include <linux/regulator/of_regulator.h>
++#include <linux/mfd/axp20x.h>
++#include <linux/regmap.h>
++
++#define AXP20X_IO_ENABLED (0x03)
++
++#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
++#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
++
++#define AXP20X_FREQ_DCDC_MASK (0x0f)
++
++struct axp20x_regulators {
++ struct regulator_desc rdesc[AXP20X_REG_ID_MAX];
++ struct regulator_dev *rdev[AXP20X_REG_ID_MAX];
++ struct axp20x_dev *axp20x;
++};
++
++#define AXP20X_DESC(_id, _min, _max, _step, _vreg, _vmask, _ereg, _emask) \
++ [AXP20X_##_id] = { \
++ .name = #_id, \
++ .type = REGULATOR_VOLTAGE, \
++ .id = AXP20X_##_id, \
++ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
++ .owner = THIS_MODULE, \
++ .min_uV = (_min) * 1000, \
++ .uV_step = (_step) * 1000, \
++ .vsel_reg = (_vreg), \
++ .vsel_mask = (_vmask), \
++ .enable_reg = (_ereg), \
++ .enable_mask = (_emask), \
++ .ops = &axp20x_ops, \
++ }
++
++#define AXP20X_DESC_IO(_id, _min, _max, _step, _vreg, _vmask, _ereg, _emask) \
++ [AXP20X_##_id] = { \
++ .name = #_id, \
++ .type = REGULATOR_VOLTAGE, \
++ .id = AXP20X_##_id, \
++ .n_voltages = (((_max) - (_min)) / (_step) + 1), \
++ .owner = THIS_MODULE, \
++ .min_uV = (_min) * 1000, \
++ .uV_step = (_step) * 1000, \
++ .vsel_reg = (_vreg), \
++ .vsel_mask = (_vmask), \
++ .enable_reg = (_ereg), \
++ .enable_mask = (_emask), \
++ .ops = &axp20x_ops_io, \
++ }
++
++#define AXP20X_DESC_FIXED(_id, _volt) \
++ [AXP20X_##_id] = { \
++ .name = #_id, \
++ .type = REGULATOR_VOLTAGE, \
++ .id = AXP20X_##_id, \
++ .n_voltages = 1, \
++ .owner = THIS_MODULE, \
++ .min_uV = (_volt) * 1000, \
++ .ops = &axp20x_ops, \
++ }
++
++#define AXP20X_DESC_TABLE(_id, _table, _vreg, _vmask, _ereg, _emask) \
++ [AXP20X_##_id] = { \
++ .name = #_id, \
++ .type = REGULATOR_VOLTAGE, \
++ .id = AXP20X_##_id, \
++ .n_voltages = ARRAY_SIZE(_table), \
++ .owner = THIS_MODULE, \
++ .vsel_reg = (_vreg), \
++ .vsel_mask = (_vmask), \
++ .enable_reg = (_ereg), \
++ .enable_mask = (_emask), \
++ .volt_table = (_table), \
++ .ops = &axp20x_ops_table, \
++ }
++
++static int axp20x_ldo4_data[] = { 1250000, 1300000, 1400000, 1500000, 1600000, 1700000,
++ 1800000, 1900000, 2000000, 2500000, 2700000, 2800000,
++ 3000000, 3100000, 3200000, 3300000 };
++
++static int axp20x_set_suspend_voltage(struct regulator_dev *rdev, int uV)
++{
++ return regulator_set_voltage_sel_regmap(rdev, 0);
++}
++
++static int axp20x_io_enable_regmap(struct regulator_dev *rdev)
++{
++ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
++ rdev->desc->enable_mask, AXP20X_IO_ENABLED);
++}
++
++static int axp109_io_is_enabled_regmap(struct regulator_dev *rdev)
++{
++ unsigned int val;
++ int ret;
++
++ ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, &val);
++ if (ret != 0)
++ return ret;
++
++ val &= rdev->desc->enable_mask;
++ return (val == AXP20X_IO_ENABLED);
++}
++
++static struct regulator_ops axp20x_ops_table = {
++ .set_voltage_sel = regulator_set_voltage_sel_regmap,
++ .get_voltage_sel = regulator_get_voltage_sel_regmap,
++ .list_voltage = regulator_list_voltage_table,
++ .enable = regulator_enable_regmap,
++ .disable = regulator_disable_regmap,
++ .is_enabled = regulator_is_enabled_regmap,
++ .set_suspend_enable = regulator_enable_regmap,
++ .set_suspend_disable = regulator_disable_regmap,
++ .set_suspend_voltage = axp20x_set_suspend_voltage,
++};
++
++
++static struct regulator_ops axp20x_ops = {
++ .set_voltage_sel = regulator_set_voltage_sel_regmap,
++ .get_voltage_sel = regulator_get_voltage_sel_regmap,
++ .list_voltage = regulator_list_voltage_linear,
++ .enable = regulator_enable_regmap,
++ .disable = regulator_disable_regmap,
++ .is_enabled = regulator_is_enabled_regmap,
++ .set_suspend_enable = regulator_enable_regmap,
++ .set_suspend_disable = regulator_disable_regmap,
++ .set_suspend_voltage = axp20x_set_suspend_voltage,
++};
++
++static struct regulator_ops axp20x_ops_io = {
++ .set_voltage_sel = regulator_set_voltage_sel_regmap,
++ .get_voltage_sel = regulator_get_voltage_sel_regmap,
++ .list_voltage = regulator_list_voltage_linear,
++ .enable = axp20x_io_enable_regmap,
++ .disable = regulator_disable_regmap,
++ .is_enabled = axp109_io_is_enabled_regmap,
++ .set_suspend_enable = regulator_enable_regmap,
++ .set_suspend_disable = regulator_disable_regmap,
++ .set_suspend_voltage = axp20x_set_suspend_voltage,
++};
++
++static struct regulator_desc axp20x_regulators[] = {
++ AXP20X_DESC(DCDC2, 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
++ AXP20X_PWR_OUT_CTRL, 0x10),
++ AXP20X_DESC(DCDC3, 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
++ AXP20X_PWR_OUT_CTRL, 0x02),
++ AXP20X_DESC_FIXED(LDO1, 1300),
++ AXP20X_DESC(LDO2, 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
++ AXP20X_PWR_OUT_CTRL, 0x04),
++ AXP20X_DESC(LDO3, 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
++ AXP20X_PWR_OUT_CTRL, 0x40),
++ AXP20X_DESC_TABLE(LDO4, axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
++ AXP20X_PWR_OUT_CTRL, 0x08),
++ AXP20X_DESC_IO(LDO5, 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
++ AXP20X_GPIO0_CTRL, 0x07),
++};
++
++#define AXP_MATCH(_name, _id) \
++ [AXP20X_##_id] = { \
++ .name = #_name, \
++ .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \
++ }
++
++static struct of_regulator_match axp20x_matches[] = {
++ AXP_MATCH(dcdc2, DCDC2),
++ AXP_MATCH(dcdc3, DCDC3),
++ AXP_MATCH(ldo1, LDO1),
++ AXP_MATCH(ldo2, LDO2),
++ AXP_MATCH(ldo3, LDO3),
++ AXP_MATCH(ldo4, LDO4),
++ AXP_MATCH(ldo5, LDO5),
++};
++
++static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
++{
++ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
++
++ if (dcdcfreq < 750)
++ dcdcfreq = 750;
++
++ if (dcdcfreq > 1875)
++ dcdcfreq = 1875;
++
++ dcdcfreq = (dcdcfreq - 750) / 75;
++
++ return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
++ AXP20X_FREQ_DCDC_MASK, dcdcfreq);
++}
++
++static int axp20x_regulator_parse_dt(struct platform_device *pdev)
++{
++ struct device_node *np, *regulators;
++ int ret;
++ u32 dcdcfreq;
++
++ np = of_node_get(pdev->dev.parent->of_node);
++ if (!np)
++ return 0;
++
++ regulators = of_find_node_by_name(np, "regulators");
++ if (!regulators) {
++ dev_err(&pdev->dev, "regulators node not found\n");
++ return -EINVAL;
++ }
++
++ ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
++ ARRAY_SIZE(axp20x_matches));
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
++ ret);
++ return ret;
++ }
++
++ dcdcfreq = 0x08;
++ of_property_read_u32(regulators, "dcdc-freq", &dcdcfreq);
++ ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "Error setting dcdc frequency: %d\n", ret);
++ return ret;
++ }
++
++ of_node_put(regulators);
++
++ return 0;
++}
++
++static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
++{
++ unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK;
++
++ if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
++ return -EINVAL;
++
++ if (id == AXP20X_DCDC3)
++ mask = AXP20X_WORKMODE_DCDC3_MASK;
++
++ return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
++}
++
++static int axp20x_regulator_probe(struct platform_device *pdev)
++{
++ struct axp20x_regulators *pmic;
++ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
++ struct regulator_config config = { };
++ struct regulator_init_data *init_data;
++ int ret, i;
++ u32 workmode;
++
++ ret = axp20x_regulator_parse_dt(pdev);
++ if (ret)
++ return ret;
++
++ pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
++ if (!pmic) {
++ dev_err(&pdev->dev, "Failed to alloc pmic\n");
++ return -ENOMEM;
++ }
++
++ pmic->axp20x = axp20x;
++ memcpy(pmic->rdesc, axp20x_regulators, sizeof(pmic->rdesc));
++ platform_set_drvdata(pdev, pmic);
++
++ for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
++ init_data = axp20x_matches[i].init_data;
++ if (!init_data)
++ continue;
++
++ config.dev = &pdev->dev;
++ config.init_data = init_data;
++ config.driver_data = pmic;
++ config.regmap = axp20x->regmap;
++ config.of_node = axp20x_matches[i].of_node;
++
++ pmic->rdev[i] = regulator_register(&pmic->rdesc[i], &config);
++ if (IS_ERR(pmic->rdev[i])) {
++ ret = PTR_ERR(pmic->rdev[i]);
++ dev_err(&pdev->dev, "Failed to register %s\n",
++ pmic->rdesc[i].name);
++
++ while (--i >= 0)
++ regulator_unregister(pmic->rdev[i]);
++
++ return ret;
++ }
++
++ ret = of_property_read_u32(axp20x_matches[i].of_node, "dcdc-workmode",
++ &workmode);
++ if (!ret) {
++ ret = axp20x_set_dcdc_workmode(pmic->rdev[i], i, workmode);
++ if (ret)
++ dev_err(&pdev->dev, "Failed to set workmode on %s\n",
++ pmic->rdesc[i].name);
++ }
++ }
++
++ return 0;
++}
++
++static int axp20x_regulator_remove(struct platform_device *pdev)
++{
++ struct axp20x_regulators *pmic = platform_get_drvdata(pdev);
++ int i;
++
++ for (i = 0; i < AXP20X_REG_ID_MAX; i++)
++ regulator_unregister(pmic->rdev[i]);
++
++ return 0;
++}
++
++static struct platform_driver axp20x_regulator_driver = {
++ .probe = axp20x_regulator_probe,
++ .remove = axp20x_regulator_remove,
++ .driver = {
++ .name = "axp20x-regulator",
++ .owner = THIS_MODULE,
++ },
++};
++
++static int __init axp20x_regulator_init(void)
++{
++ return platform_driver_register(&axp20x_regulator_driver);
++}
++
++subsys_initcall(axp20x_regulator_init);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
++MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/213-dt-sunxi-add-x-powers.patch b/target/linux/sunxi/patches-3.14/213-dt-sunxi-add-x-powers.patch
new file mode 100644
index 0000000000..3b37c47282
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/213-dt-sunxi-add-x-powers.patch
@@ -0,0 +1,83 @@
+From 7b42dc4ff2cca887e0c6e1ad291d65b30e64dd92 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 5 Mar 2014 20:30:41 +0100
+Subject: [PATCH] ARM: sunxi: dt: Add x-powers-axp209.dtsi file
+
+This dtsi describes the axp209 PMIC, and is to be included from inside
+the i2c controller node to which the axp209 is connected.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/x-powers-axp209.dtsi | 60 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 60 insertions(+)
+ create mode 100644 arch/arm/boot/dts/x-powers-axp209.dtsi
+
+diff --git a/arch/arm/boot/dts/x-powers-axp209.dtsi b/arch/arm/boot/dts/x-powers-axp209.dtsi
+new file mode 100644
+index 0000000..118ce3a1
+--- /dev/null
++++ b/arch/arm/boot/dts/x-powers-axp209.dtsi
+@@ -0,0 +1,60 @@
++/*
++ * x-powers,axp209 common code to be include from inside the axp209 node
++ *
++ * Copyright 2014 - Carlo Caione <carlo@caione.org>
++ *
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++ compatible = "x-powers,axp209";
++ interrupt-controller;
++ #interrupt-cells = <1>;
++
++ regulators {
++ dcdc-freq = "8";
++
++ axp_dcdc2: dcdc2 {
++ regulator-min-microvolt = <700000>;
++ regulator-max-microvolt = <2275000>;
++ dcdc-workmode = <0>;
++ regulator-always-on;
++ };
++
++ axp_dcdc3: dcdc3 {
++ regulator-min-microvolt = <700000>;
++ regulator-max-microvolt = <3500000>;
++ dcdc-workmode = <0>;
++ regulator-always-on;
++ };
++
++ axp_ldo1: ldo1 {
++ regulator-min-microvolt = <1300000>;
++ regulator-max-microvolt = <1300000>;
++ };
++
++ axp_ldo2: ldo2 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-always-on;
++ };
++
++ axp_ldo3: ldo3 {
++ regulator-min-microvolt = <700000>;
++ regulator-max-microvolt = <3500000>;
++ };
++
++ axp_ldo4: ldo4 {
++ regulator-min-microvolt = <1250000>;
++ regulator-max-microvolt = <3300000>;
++ };
++
++ axp_ldo5: ldo5 {
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ };
++ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/214-1-dt-sun7i-add-axp209-to-cubieboard2.patch b/target/linux/sunxi/patches-3.14/214-1-dt-sun7i-add-axp209-to-cubieboard2.patch
new file mode 100644
index 0000000000..a7d9c17cab
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/214-1-dt-sun7i-add-axp209-to-cubieboard2.patch
@@ -0,0 +1,40 @@
+From c792a05efcfebcf94ba925135a778961700965f5 Mon Sep 17 00:00:00 2001
+From: Carlo Caione <carlo@caione.org>
+Date: Sat, 1 Mar 2014 17:45:48 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add AXP209 support to the cubieboard2
+
+AXP209 is the PMU used by Cubieboard2. This patch enables the AXP209
+support in the dts file.
+
+This patch requires: "ARM: sun7i/sun6i: irqchip: Add irqchip driver for
+NMI controller"
+
+Signed-off-by: Carlo Caione <carlo@caione.org>
+---
+ arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+index cd9d3c2..40e9c3a 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+@@ -74,6 +74,16 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupt-parent = <&nmi_intc>;
++ interrupts = <0 8>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+
+ i2c1: i2c@01c2b000 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/214-2-dt-sun4i-add-axp209-to-boards.patch b/target/linux/sunxi/patches-3.14/214-2-dt-sun4i-add-axp209-to-boards.patch
new file mode 100644
index 0000000000..43fba1abf9
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/214-2-dt-sun4i-add-axp209-to-boards.patch
@@ -0,0 +1,159 @@
+From d14c5523653ca6ce9f1487922c8ab4e571d17b62 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Tue, 11 Mar 2014 16:51:44 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add AXP209 support to various boards
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10-a1000.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-hackberry.dts | 15 +++++++++++++++
+ arch/arm/boot/dts/sun4i-a10-inet97fv2.dts | 9 +++++++++
+ arch/arm/boot/dts/sun4i-a10-mini-xplus.dts | 15 +++++++++++++++
+ arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts | 15 +++++++++++++++
+ arch/arm/boot/dts/sun4i-a10-pcduino.dts | 9 +++++++++
+ 7 files changed, 81 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
+index 68b687e..99f53c0 100644
+--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
++++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
+@@ -96,6 +96,15 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+ };
+
+diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+index 13088f0..5e4986c 100644
+--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
++++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+@@ -88,6 +88,15 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+
+ i2c1: i2c@01c2b000 {
+diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+index a4b05d6..18f0030 100644
+--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
++++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+@@ -91,6 +91,21 @@
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
++
++ i2c0: i2c@01c2ac00 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins_a>;
++ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
++ };
+ };
+
+ reg_emac_3v3: emac-3v3 {
+diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+index b73a070..7d3599e 100644
+diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+index c906171..4acddf7 100644
+--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
++++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+@@ -55,6 +55,21 @@
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
++
++ i2c0: i2c@01c2ac00 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins_a>;
++ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
++ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+index e5a2765..2ce7267 100644
+--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
++++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+@@ -90,6 +90,21 @@
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
++
++ i2c0: i2c@01c2ac00 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins_a>;
++ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
++ };
+ };
+
+ leds {
+diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+index 2820229..817cdca 100644
+--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
++++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+@@ -74,6 +74,15 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupts = <0>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+ };
+
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/214-3-dt-sun7i-add-axp209-to-cubietruck.patch b/target/linux/sunxi/patches-3.14/214-3-dt-sun7i-add-axp209-to-cubietruck.patch
new file mode 100644
index 0000000000..af8ca023ea
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/214-3-dt-sun7i-add-axp209-to-cubietruck.patch
@@ -0,0 +1,56 @@
+From 886f41537ad5e873caee522704e96e844a485961 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 5 Mar 2014 20:41:17 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add AXP209 support to cubietruck
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 10 ++++++++++
+ arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts | 10 ++++++++++
+ 2 files changed, 20 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index 9a127d1..ebf6a2f 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -137,6 +137,16 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupt-parent = <&nmi_intc>;
++ interrupts = <0 8>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+
+ i2c1: i2c@01c2b000 {
+diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+index 15f1f3f..926f111 100644
+--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
++++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+@@ -127,6 +127,16 @@
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
++
++ axp: axp20x@34 {
++ reg = <0x34>;
++ interrupt-parent = <&nmi_intc>;
++ interrupts = <0 8>;
++
++ axp,system-power-controller;
++
++ /include/ "x-powers-axp209.dtsi"
++ };
+ };
+
+ i2c1: i2c@01c2b000 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/215-2-dt-sun5i-add-address-and-sizecells-to-i2c.patch b/target/linux/sunxi/patches-3.14/215-2-dt-sun5i-add-address-and-sizecells-to-i2c.patch
new file mode 100644
index 0000000000..5f79073e92
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/215-2-dt-sun5i-add-address-and-sizecells-to-i2c.patch
@@ -0,0 +1,45 @@
+From 505ad20db47442ae2650a41eca0a7a869aace789 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 5 Mar 2014 20:40:44 +0100
+Subject: [PATCH] ARM: sun5i: dt: Add address- and size-cells info to i2c
+ controller nodes
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun5i-a13.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
+index 280ffee..68ab353 100644
+--- a/arch/arm/boot/dts/sun5i-a13.dtsi
++++ b/arch/arm/boot/dts/sun5i-a13.dtsi
+@@ -503,6 +503,8 @@
+ clocks = <&apb1_gates 0>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+@@ -512,6 +514,8 @@
+ clocks = <&apb1_gates 1>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+@@ -521,6 +525,8 @@
+ clocks = <&apb1_gates 2>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ timer@01c60000 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/215-3-dt-sun7i-add-address-and-sizecells-to-i2c.patch b/target/linux/sunxi/patches-3.14/215-3-dt-sun7i-add-address-and-sizecells-to-i2c.patch
new file mode 100644
index 0000000000..a699644466
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/215-3-dt-sun7i-add-address-and-sizecells-to-i2c.patch
@@ -0,0 +1,63 @@
+From 338560ad44f2e8b6f4eb095567830b6c78b35ba2 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 5 Mar 2014 20:40:57 +0100
+Subject: [PATCH] ARM: sun7i: dt: Add address- and size-cells info to i2c
+ controller nodes
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 2e66c85..15ea85e 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -848,6 +848,8 @@
+ clocks = <&apb1_gates 0>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+@@ -857,6 +859,8 @@
+ clocks = <&apb1_gates 1>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+@@ -866,6 +870,8 @@
+ clocks = <&apb1_gates 2>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c3: i2c@01c2b800 {
+@@ -875,6 +881,8 @@
+ clocks = <&apb1_gates 3>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c4: i2c@01c2bc00 {
+@@ -884,6 +892,8 @@
+ clocks = <&apb1_gates 15>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ gmac: ethernet@01c50000 {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/215-dt-sun4i-add-address-and-sizecells-to-i2c.patch b/target/linux/sunxi/patches-3.14/215-dt-sun4i-add-address-and-sizecells-to-i2c.patch
new file mode 100644
index 0000000000..c8c8ae1be6
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/215-dt-sun4i-add-address-and-sizecells-to-i2c.patch
@@ -0,0 +1,45 @@
+From 46d3d005e5f91d8221676cbb6307e790d4b63345 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 5 Mar 2014 20:40:26 +0100
+Subject: [PATCH] ARM: sun4i: dt: Add address- and size-cells info to i2c
+ controller nodes
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 4b90a18..2a705e7 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -712,6 +712,8 @@
+ clocks = <&apb1_gates 0>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c1: i2c@01c2b000 {
+@@ -721,6 +723,8 @@
+ clocks = <&apb1_gates 1>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+
+ i2c2: i2c@01c2b400 {
+@@ -730,6 +734,8 @@
+ clocks = <&apb1_gates 2>;
+ clock-frequency = <100000>;
+ status = "disabled";
++ #address-cells = <1>;
++ #size-cells = <0>;
+ };
+ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/216-dt-sun7i-add-i2c-to-cubietruck.patch b/target/linux/sunxi/patches-3.14/216-dt-sun7i-add-i2c-to-cubietruck.patch
new file mode 100644
index 0000000000..1e972d83ca
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/216-dt-sun7i-add-i2c-to-cubietruck.patch
@@ -0,0 +1,48 @@
+From 6267355f0e513bed9a5009924abc7a1e7de22ab3 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Mon, 6 Jan 2014 13:58:12 +0800
+Subject: [PATCH] arm: sun7i: cubietruck: Enable the i2c controllers
+
+The Cubietruck makes use of the first three i2c controllers found on the
+Allwinner A20; i2c-0 is used internally for the PMIC, i2c-1 is exposed on
+the board headers, and i2c-2 is used for DDC on the VGA connector. This
+patch enables them in the device tree.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index 8a1009d..f9dcb61 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -33,6 +33,24 @@
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
++
++ i2c0: i2c@01c2ac00 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c0_pins_a>;
++ status = "okay";
++ };
++
++ i2c1: i2c@01c2b000 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c1_pins_a>;
++ status = "okay";
++ };
++
++ i2c2: i2c@01c2b400 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&i2c2_pins_a>;
++ status = "okay";
++ };
+ };
+
+ leds {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/220-clk-sunxi-remove-calls-to-clk_put.patch b/target/linux/sunxi/patches-3.14/220-clk-sunxi-remove-calls-to-clk_put.patch
new file mode 100644
index 0000000000..9d87e88a38
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/220-clk-sunxi-remove-calls-to-clk_put.patch
@@ -0,0 +1,41 @@
+From 81b745ee30dc7cd230f924f6263879f1b7ffbc0c Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 13 Mar 2014 16:14:13 +0100
+Subject: [PATCH] clk: sunxi: Remove calls to clk_put
+
+Callers of clk_put must disable the clock first. This also means that as long
+as the clock is enabled the driver should hold a reference to that clock.
+Hence, the call to clk_put here are bogus and should be removed.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ drivers/clk/sunxi/clk-sunxi.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
+index 9afd8dd..a10a645 100644
+--- a/drivers/clk/sunxi/clk-sunxi.c
++++ b/drivers/clk/sunxi/clk-sunxi.c
+@@ -1325,17 +1325,13 @@ static void __init sunxi_clock_protect(void)
+
+ /* memory bus clock - sun5i+ */
+ clk = clk_get(NULL, "mbus");
+- if (!IS_ERR(clk)) {
++ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+- clk_put(clk);
+- }
+
+ /* DDR clock - sun4i+ */
+ clk = clk_get(NULL, "pll5_ddr");
+- if (!IS_ERR(clk)) {
++ if (!IS_ERR(clk))
+ clk_prepare_enable(clk);
+- clk_put(clk);
+- }
+ }
+
+ static void __init sunxi_init_clocks(void)
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/230-net-rfkill-changes.patch b/target/linux/sunxi/patches-3.14/230-net-rfkill-changes.patch
new file mode 100644
index 0000000000..ca71a915a8
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/230-net-rfkill-changes.patch
@@ -0,0 +1,271 @@
+From 5f6f6af41e39677c9b722376a4088d10732cdd44 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 17 Jan 2014 14:47:26 +0800
+Subject: [PATCH] net: rfkill: gpio: fix gpio name buffer size off by 1
+
+snprintf should be passed the complete size of the buffer, including
+the space for '\0'. The previous code resulted in the *_reset and
+*_shutdown strings being truncated.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ net/rfkill/rfkill-gpio.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index bd2a5b9..97ec12a 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -117,8 +117,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
+ if (!rfkill->shutdown_name)
+ return -ENOMEM;
+
+- snprintf(rfkill->reset_name, len + 6 , "%s_reset", rfkill->name);
+- snprintf(rfkill->shutdown_name, len + 9, "%s_shutdown", rfkill->name);
++ snprintf(rfkill->reset_name, len + 7 , "%s_reset", rfkill->name);
++ snprintf(rfkill->shutdown_name, len + 10, "%s_shutdown", rfkill->name);
+
+ rfkill->clk = devm_clk_get(&pdev->dev, clk_name);
+
+--
+2.0.3
+
+From d91c313c08167978c3fb20b327b6a7abb7b00ffd Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 17 Jan 2014 14:47:27 +0800
+Subject: [PATCH] net: rfkill: gpio: use
+ clk_prepare_enable/clk_disable_unprepare
+
+rfkill-gpio calls clk_enable() without first calling clk_prepare(),
+resulting in a warning and no effect. Switch to clk_prepare_enable()
+and clk_disable_unprepare.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ net/rfkill/rfkill-gpio.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index 97ec12a..c7081b7 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -51,10 +51,10 @@ static int rfkill_gpio_set_power(void *data, bool blocked)
+ gpiod_set_value(rfkill->shutdown_gpio, 0);
+ gpiod_set_value(rfkill->reset_gpio, 0);
+ if (!IS_ERR(rfkill->clk) && rfkill->clk_enabled)
+- clk_disable(rfkill->clk);
++ clk_disable_unprepare(rfkill->clk);
+ } else {
+ if (!IS_ERR(rfkill->clk) && !rfkill->clk_enabled)
+- clk_enable(rfkill->clk);
++ clk_prepare_enable(rfkill->clk);
+ gpiod_set_value(rfkill->reset_gpio, 1);
+ gpiod_set_value(rfkill->shutdown_gpio, 1);
+ }
+--
+2.0.3
+
+From f6dc85e22d3215a26f509fb5b34ca34c56a0d8b4 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 17 Jan 2014 14:47:28 +0800
+Subject: [PATCH] net: rfkill: gpio: fix reversed clock enable state
+
+rfkill-gpio has clk_enabled = blocked, which is true when rfkill
+blocks the device. This results in calling clock enable/disable at
+the wrong time. Reversing the value fixes this.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ net/rfkill/rfkill-gpio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index c7081b7..3084fa3 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -59,7 +59,7 @@ static int rfkill_gpio_set_power(void *data, bool blocked)
+ gpiod_set_value(rfkill->shutdown_gpio, 1);
+ }
+
+- rfkill->clk_enabled = blocked;
++ rfkill->clk_enabled = !blocked;
+
+ return 0;
+ }
+--
+2.0.3
+
+From 57301a41d4a82902e967f6bd9f09ba6ca31fcbed Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 17 Jan 2014 14:47:29 +0800
+Subject: [PATCH] net: rfkill: gpio: add device tree support
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ .../devicetree/bindings/rfkill/rfkill-gpio.txt | 26 ++++++++++++++++++++++
+ net/rfkill/rfkill-gpio.c | 23 +++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
+
+diff --git a/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt b/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
+new file mode 100644
+index 0000000..8a07ea4
+--- /dev/null
++++ b/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
+@@ -0,0 +1,26 @@
++GPIO controlled RFKILL devices
++
++Required properties:
++- compatible : Must be "rfkill-gpio".
++- rfkill-name : Name of RFKILL device
++- rfkill-type : Type of RFKILL device: 1 for WiFi, 2 for BlueTooth
++- NAME_shutdown-gpios : GPIO phandle to shutdown control
++ (phandle must be the second)
++- NAME_reset-gpios : GPIO phandle to reset control
++
++NAME must match the rfkill-name property. NAME_shutdown-gpios or
++NAME_reset-gpios, or both, must be defined.
++
++Optional properties:
++- clocks : phandle to clock to enable/disable
++
++Example:
++
++ rfkill_bt: rfkill@0 {
++ compatible = "rfkill-gpio";
++ rfkill-name = "bluetooth";
++ rfkill-type = <2>;
++ bluetooth_shutdown-gpios = <0>, <&pio 7 18 0>;
++ bluetooth_reset-gpios = <&pio 7 24 0>;
++ clocks = <&clk_out_a>;
++ };
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index 3084fa3..48381a8 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -26,6 +26,7 @@
+ #include <linux/slab.h>
+ #include <linux/acpi.h>
+ #include <linux/gpio/consumer.h>
++#include <linux/of_gpio.h>
+
+ #include <linux/rfkill-gpio.h>
+
+@@ -83,6 +84,18 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
+ return 0;
+ }
+
++static int rfkill_gpio_dt_probe(struct device *dev,
++ struct rfkill_gpio_data *rfkill)
++{
++ struct device_node * np = dev->of_node;
++
++ rfkill->name = np->name;
++ of_property_read_string(np, "rfkill-name", &rfkill->name);
++ of_property_read_u32(np, "rfkill-type", &rfkill->type);
++
++ return 0;
++}
++
+ static int rfkill_gpio_probe(struct platform_device *pdev)
+ {
+ struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
+@@ -100,6 +113,10 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
+ ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
+ if (ret)
+ return ret;
++ } else if (&pdev->dev.of_node) {
++ ret = rfkill_gpio_dt_probe(&pdev->dev, rfkill);
++ if (ret)
++ return ret;
+ } else if (pdata) {
+ clk_name = pdata->power_clk_name;
+ rfkill->name = pdata->name;
+@@ -189,6 +206,11 @@ static const struct acpi_device_id rfkill_acpi_match[] = {
+ { },
+ };
+
++static const struct of_device_id rfkill_of_match[] = {
++ { .compatible = "rfkill-gpio", },
++ {},
++};
++
+ static struct platform_driver rfkill_gpio_driver = {
+ .probe = rfkill_gpio_probe,
+ .remove = rfkill_gpio_remove,
+@@ -196,6 +218,7 @@ static struct platform_driver rfkill_gpio_driver = {
+ .name = "rfkill_gpio",
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(rfkill_acpi_match),
++ .of_match_table = of_match_ptr(rfkill_of_match),
+ },
+ };
+
+--
+2.0.3
+
+From 83c43937ee8c5fcb38241a8e89c2b93e5b0f9526 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Fri, 17 Jan 2014 14:47:30 +0800
+Subject: [PATCH] net: rfkill: gpio: add clock-frequency device tree property
+
+Some devices, such as Broadcom Bluetooth devices, require a specific
+clock rate for the clock tied to the rfkill device. Add clock-frequency
+property so we can specify this from the device tree.
+
+Signed-off-by: Chen-Yu Tsai <wens@csie.org>
+---
+ Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt | 2 ++
+ net/rfkill/rfkill-gpio.c | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt b/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
+index 8a07ea4..8b8db0a 100644
+--- a/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
++++ b/Documentation/devicetree/bindings/rfkill/rfkill-gpio.txt
+@@ -13,6 +13,7 @@ NAME_reset-gpios, or both, must be defined.
+
+ Optional properties:
+ - clocks : phandle to clock to enable/disable
++- clock-frequency : clock rate to set for the given clock
+
+ Example:
+
+@@ -23,4 +24,5 @@ Example:
+ bluetooth_shutdown-gpios = <0>, <&pio 7 18 0>;
+ bluetooth_reset-gpios = <&pio 7 24 0>;
+ clocks = <&clk_out_a>;
++ clock-frequency = <32678>;
+ };
+diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
+index 48381a8..3092681 100644
+--- a/net/rfkill/rfkill-gpio.c
++++ b/net/rfkill/rfkill-gpio.c
+@@ -40,6 +40,7 @@ struct rfkill_gpio_data {
+ char *reset_name;
+ char *shutdown_name;
+ struct clk *clk;
++ int clk_frequency;
+
+ bool clk_enabled;
+ };
+@@ -92,6 +93,7 @@ static int rfkill_gpio_dt_probe(struct device *dev,
+ rfkill->name = np->name;
+ of_property_read_string(np, "rfkill-name", &rfkill->name);
+ of_property_read_u32(np, "rfkill-type", &rfkill->type);
++ of_property_read_u32(np, "clock-frequency", &rfkill->clk_frequency);
+
+ return 0;
+ }
+@@ -138,6 +140,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
+ snprintf(rfkill->shutdown_name, len + 10, "%s_shutdown", rfkill->name);
+
+ rfkill->clk = devm_clk_get(&pdev->dev, clk_name);
++ if (!IS_ERR(rfkill->clk) && rfkill->clk_frequency > 0)
++ clk_set_rate(rfkill->clk, rfkill->clk_frequency);
+
+ gpio = devm_gpiod_get_index(&pdev->dev, rfkill->reset_name, 0);
+ if (!IS_ERR(gpio)) {
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/231-1-brcmfmac-fix-sdio-sending.patch b/target/linux/sunxi/patches-3.14/231-1-brcmfmac-fix-sdio-sending.patch
new file mode 100644
index 0000000000..8f9914fb10
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/231-1-brcmfmac-fix-sdio-sending.patch
@@ -0,0 +1,37 @@
+From df25859babd9c164a61e86d953d5c88400009a14 Mon Sep 17 00:00:00 2001
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Wed, 29 Jan 2014 15:32:16 +0100
+Subject: [PATCH] brcmfmac: fix sdio sending of large buffers.
+
+the function brcmf_sdiod_ramrw is supposed to be able to send
+large blobs of data. However inside the loop the skb->len field
+did not correctly get reset each round. As a result only small
+blobs could be sent. This patch fixes this problem.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+index fa35b23..bd19323 100644
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+@@ -827,7 +827,7 @@ brcmf_sdiod_ramrw(struct brcmf_sdio_dev *sdiodev, bool write, u32 address,
+ }
+ if (!write)
+ memcpy(data, pkt->data, dsize);
+- skb_trim(pkt, dsize);
++ skb_trim(pkt, 0);
+
+ /* Adjust for next transfer (if any) */
+ size -= dsize;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/231-2-brcmfmac-fix-use-of-skb-ctrlbuf-in-SDIO.patch b/target/linux/sunxi/patches-3.14/231-2-brcmfmac-fix-use-of-skb-ctrlbuf-in-SDIO.patch
new file mode 100644
index 0000000000..5743e66f6c
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/231-2-brcmfmac-fix-use-of-skb-ctrlbuf-in-SDIO.patch
@@ -0,0 +1,69 @@
+From 3eee5fd6d045dc744f98fd684258e3fdfa667fd6 Mon Sep 17 00:00:00 2001
+From: Arend van Spriel <arend@broadcom.com>
+Date: Tue, 25 Feb 2014 20:30:27 +0100
+Subject: [PATCH] brcmfmac: fix use of skb control buffer in SDIO driver part
+
+The SDIO driver has a 16-bit field defined in the skbuff control buffer.
+However, it is accessed as a u32 overwriting other control info. Another
+issue is that the field is not initialized for networking packets, but
+the control buffer content is unspecified as other networking layers can
+use it.
+
+Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: John W. Linville <linville@tuxdriver.com>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+index ddaa9ef..e006e7c 100644
+--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
+@@ -1955,7 +1955,7 @@ static int brcmf_sdio_txpkt_prep_sg(struct brcmf_sdio *bus,
+ memcpy(pkt_pad->data,
+ pkt->data + pkt->len - tail_chop,
+ tail_chop);
+- *(u32 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
++ *(u16 *)(pkt_pad->cb) = ALIGN_SKB_FLAG + tail_chop;
+ skb_trim(pkt, pkt->len - tail_chop);
+ skb_trim(pkt_pad, tail_pad + tail_chop);
+ __skb_queue_after(pktq, pkt, pkt_pad);
+@@ -2003,7 +2003,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
+ * already properly aligned and does not
+ * need an sdpcm header.
+ */
+- if (*(u32 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
++ if (*(u16 *)(pkt_next->cb) & ALIGN_SKB_FLAG)
+ continue;
+
+ /* align packet data pointer */
+@@ -2067,11 +2067,11 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
+ u8 *hdr;
+ u32 dat_offset;
+ u16 tail_pad;
+- u32 dummy_flags, chop_len;
++ u16 dummy_flags, chop_len;
+ struct sk_buff *pkt_next, *tmp, *pkt_prev;
+
+ skb_queue_walk_safe(pktq, pkt_next, tmp) {
+- dummy_flags = *(u32 *)(pkt_next->cb);
++ dummy_flags = *(u16 *)(pkt_next->cb);
+ if (dummy_flags & ALIGN_SKB_FLAG) {
+ chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
+ if (chop_len) {
+@@ -2554,6 +2554,8 @@ static int brcmf_sdio_bus_txdata(struct device *dev, struct sk_buff *pkt)
+
+ /* Priority based enq */
+ spin_lock_irqsave(&bus->txqlock, flags);
++ /* reset bus_flags in packet cb */
++ *(u16 *)(pkt->cb) = 0;
+ if (!brcmf_c_prec_enq(bus->sdiodev->dev, &bus->txq, pkt, prec)) {
+ skb_pull(pkt, bus->tx_hdrlen);
+ brcmf_err("out of bus->txq !!!\n");
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/232-1-dt-sun7i-add-wifi-to-cubietruck.patch b/target/linux/sunxi/patches-3.14/232-1-dt-sun7i-add-wifi-to-cubietruck.patch
new file mode 100644
index 0000000000..2e80804891
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/232-1-dt-sun7i-add-wifi-to-cubietruck.patch
@@ -0,0 +1,96 @@
+From 3e7fc7d394db0783996519f2d5affde5152a628e Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Thu, 26 Dec 2013 17:14:33 +0800
+Subject: [PATCH] ARM: dts: sun7i: add WiFi module to Cubietruck DTS
+
+The CubieTruck has an AMPAK AP6210 WiFi+Bluetooth module. The WiFi
+part is a BCM43362 IC connected to MMC2 in the A20 SoC via SDIO.
+The IC also takes a 32.768 KHz low power clock input, and a power
+enable signal via GPIO.
+
+The WiFi module supports out-of-band interrupt signaling via GPIO,
+but this is not supported in this patch.
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 47 ++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index 66bb3ef..2444806 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -28,6 +28,23 @@
+ status = "okay";
+ };
+
++ mmc3: mmc@01c12000 {
++ pinctrl-names = "default", "default";
++ pinctrl-0 = <&mmc3_pins_a>;
++ pinctrl-1 = <&wifi_host_wake_pin>;
++ vmmc-supply = <&reg_vmmc3>;
++ non-removable;
++ status = "okay";
++
++ brcmf: bcrmf@0 {
++ /* out of band interrupt not working */
++ /* compatible = "broadcom,bcm43362"; */
++ interrupt-parent = <&pio>;
++ interrupts = <10 2>; /* EINT10 */
++ status = "okay";
++ };
++ };
++
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+@@ -56,6 +73,18 @@
+ };
+
+ pinctrl@01c20800 {
++ mmc3_pins_a: mmc3@0 {
++ /* AP6210 requires pull-up */
++ allwinner,pull = <1>;
++ };
++
++ vmmc3_pin_cubietruck: vmmc3_pin@0 {
++ allwinner,pins = "PH9";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
+ ahci_pwr_pin_cubietruck: ahci_pwr_pin@1 {
+ allwinner,pins = "PH12";
+ allwinner,function = "gpio_out";
+@@ -69,6 +98,13 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ wifi_host_wake_pin: wifi_host_wake_pin@0 {
++ allwinner,pins = "PH10";
++ allwinner,function = "gpio_in";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ uart0: serial@01c28000 {
+@@ -147,4 +183,15 @@
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
++
++ reg_vmmc3: vmmc3 {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&vmmc3_pin_cubietruck>;
++ regulator-name = "vmmc3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ enable-active-high;
++ gpio = <&pio 7 9 0>;
++ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/232-2-dt-sun7i-add-bluetooth-to-cubietruck.patch b/target/linux/sunxi/patches-3.14/232-2-dt-sun7i-add-bluetooth-to-cubietruck.patch
new file mode 100644
index 0000000000..e41eb82185
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/232-2-dt-sun7i-add-bluetooth-to-cubietruck.patch
@@ -0,0 +1,78 @@
+From 7ed66f828ad1ae46226ad7c1b56466d5ae6d67b9 Mon Sep 17 00:00:00 2001
+From: Chen-Yu Tsai <wens@csie.org>
+Date: Thu, 26 Dec 2013 17:15:47 +0800
+Subject: [PATCH] ARM: dts: sun7i: add bluetooth module to CubieTruck DTS
+
+The CubieTruck has an AMPAK AP6210 WiFi+Bluetooth module. The
+Bluetooth part is a BCM20710 IC connected to UART2 in the A20
+SoC. The IC also takes a 32.768 KHz low power clock input, a power
+enable signal and a wake signal via GPIO.
+
+The Bluetooth module supports out-of-band interrupt signaling via
+GPIO, but this is not supported in this patch.
+---
+ arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 36 ++++++++++++++++++++++++++++++
+ 1 file changed, 36 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+index 2444806..9a127d1 100644
+--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
++++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+@@ -105,6 +105,20 @@
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
++
++ bt_pwr_pin: bt_pwr_pin@0 {
++ allwinner,pins = "PH18";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ bt_wake_pin: bt_wake_pin@0 {
++ allwinner,pins = "PH24";
++ allwinner,function = "gpio_out";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
+ };
+
+ uart0: serial@01c28000 {
+@@ -113,6 +127,12 @@
+ status = "okay";
+ };
+
++ uart2: serial@01c28800 {
++ pinctrl-names = "default";
++ pinctrl-0 = <&uart2_pins_a>;
++ status = "okay";
++ };
++
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+@@ -194,4 +214,20 @@
+ enable-active-high;
+ gpio = <&pio 7 9 0>;
+ };
++
++ rfkill-switches {
++ compatible = "simple-bus";
++ pinctrl-names = "default";
++
++ rfkill_bt {
++ compatible = "rfkill-gpio";
++ pinctrl-0 = <&bt_pwr_pin>, <&clk_out_a_pins_a>;
++ rfkill-name = "bt";
++ rfkill-type = <2>;
++ bt_shutdown-gpios = <0>, <&pio 7 18 0>; /* PH18 */
++ bt_reset-gpios = <&pio 7 24 0>; /* PH24 */
++ clocks = <&clk_out_a>;
++ clock-frequency = <32768>;
++ };
++ };
+ };
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/250-pwm-add-driver.patch b/target/linux/sunxi/patches-3.14/250-pwm-add-driver.patch
new file mode 100644
index 0000000000..8d77a3408e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/250-pwm-add-driver.patch
@@ -0,0 +1,376 @@
+diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
+index 5b34ff29ea38..178b017be827 100644
+--- a/drivers/pwm/Kconfig
++++ b/drivers/pwm/Kconfig
+@@ -217,6 +217,15 @@ config PWM_SPEAR
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-spear.
+
++config PWM_SUNXI
++ tristate "Allwinner PWM support"
++ depends on ARCH_SUNXI || COMPILE_TEST
++ help
++ Generic PWM framework driver for Allwinner SoCs.
++
++ To compile this driver as a module, choose M here: the module
++ will be called pwm-sunxi.
++
+ config PWM_TEGRA
+ tristate "NVIDIA Tegra PWM support"
+ depends on ARCH_TEGRA
+diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
+index e57d2c38a794..39997ea2e276 100644
+--- a/drivers/pwm/Makefile
++++ b/drivers/pwm/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
+ obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
+ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
+ obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
++obj-$(CONFIG_PWM_SUNXI) += pwm-sunxi.o
+ obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
+ obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
+ obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
+diff --git a/drivers/pwm/pwm-sunxi.c b/drivers/pwm/pwm-sunxi.c
+new file mode 100644
+index 000000000000..e7c3ca1d3c42
+--- /dev/null
++++ b/drivers/pwm/pwm-sunxi.c
+@@ -0,0 +1,338 @@
++/*
++ * Driver for Allwinner Pulse Width Modulation Controller
++ *
++ * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com>
++ *
++ * Licensed under GPLv2.
++ */
++
++#include <linux/bitops.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_device.h>
++#include <linux/platform_device.h>
++#include <linux/pwm.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/slab.h>
++
++#define PWM_CTRL_REG 0x0
++
++#define PWM_CH_PRD_BASE 0x4
++#define PWM_CH_PRD_OFF 0x4
++#define PWM_CH_PRD(x) (PWM_CH_PRD_BASE + PWM_CH_PRD_OFF * (x))
++
++#define PWMCH_OFFSET 15
++#define PWM_PRESCAL_MASK GENMASK(3, 0)
++#define PWM_PRESCAL_OFF 0
++#define PWM_EN BIT(4)
++#define PWM_ACT_STATE BIT(5)
++#define PWM_CLK_GATING BIT(6)
++#define PWM_MODE BIT(7)
++#define PWM_PULSE BIT(8)
++#define PWM_BYPASS BIT(9)
++
++#define PWM_RDY_BASE 28
++#define PWM_RDY_OFF 1
++#define PWM_RDY(x) BIT(PWM_RDY_BASE + PWM_RDY_OFF * (x))
++
++#define PWM_PRD_ACT_MASK GENMASK(7, 0)
++#define PWM_PRD(x) ((x - 1) << 16)
++#define PWM_PRD_MASK GENMASK(7, 0)
++
++#define BIT_CH(bit, chan) (bit << (chan * PWMCH_OFFSET))
++
++u32 prescal_table[] = { 120, 180, 240, 360, 480, 0, 0, 0,
++ 12000, 24000, 36000, 48000, 72000,
++ 0, 0, 1 };
++
++struct sunxi_pwm_data {
++ bool has_rdy;
++};
++
++struct sunxi_pwm_chip {
++ struct pwm_chip chip;
++ struct clk *clk;
++ void __iomem *base;
++ struct mutex ctrl_lock;
++ const struct sunxi_pwm_data *data;
++};
++
++#define to_sunxi_pwm_chip(chip) container_of(chip, struct sunxi_pwm_chip, chip)
++
++static inline u32 sunxi_pwm_readl(struct sunxi_pwm_chip *chip,
++ unsigned long offset)
++{
++ return readl(chip->base + offset);
++}
++
++static inline void sunxi_pwm_writel(struct sunxi_pwm_chip *chip,
++ unsigned long offset, unsigned long val)
++{
++ writel(val, chip->base + offset);
++}
++
++static int sunxi_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
++ int duty_ns, int period_ns)
++{
++ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
++ u32 clk_rate, prd, dty;
++ u64 div;
++ u32 val, clk_gate;
++ int i, ret;
++
++ clk_rate = clk_get_rate(sunxi_pwm->clk);
++
++ /* First, test without any divider */
++ i = PWM_PRESCAL_MASK;
++ div = clk_rate * period_ns;
++ do_div(div, 1000000000);
++ if (div > PWM_PRD_MASK) {
++ /* Then go up from the first divider */
++ for (i = 0; i < PWM_PRESCAL_MASK; i++) {
++ if (!prescal_table[i])
++ continue;
++ div = clk_rate / prescal_table[i];
++ div = div * period_ns;
++ do_div(div, 1000000000);
++ if (div <= PWM_PRD_MASK)
++ break;
++ }
++ }
++
++ if (div > PWM_PRD_MASK) {
++ dev_err(chip->dev, "prescaler exceeds the maximum value\n");
++ return -EINVAL;
++ }
++
++ prd = div;
++ div *= duty_ns;
++ do_div(div, period_ns);
++ dty = div;
++
++ ret = clk_prepare_enable(sunxi_pwm->clk);
++ if (ret) {
++ dev_err(chip->dev, "failed to enable PWM clock\n");
++ return ret;
++ }
++
++ mutex_lock(&sunxi_pwm->ctrl_lock);
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++
++ if (sunxi_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
++ mutex_unlock(&sunxi_pwm->ctrl_lock);
++ clk_disable_unprepare(sunxi_pwm->clk);
++ return -EBUSY;
++ }
++
++ clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++ if (clk_gate) {
++ val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++ }
++
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++ val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
++ val |= i;
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++
++ sunxi_pwm_writel(sunxi_pwm, PWM_CH_PRD(pwm->hwpwm), dty | PWM_PRD(prd));
++
++ if (clk_gate) {
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++ val |= clk_gate;
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++ }
++
++ mutex_unlock(&sunxi_pwm->ctrl_lock);
++ clk_disable_unprepare(sunxi_pwm->clk);
++
++ return 0;
++}
++
++static int sunxi_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
++ enum pwm_polarity polarity)
++{
++ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
++ u32 val;
++ int ret;
++
++ ret = clk_prepare_enable(sunxi_pwm->clk);
++ if (ret) {
++ dev_err(chip->dev, "failed to enable PWM clock\n");
++ return ret;
++ }
++
++ mutex_lock(&sunxi_pwm->ctrl_lock);
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++
++ if (polarity != PWM_POLARITY_NORMAL)
++ val &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
++ else
++ val |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
++
++
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++
++ mutex_unlock(&sunxi_pwm->ctrl_lock);
++ clk_disable_unprepare(sunxi_pwm->clk);
++
++ return 0;
++}
++
++static int sunxi_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
++ u32 val;
++ int ret;
++
++ ret = clk_prepare_enable(sunxi_pwm->clk);
++ if (ret) {
++ dev_err(chip->dev, "failed to enable PWM clock\n");
++ return ret;
++ }
++
++ mutex_lock(&sunxi_pwm->ctrl_lock);
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++ val |= BIT_CH(PWM_EN, pwm->hwpwm);
++ val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++ mutex_unlock(&sunxi_pwm->ctrl_lock);
++
++ return 0;
++}
++
++static void sunxi_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
++{
++ struct sunxi_pwm_chip *sunxi_pwm = to_sunxi_pwm_chip(chip);
++ u32 val;
++
++ mutex_lock(&sunxi_pwm->ctrl_lock);
++ val = sunxi_pwm_readl(sunxi_pwm, PWM_CTRL_REG);
++ val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
++ val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG, val);
++ mutex_unlock(&sunxi_pwm->ctrl_lock);
++
++ clk_disable_unprepare(sunxi_pwm->clk);
++}
++
++static const struct pwm_ops sunxi_pwm_ops = {
++ .config = sunxi_pwm_config,
++ .set_polarity = sunxi_pwm_set_polarity,
++ .enable = sunxi_pwm_enable,
++ .disable = sunxi_pwm_disable,
++ .owner = THIS_MODULE,
++};
++
++static const struct sunxi_pwm_data sunxi_pwm_data_a10 = {
++ .has_rdy = false,
++};
++
++static const struct sunxi_pwm_data sunxi_pwm_data_a20 = {
++ .has_rdy = true,
++};
++
++static const struct of_device_id sunxi_pwm_dt_ids[] = {
++ {
++ .compatible = "allwinner,sun4i-a10-pwm",
++ .data = &sunxi_pwm_data_a10,
++ }, {
++ .compatible = "allwinner,sun7i-a20-pwm",
++ .data = &sunxi_pwm_data_a20,
++ }, {
++ /* sentinel */
++ },
++};
++MODULE_DEVICE_TABLE(of, sunxi_pwm_dt_ids);
++
++static int sunxi_pwm_probe(struct platform_device *pdev)
++{
++ struct sunxi_pwm_chip *sunxi_pwm;
++ struct resource *res;
++ int ret;
++
++ const struct of_device_id *match;
++
++ match = of_match_device(sunxi_pwm_dt_ids, &pdev->dev);
++ if (!match || !match->data)
++ return -ENODEV;
++
++ sunxi_pwm = devm_kzalloc(&pdev->dev, sizeof(*sunxi_pwm), GFP_KERNEL);
++ if (!sunxi_pwm)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ sunxi_pwm->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(sunxi_pwm->base))
++ return PTR_ERR(sunxi_pwm->base);
++
++ sunxi_pwm->clk = devm_clk_get(&pdev->dev, NULL);
++ if (IS_ERR(sunxi_pwm->clk))
++ return PTR_ERR(sunxi_pwm->clk);
++
++ sunxi_pwm->chip.dev = &pdev->dev;
++ sunxi_pwm->chip.ops = &sunxi_pwm_ops;
++
++ sunxi_pwm->chip.base = -1;
++ sunxi_pwm->chip.npwm = 2;
++ sunxi_pwm->chip.can_sleep = true;
++ sunxi_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
++ sunxi_pwm->chip.of_pwm_n_cells = 3;
++ sunxi_pwm->data = match->data;
++
++ mutex_init(&sunxi_pwm->ctrl_lock);
++
++ ret = clk_prepare_enable(sunxi_pwm->clk);
++ if (ret) {
++ dev_err(&pdev->dev, "failed to enable PWM clock\n");
++ goto error;
++ }
++
++ /* By default, the polarity is inversed, set it to normal */
++ sunxi_pwm_writel(sunxi_pwm, PWM_CTRL_REG,
++ BIT_CH(PWM_ACT_STATE, 0) |
++ BIT_CH(PWM_ACT_STATE, 1));
++ clk_disable_unprepare(sunxi_pwm->clk);
++
++ ret = pwmchip_add(&sunxi_pwm->chip);
++ if (ret < 0) {
++ dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret);
++ goto error;
++ }
++
++ platform_set_drvdata(pdev, sunxi_pwm);
++
++ return ret;
++
++error:
++ mutex_destroy(&sunxi_pwm->ctrl_lock);
++ clk_disable_unprepare(sunxi_pwm->clk);
++ return ret;
++}
++
++static int sunxi_pwm_remove(struct platform_device *pdev)
++{
++ struct sunxi_pwm_chip *sunxi_pwm = platform_get_drvdata(pdev);
++
++ mutex_destroy(&sunxi_pwm->ctrl_lock);
++
++ return pwmchip_remove(&sunxi_pwm->chip);
++}
++
++static struct platform_driver sunxi_pwm_driver = {
++ .driver = {
++ .name = "sunxi-pwm",
++ .of_match_table = sunxi_pwm_dt_ids,
++ },
++ .probe = sunxi_pwm_probe,
++ .remove = sunxi_pwm_remove,
++};
++module_platform_driver(sunxi_pwm_driver);
++
++MODULE_ALIAS("platform:sunxi-pwm");
++MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
++MODULE_DESCRIPTION("Allwinner PWM driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/sunxi/patches-3.14/251-1-dt-sun4i-add-pinmux-for-pwm.patch b/target/linux/sunxi/patches-3.14/251-1-dt-sun4i-add-pinmux-for-pwm.patch
new file mode 100644
index 0000000000..00881f02c3
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/251-1-dt-sun4i-add-pinmux-for-pwm.patch
@@ -0,0 +1,41 @@
+From 1d8e9db920352680e9091ec5d2873e90a4a53214 Mon Sep 17 00:00:00 2001
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Date: Mon, 28 Apr 2014 18:17:10 +0200
+Subject: [PATCH] ARM: sun4i: dt: add pinmux configuration for the PWM
+
+Add the pinctrl descriptions for both PWM channels of the Allwinner A10.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index fe845eb..8810ce4 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -477,6 +477,20 @@
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
++ pwm0_pins_a: pwm0@0 {
++ allwinner,pins = "PB2";
++ allwinner,function = "pwm";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ pwm1_pins_a: pwm1@0 {
++ allwinner,pins = "PI3";
++ allwinner,function = "pwm";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PB22", "PB23";
+ allwinner,function = "uart0";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/251-2-dt-sun7i-add-pinmux-for-pwm.patch b/target/linux/sunxi/patches-3.14/251-2-dt-sun7i-add-pinmux-for-pwm.patch
new file mode 100644
index 0000000000..128e064046
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/251-2-dt-sun7i-add-pinmux-for-pwm.patch
@@ -0,0 +1,41 @@
+From cf34231072d53e643d6ef1baa95a8e9df644542e Mon Sep 17 00:00:00 2001
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Date: Mon, 28 Apr 2014 18:17:12 +0200
+Subject: [PATCH] ARM: sun7i: dt: add pinmux configuration for the PWM
+
+Add the pinctrl descriptions for both PWM channels of the Allwinner A20.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index f9f5e0c..2eaf7c0f 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -554,6 +554,20 @@
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
++ pwm0_pins_a: pwm0@0 {
++ allwinner,pins = "PB2";
++ allwinner,function = "pwm";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
++ pwm1_pins_a: pwm1@0 {
++ allwinner,pins = "PI3";
++ allwinner,function = "pwm";
++ allwinner,drive = <0>;
++ allwinner,pull = <0>;
++ };
++
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PB22", "PB23";
+ allwinner,function = "uart0";
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/252-1-dt-sun4i-add-pwm-support.patch b/target/linux/sunxi/patches-3.14/252-1-dt-sun4i-add-pwm-support.patch
new file mode 100644
index 0000000000..fd06b0bf89
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/252-1-dt-sun4i-add-pwm-support.patch
@@ -0,0 +1,35 @@
+From 25a4e0f1ac49c9ecafeba0d034806e25c491f012 Mon Sep 17 00:00:00 2001
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Date: Mon, 28 Apr 2014 18:17:11 +0200
+Subject: [PATCH] ARM: sun4i: dt: add PWM support
+
+Add the PWM bindings for the Allwinner A10.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
+index 8810ce4..4dc3761 100644
+--- a/arch/arm/boot/dts/sun4i-a10.dtsi
++++ b/arch/arm/boot/dts/sun4i-a10.dtsi
+@@ -563,6 +563,14 @@
+ interrupts = <24>;
+ };
+
++ pwm: pwm@01c20e00 {
++ compatible = "allwinner,sun4i-a10-pwm";
++ reg = <0x01c20e00 0xc>;
++ clocks = <&osc24M>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun4i-a10-sid";
+ reg = <0x01c23800 0x10>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/252-2-dt-sun7i-add-pwm-support.patch b/target/linux/sunxi/patches-3.14/252-2-dt-sun7i-add-pwm-support.patch
new file mode 100644
index 0000000000..3bb1186523
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/252-2-dt-sun7i-add-pwm-support.patch
@@ -0,0 +1,35 @@
+From 216a4cc15c24d46a5b50b3f9a224576a69c1a83e Mon Sep 17 00:00:00 2001
+From: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Date: Mon, 28 Apr 2014 18:17:13 +0200
+Subject: [PATCH] ARM: sun7i: dt: add PWM support
+
+Add the PWM bindings for the Allwinner A20.
+
+Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 2eaf7c0f..61a4b5e 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -706,6 +706,14 @@
+ interrupts = <0 24 4>;
+ };
+
++ pwm: pwm@01c20e00 {
++ compatible = "allwinner,sun7i-a20-pwm";
++ reg = <0x01c20e00 0xc>;
++ clocks = <&osc24M>;
++ #pwm-cells = <3>;
++ status = "disabled";
++ };
++
+ sid: eeprom@01c23800 {
+ compatible = "allwinner,sun7i-a20-sid";
+ reg = <0x01c23800 0x200>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/260-dt-sun7i-enable-arm-pmu.patch b/target/linux/sunxi/patches-3.14/260-dt-sun7i-enable-arm-pmu.patch
new file mode 100644
index 0000000000..41ff076c85
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/260-dt-sun7i-enable-arm-pmu.patch
@@ -0,0 +1,33 @@
+From 531f223d1426a826c7da4908e1a5e8eb3d40d6ed Mon Sep 17 00:00:00 2001
+From: Maxime Ripard <maxime.ripard@free-electrons.com>
+Date: Thu, 17 Apr 2014 21:54:41 +0200
+Subject: [PATCH] ARM: sun7i: Add ARM PMU in A20 DTSI
+
+Enable the performance monitoring unit found in the A20 SoCs.
+
+Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+---
+ arch/arm/boot/dts/sun7i-a20.dtsi | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 9dd904d..f9f5e0c 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -57,6 +57,12 @@
+ <1 10 0xf08>;
+ };
+
++ pmu {
++ compatible = "arm,cortex-a7-pmu", "arm,cortex-a15-pmu";
++ interrupts = <0 120 4>,
++ <0 121 4>;
++ };
++
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/270-dt-sun7i-add-ss-to-a20.patch b/target/linux/sunxi/patches-3.14/270-dt-sun7i-add-ss-to-a20.patch
new file mode 100644
index 0000000000..4a5ceba82e
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/270-dt-sun7i-add-ss-to-a20.patch
@@ -0,0 +1,23 @@
+diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
+index 6acdbdf..19b1ced 100644
+--- a/arch/arm/boot/dts/sun7i-a20.dtsi
++++ b/arch/arm/boot/dts/sun7i-a20.dtsi
+@@ -529,6 +529,14 @@
+ status = "disabled";
+ };
+
++ crypto: crypto-engine@01c15000 {
++ compatible = "allwinner,sun7i-a20-crypto";
++ reg = <0x01c15000 0x1000>;
++ interrupts = <0 86 4>;
++ clocks = <&ahb_gates 5>, <&ss_clk>;
++ clock-names = "ahb", "mod";
++ };
++
+ spi2: spi@01c17000 {
+ compatible = "allwinner,sun4i-a10-spi";
+ reg = <0x01c17000 0x1000>;
+--
+1.8.5.5
+
+ \ No newline at end of file
diff --git a/target/linux/sunxi/patches-3.14/271-crypto-add-ss.patch b/target/linux/sunxi/patches-3.14/271-crypto-add-ss.patch
new file mode 100644
index 0000000000..782a5373db
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/271-crypto-add-ss.patch
@@ -0,0 +1,1264 @@
+diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
+index 03ccdb0..a2acda4 100644
+--- a/drivers/crypto/Kconfig
++++ b/drivers/crypto/Kconfig
+@@ -418,4 +418,21 @@ config CRYPTO_DEV_MXS_DCP
+ To compile this driver as a module, choose M here: the module
+ will be called mxs-dcp.
+
++config CRYPTO_DEV_SUNXI_SS
++ tristate "Support for Allwinner Security System cryptographic accelerator"
++ depends on ARCH_SUNXI
++ select CRYPTO_MD5
++ select CRYPTO_SHA1
++ select CRYPTO_AES
++ select CRYPTO_DES
++ select CRYPTO_BLKCIPHER
++ help
++ Some Allwinner SoC have a crypto accelerator named
++ Security System. Select this if you want to use it.
++ The Security System handle AES/DES/3DES ciphers in CBC mode
++ and SHA1 and MD5 hash algorithms.
++
++ To compile this driver as a module, choose M here: the module
++ will be called sunxi-ss.
++
+ endif # CRYPTO_HW
+diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
+index 482f090..855292a 100644
+--- a/drivers/crypto/Makefile
++++ b/drivers/crypto/Makefile
+@@ -23,3 +23,4 @@ obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o
+ obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
+ obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
+ obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/
++obj-$(CONFIG_CRYPTO_DEV_SUNXI_SS) += sunxi-ss/
+diff --git a/drivers/crypto/sunxi-ss/Makefile b/drivers/crypto/sunxi-ss/Makefile
+new file mode 100644
+index 0000000..8bb287d
+--- /dev/null
++++ b/drivers/crypto/sunxi-ss/Makefile
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_CRYPTO_DEV_SUNXI_SS) += sunxi-ss.o
++sunxi-ss-y += sunxi-ss-core.o sunxi-ss-hash.o sunxi-ss-cipher.o
+diff --git a/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c b/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c
+new file mode 100644
+index 0000000..c2422f7
+--- /dev/null
++++ b/drivers/crypto/sunxi-ss/sunxi-ss-cipher.c
+@@ -0,0 +1,461 @@
++/*
++ * sunxi-ss-cipher.c - hardware cryptographic accelerator for Allwinner A20 SoC
++ *
++ * Copyright (C) 2013-2014 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
++ * This file add support for AES cipher with 128,192,256 bits
++ * keysize in CBC mode.
++ *
++ * You could find the datasheet at
++ * http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#include "sunxi-ss.h"
++
++extern struct sunxi_ss_ctx *ss;
++
++static int sunxi_ss_cipher(struct ablkcipher_request *areq, u32 mode)
++{
++ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++ const char *cipher_type;
++
++ cipher_type = crypto_tfm_alg_name(crypto_ablkcipher_tfm(tfm));
++
++ if (areq->nbytes == 0) {
++ mutex_unlock(&ss->lock);
++ return 0;
++ }
++
++ if (areq->info == NULL) {
++ dev_err(ss->dev, "ERROR: Empty IV\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++
++ if (areq->src == NULL || areq->dst == NULL) {
++ dev_err(ss->dev, "ERROR: Some SGs are NULL\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++
++ if (strcmp("cbc(aes)", cipher_type) == 0) {
++ op->mode |= SS_OP_AES | SS_CBC | SS_ENABLED | mode;
++ return sunxi_ss_aes_poll(areq);
++ }
++ if (strcmp("cbc(des)", cipher_type) == 0) {
++ op->mode = SS_OP_DES | SS_CBC | SS_ENABLED | mode;
++ return sunxi_ss_des_poll(areq);
++ }
++ if (strcmp("cbc(des3_ede)", cipher_type) == 0) {
++ op->mode = SS_OP_3DES | SS_CBC | SS_ENABLED | mode;
++ return sunxi_ss_des_poll(areq);
++ }
++ dev_err(ss->dev, "ERROR: Cipher %s not handled\n", cipher_type);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++}
++
++int sunxi_ss_cipher_encrypt(struct ablkcipher_request *areq)
++{
++ return sunxi_ss_cipher(areq, SS_ENCRYPTION);
++}
++
++int sunxi_ss_cipher_decrypt(struct ablkcipher_request *areq)
++{
++ return sunxi_ss_cipher(areq, SS_DECRYPTION);
++}
++
++int sunxi_ss_cipher_init(struct crypto_tfm *tfm)
++{
++ struct sunxi_req_ctx *op = crypto_tfm_ctx(tfm);
++
++ mutex_lock(&ss->lock);
++
++ memset(op, 0, sizeof(struct sunxi_req_ctx));
++ return 0;
++}
++
++int sunxi_ss_aes_poll(struct ablkcipher_request *areq)
++{
++ u32 spaces;
++ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++ unsigned int ivsize = crypto_ablkcipher_ivsize(tfm);
++ /* when activating SS, the default FIFO space is 32 */
++ u32 rx_cnt = 32;
++ u32 tx_cnt = 0;
++ u32 v;
++ int i;
++ struct scatterlist *in_sg;
++ struct scatterlist *out_sg;
++ void *src_addr;
++ void *dst_addr;
++ unsigned int ileft = areq->nbytes;
++ unsigned int oleft = areq->nbytes;
++ unsigned int sgileft = areq->src->length;
++ unsigned int sgoleft = areq->dst->length;
++ unsigned int todo;
++ u32 *src32;
++ u32 *dst32;
++
++ in_sg = areq->src;
++ out_sg = areq->dst;
++ for (i = 0; i < op->keylen; i += 4)
++ writel(*(op->key + i/4), ss->base + SS_KEY0 + i);
++ if (areq->info != NULL) {
++ for (i = 0; i < 4 && i < ivsize / 4; i++) {
++ v = *(u32 *)(areq->info + i * 4);
++ writel(v, ss->base + SS_IV0 + i * 4);
++ }
++ }
++ writel(op->mode, ss->base + SS_CTL);
++
++ /* If we have only one SG, we can use kmap_atomic */
++ if (sg_next(in_sg) == NULL && sg_next(out_sg) == NULL) {
++ src_addr = kmap_atomic(sg_page(in_sg)) + in_sg->offset;
++ if (src_addr == NULL) {
++ dev_err(ss->dev, "kmap_atomic error for src SG\n");
++ writel(0, ss->base + SS_CTL);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ dst_addr = kmap_atomic(sg_page(out_sg)) + out_sg->offset;
++ if (dst_addr == NULL) {
++ dev_err(ss->dev, "kmap_atomic error for dst SG\n");
++ writel(0, ss->base + SS_CTL);
++ kunmap_atomic(src_addr);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ src32 = (u32 *)src_addr;
++ dst32 = (u32 *)dst_addr;
++ ileft = areq->nbytes / 4;
++ oleft = areq->nbytes / 4;
++ i = 0;
++ do {
++ if (ileft > 0 && rx_cnt > 0) {
++ todo = min(rx_cnt, ileft);
++ ileft -= todo;
++ do {
++ writel_relaxed(*src32++,
++ ss->base +
++ SS_RXFIFO);
++ todo--;
++ } while (todo > 0);
++ }
++ if (tx_cnt > 0) {
++ todo = min(tx_cnt, oleft);
++ oleft -= todo;
++ do {
++ *dst32++ = readl_relaxed(ss->base +
++ SS_TXFIFO);
++ todo--;
++ } while (todo > 0);
++ }
++ spaces = readl_relaxed(ss->base + SS_FCSR);
++ rx_cnt = SS_RXFIFO_SPACES(spaces);
++ tx_cnt = SS_TXFIFO_SPACES(spaces);
++ } while (oleft > 0);
++ writel(0, ss->base + SS_CTL);
++ kunmap_atomic(src_addr);
++ kunmap_atomic(dst_addr);
++ mutex_unlock(&ss->lock);
++ return 0;
++ }
++
++ /* If we have more than one SG, we cannot use kmap_atomic since
++ * we hold the mapping too long
++ */
++ src_addr = kmap(sg_page(in_sg)) + in_sg->offset;
++ if (src_addr == NULL) {
++ dev_err(ss->dev, "KMAP error for src SG\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ dst_addr = kmap(sg_page(out_sg)) + out_sg->offset;
++ if (dst_addr == NULL) {
++ kunmap(sg_page(in_sg));
++ dev_err(ss->dev, "KMAP error for dst SG\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ src32 = (u32 *)src_addr;
++ dst32 = (u32 *)dst_addr;
++ ileft = areq->nbytes / 4;
++ oleft = areq->nbytes / 4;
++ sgileft = in_sg->length / 4;
++ sgoleft = out_sg->length / 4;
++ do {
++ spaces = readl_relaxed(ss->base + SS_FCSR);
++ rx_cnt = SS_RXFIFO_SPACES(spaces);
++ tx_cnt = SS_TXFIFO_SPACES(spaces);
++ todo = min3(rx_cnt, ileft, sgileft);
++ if (todo > 0) {
++ ileft -= todo;
++ sgileft -= todo;
++ }
++ while (todo > 0) {
++ writel_relaxed(*src32++, ss->base + SS_RXFIFO);
++ todo--;
++ }
++ if (in_sg != NULL && sgileft == 0 && ileft > 0) {
++ kunmap(sg_page(in_sg));
++ in_sg = sg_next(in_sg);
++ while (in_sg != NULL && in_sg->length == 0)
++ in_sg = sg_next(in_sg);
++ if (in_sg != NULL && ileft > 0) {
++ src_addr = kmap(sg_page(in_sg)) + in_sg->offset;
++ if (src_addr == NULL) {
++ dev_err(ss->dev, "ERROR: KMAP for src SG\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ src32 = src_addr;
++ sgileft = in_sg->length / 4;
++ }
++ }
++ /* do not test oleft since when oleft == 0 we have finished */
++ todo = min3(tx_cnt, oleft, sgoleft);
++ if (todo > 0) {
++ oleft -= todo;
++ sgoleft -= todo;
++ }
++ while (todo > 0) {
++ *dst32++ = readl_relaxed(ss->base + SS_TXFIFO);
++ todo--;
++ }
++ if (out_sg != NULL && sgoleft == 0 && oleft >= 0) {
++ kunmap(sg_page(out_sg));
++ out_sg = sg_next(out_sg);
++ while (out_sg != NULL && out_sg->length == 0)
++ out_sg = sg_next(out_sg);
++ if (out_sg != NULL && oleft > 0) {
++ dst_addr = kmap(sg_page(out_sg)) +
++ out_sg->offset;
++ if (dst_addr == NULL) {
++ dev_err(ss->dev, "KMAP error\n");
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ dst32 = dst_addr;
++ sgoleft = out_sg->length / 4;
++ }
++ }
++ } while (oleft > 0);
++
++ writel(0, ss->base + SS_CTL);
++ mutex_unlock(&ss->lock);
++ return 0;
++}
++
++/* Pure CPU way of doing DES/3DES with SS
++ * Since DES and 3DES SGs could be smaller than 4 bytes, I use sg_copy_to_buffer
++ * for "linearize" them.
++ * The problem with that is that I alloc (2 x areq->nbytes) for buf_in/buf_out
++ * TODO: change this system
++ * SGsrc -> buf_in -> SS -> buf_out -> SGdst */
++int sunxi_ss_des_poll(struct ablkcipher_request *areq)
++{
++ u32 value, spaces;
++ size_t nb_in_sg_tx, nb_in_sg_rx;
++ size_t ir, it;
++ struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++ unsigned int ivsize = crypto_ablkcipher_ivsize(tfm);
++ u32 tx_cnt = 0;
++ u32 rx_cnt = 0;
++ u32 v;
++ int i;
++ int no_chunk = 1;
++
++ /* if we have only SGs with size multiple of 4,
++ * we can use the SS AES function */
++ struct scatterlist *in_sg;
++ struct scatterlist *out_sg;
++
++ in_sg = areq->src;
++ out_sg = areq->dst;
++
++ while (in_sg != NULL && no_chunk == 1) {
++ if ((in_sg->length % 4) != 0)
++ no_chunk = 0;
++ in_sg = sg_next(in_sg);
++ }
++ while (out_sg != NULL && no_chunk == 1) {
++ if ((out_sg->length % 4) != 0)
++ no_chunk = 0;
++ out_sg = sg_next(out_sg);
++ }
++
++ if (no_chunk == 1)
++ return sunxi_ss_aes_poll(areq);
++ in_sg = areq->src;
++ out_sg = areq->dst;
++
++ nb_in_sg_rx = sg_nents(in_sg);
++ nb_in_sg_tx = sg_nents(out_sg);
++
++ mutex_lock(&ss->bufin_lock);
++ if (ss->buf_in == NULL) {
++ ss->buf_in = kmalloc(areq->nbytes, GFP_KERNEL);
++ ss->buf_in_size = areq->nbytes;
++ } else {
++ if (areq->nbytes > ss->buf_in_size) {
++ kfree(ss->buf_in);
++ ss->buf_in = kmalloc(areq->nbytes, GFP_KERNEL);
++ ss->buf_in_size = areq->nbytes;
++ }
++ }
++ if (ss->buf_in == NULL) {
++ ss->buf_in_size = 0;
++ mutex_unlock(&ss->bufin_lock);
++ dev_err(ss->dev, "Unable to allocate pages.\n");
++ return -ENOMEM;
++ }
++ if (ss->buf_out == NULL) {
++ mutex_lock(&ss->bufout_lock);
++ ss->buf_out = kmalloc(areq->nbytes, GFP_KERNEL);
++ if (ss->buf_out == NULL) {
++ ss->buf_out_size = 0;
++ mutex_unlock(&ss->bufout_lock);
++ dev_err(ss->dev, "Unable to allocate pages.\n");
++ return -ENOMEM;
++ }
++ ss->buf_out_size = areq->nbytes;
++ mutex_unlock(&ss->bufout_lock);
++ } else {
++ if (areq->nbytes > ss->buf_out_size) {
++ mutex_lock(&ss->bufout_lock);
++ kfree(ss->buf_out);
++ ss->buf_out = kmalloc(areq->nbytes, GFP_KERNEL);
++ if (ss->buf_out == NULL) {
++ ss->buf_out_size = 0;
++ mutex_unlock(&ss->bufout_lock);
++ dev_err(ss->dev, "Unable to allocate pages.\n");
++ return -ENOMEM;
++ }
++ ss->buf_out_size = areq->nbytes;
++ mutex_unlock(&ss->bufout_lock);
++ }
++ }
++
++ sg_copy_to_buffer(areq->src, nb_in_sg_rx, ss->buf_in, areq->nbytes);
++
++ ir = 0;
++ it = 0;
++
++ for (i = 0; i < op->keylen; i += 4)
++ writel(*(op->key + i/4), ss->base + SS_KEY0 + i);
++ if (areq->info != NULL) {
++ for (i = 0; i < 4 && i < ivsize / 4; i++) {
++ v = *(u32 *)(areq->info + i * 4);
++ writel(v, ss->base + SS_IV0 + i * 4);
++ }
++ }
++ writel(op->mode, ss->base + SS_CTL);
++
++ do {
++ if (rx_cnt == 0 || tx_cnt == 0) {
++ spaces = readl(ss->base + SS_FCSR);
++ rx_cnt = SS_RXFIFO_SPACES(spaces);
++ tx_cnt = SS_TXFIFO_SPACES(spaces);
++ }
++ if (rx_cnt > 0 && ir < areq->nbytes) {
++ do {
++ value = *(u32 *)(ss->buf_in + ir);
++ writel(value, ss->base + SS_RXFIFO);
++ ir += 4;
++ rx_cnt--;
++ } while (rx_cnt > 0 && ir < areq->nbytes);
++ }
++ if (tx_cnt > 0 && it < areq->nbytes) {
++ do {
++ value = readl(ss->base + SS_TXFIFO);
++ *(u32 *)(ss->buf_out + it) = value;
++ it += 4;
++ tx_cnt--;
++ } while (tx_cnt > 0 && it < areq->nbytes);
++ }
++ if (ir == areq->nbytes) {
++ mutex_unlock(&ss->bufin_lock);
++ ir++;
++ }
++ } while (it < areq->nbytes);
++
++ writel(0, ss->base + SS_CTL);
++ mutex_unlock(&ss->lock);
++
++ /* a simple optimization, since we dont need the hardware for this copy
++ * we release the lock and do the copy. With that we gain 5/10% perf */
++ mutex_lock(&ss->bufout_lock);
++ sg_copy_from_buffer(areq->dst, nb_in_sg_tx, ss->buf_out, areq->nbytes);
++
++ mutex_unlock(&ss->bufout_lock);
++ return 0;
++}
++
++/* check and set the AES key, prepare the mode to be used */
++int sunxi_ss_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++
++ switch (keylen) {
++ case 128 / 8:
++ op->mode = SS_AES_128BITS;
++ break;
++ case 192 / 8:
++ op->mode = SS_AES_192BITS;
++ break;
++ case 256 / 8:
++ op->mode = SS_AES_256BITS;
++ break;
++ default:
++ dev_err(ss->dev, "ERROR: Invalid keylen %u\n", keylen);
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ op->keylen = keylen;
++ memcpy(op->key, key, keylen);
++ return 0;
++}
++
++/* check and set the DES key, prepare the mode to be used */
++int sunxi_ss_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != DES_KEY_SIZE) {
++ dev_err(ss->dev, "Invalid keylen %u\n", keylen);
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ op->keylen = keylen;
++ memcpy(op->key, key, keylen);
++ return 0;
++}
++
++/* check and set the 3DES key, prepare the mode to be used */
++int sunxi_ss_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen)
++{
++ struct sunxi_req_ctx *op = crypto_ablkcipher_ctx(tfm);
++
++ if (keylen != 3 * DES_KEY_SIZE) {
++ dev_err(ss->dev, "Invalid keylen %u\n", keylen);
++ crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
++ mutex_unlock(&ss->lock);
++ return -EINVAL;
++ }
++ op->keylen = keylen;
++ memcpy(op->key, key, keylen);
++ return 0;
++}
+diff --git a/drivers/crypto/sunxi-ss/sunxi-ss-core.c b/drivers/crypto/sunxi-ss/sunxi-ss-core.c
+new file mode 100644
+index 0000000..c76016e
+--- /dev/null
++++ b/drivers/crypto/sunxi-ss/sunxi-ss-core.c
+@@ -0,0 +1,308 @@
++/*
++ * sunxi-ss.c - hardware cryptographic accelerator for Allwinner A20 SoC
++ *
++ * Copyright (C) 2013-2014 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
++ * Core file which registers crypto algorithms supported by the SS.
++ *
++ * You could find the datasheet at
++ * http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#include <linux/clk.h>
++#include <linux/crypto.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <crypto/scatterwalk.h>
++#include <linux/scatterlist.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++
++#include "sunxi-ss.h"
++
++struct sunxi_ss_ctx *ss;
++
++/* General notes:
++ * I cannot use a key/IV cache because each time one of these change ALL stuff
++ * need to be re-writed (rewrite SS_KEYX ans SS_IVX).
++ * And for example, with dm-crypt IV changes on each request.
++ *
++ * After each request the device must be disabled with a write of 0 in SS_CTL
++ *
++ * For performance reason, we use writel_relaxed/read_relaxed for all
++ * operations on RX and TX FIFO and also SS_FCSR.
++ * For all other registers, we use writel/readl.
++ * See http://permalink.gmane.org/gmane.linux.ports.arm.kernel/117644
++ * and http://permalink.gmane.org/gmane.linux.ports.arm.kernel/117640
++ * */
++
++static struct ahash_alg sunxi_md5_alg = {
++ .init = sunxi_hash_init,
++ .update = sunxi_hash_update,
++ .final = sunxi_hash_final,
++ .finup = sunxi_hash_finup,
++ .digest = sunxi_hash_digest,
++ .halg = {
++ .digestsize = MD5_DIGEST_SIZE,
++ .base = {
++ .cra_name = "md5",
++ .cra_driver_name = "md5-sunxi-ss",
++ .cra_priority = 300,
++ .cra_alignmask = 3,
++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct sunxi_req_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_type = &crypto_ahash_type
++ }
++ }
++};
++static struct ahash_alg sunxi_sha1_alg = {
++ .init = sunxi_hash_init,
++ .update = sunxi_hash_update,
++ .final = sunxi_hash_final,
++ .finup = sunxi_hash_finup,
++ .digest = sunxi_hash_digest,
++ .halg = {
++ .digestsize = SHA1_DIGEST_SIZE,
++ .base = {
++ .cra_name = "sha1",
++ .cra_driver_name = "sha1-sunxi-ss",
++ .cra_priority = 300,
++ .cra_alignmask = 3,
++ .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
++ .cra_blocksize = SHA1_BLOCK_SIZE,
++ .cra_ctxsize = sizeof(struct sunxi_req_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_type = &crypto_ahash_type
++ }
++ }
++};
++
++static struct crypto_alg sunxi_cipher_algs[] = {
++{
++ .cra_name = "cbc(aes)",
++ .cra_driver_name = "cbc-aes-sunxi-ss",
++ .cra_priority = 300,
++ .cra_blocksize = AES_BLOCK_SIZE,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
++ .cra_ctxsize = sizeof(struct sunxi_req_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_alignmask = 3,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_init = sunxi_ss_cipher_init,
++ .cra_u = {
++ .ablkcipher = {
++ .min_keysize = AES_MIN_KEY_SIZE,
++ .max_keysize = AES_MAX_KEY_SIZE,
++ .ivsize = AES_BLOCK_SIZE,
++ .setkey = sunxi_ss_aes_setkey,
++ .encrypt = sunxi_ss_cipher_encrypt,
++ .decrypt = sunxi_ss_cipher_decrypt,
++ }
++ }
++}, {
++ .cra_name = "cbc(des)",
++ .cra_driver_name = "cbc-des-sunxi-ss",
++ .cra_priority = 300,
++ .cra_blocksize = DES_BLOCK_SIZE,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
++ .cra_ctxsize = sizeof(struct sunxi_req_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_alignmask = 3,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_init = sunxi_ss_cipher_init,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES_KEY_SIZE,
++ .max_keysize = DES_KEY_SIZE,
++ .ivsize = DES_BLOCK_SIZE,
++ .setkey = sunxi_ss_des_setkey,
++ .encrypt = sunxi_ss_cipher_encrypt,
++ .decrypt = sunxi_ss_cipher_decrypt,
++ }
++}, {
++ .cra_name = "cbc(des3_ede)",
++ .cra_driver_name = "cbc-des3-sunxi-ss",
++ .cra_priority = 300,
++ .cra_blocksize = DES3_EDE_BLOCK_SIZE,
++ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER,
++ .cra_ctxsize = sizeof(struct sunxi_req_ctx),
++ .cra_module = THIS_MODULE,
++ .cra_alignmask = 3,
++ .cra_type = &crypto_ablkcipher_type,
++ .cra_init = sunxi_ss_cipher_init,
++ .cra_u.ablkcipher = {
++ .min_keysize = DES3_EDE_KEY_SIZE,
++ .max_keysize = DES3_EDE_KEY_SIZE,
++ .ivsize = DES3_EDE_BLOCK_SIZE,
++ .setkey = sunxi_ss_des3_setkey,
++ .encrypt = sunxi_ss_cipher_encrypt,
++ .decrypt = sunxi_ss_cipher_decrypt,
++ }
++}
++};
++
++static int sunxi_ss_probe(struct platform_device *pdev)
++{
++ struct resource *res;
++ u32 v;
++ int err;
++ unsigned long cr;
++ const unsigned long cr_ahb = 24 * 1000 * 1000;
++ const unsigned long cr_mod = 150 * 1000 * 1000;
++
++ if (!pdev->dev.of_node)
++ return -ENODEV;
++
++ ss = devm_kzalloc(&pdev->dev, sizeof(*ss), GFP_KERNEL);
++ if (ss == NULL)
++ return -ENOMEM;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ss->base = devm_ioremap_resource(&pdev->dev, res);
++ if (IS_ERR(ss->base)) {
++ dev_err(&pdev->dev, "Cannot request MMIO\n");
++ return PTR_ERR(ss->base);
++ }
++
++ ss->ssclk = devm_clk_get(&pdev->dev, "mod");
++ if (IS_ERR(ss->ssclk)) {
++ err = PTR_ERR(ss->ssclk);
++ dev_err(&pdev->dev, "Cannot get SS clock err=%d\n", err);
++ return err;
++ }
++ dev_dbg(&pdev->dev, "clock ss acquired\n");
++
++ ss->busclk = devm_clk_get(&pdev->dev, "ahb");
++ if (IS_ERR(ss->busclk)) {
++ err = PTR_ERR(ss->busclk);
++ dev_err(&pdev->dev, "Cannot get AHB SS clock err=%d\n", err);
++ return err;
++ }
++ dev_dbg(&pdev->dev, "clock ahb_ss acquired\n");
++
++ /* Enable the clocks */
++ err = clk_prepare_enable(ss->busclk);
++ if (err != 0) {
++ dev_err(&pdev->dev, "Cannot prepare_enable busclk\n");
++ return err;
++ }
++ err = clk_prepare_enable(ss->ssclk);
++ if (err != 0) {
++ dev_err(&pdev->dev, "Cannot prepare_enable ssclk\n");
++ clk_disable_unprepare(ss->busclk);
++ return err;
++ }
++
++ /* Check that clock have the correct rates gived in the datasheet */
++ /* Try to set the clock to the maximum allowed */
++ err = clk_set_rate(ss->ssclk, cr_mod);
++ if (err != 0) {
++ dev_err(&pdev->dev, "Cannot set clock rate to ssclk\n");
++ clk_disable_unprepare(ss->ssclk);
++ clk_disable_unprepare(ss->busclk);
++ return err;
++ }
++ cr = clk_get_rate(ss->busclk);
++ if (cr >= cr_ahb)
++ dev_dbg(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
++ cr, cr / 1000000, cr_ahb);
++ else
++ dev_warn(&pdev->dev, "Clock bus %lu (%lu MHz) (must be >= %lu)\n",
++ cr, cr / 1000000, cr_ahb);
++ cr = clk_get_rate(ss->ssclk);
++ if (cr == cr_mod)
++ dev_dbg(&pdev->dev, "Clock ss %lu (%lu MHz) (must be <= %lu)\n",
++ cr, cr / 1000000, cr_mod);
++ else {
++ dev_warn(&pdev->dev, "Clock ss is at %lu (%lu MHz) (must be <= %lu)\n",
++ cr, cr / 1000000, cr_mod);
++ }
++
++ /* TODO Does this information could be usefull ? */
++ writel(SS_ENABLED, ss->base + SS_CTL);
++ v = readl(ss->base + SS_CTL);
++ v >>= 16;
++ v &= 0x07;
++ dev_info(&pdev->dev, "Die ID %d\n", v);
++ writel(0, ss->base + SS_CTL);
++
++ ss->dev = &pdev->dev;
++
++ mutex_init(&ss->lock);
++ mutex_init(&ss->bufin_lock);
++ mutex_init(&ss->bufout_lock);
++
++ err = crypto_register_ahash(&sunxi_md5_alg);
++ if (err)
++ goto error_md5;
++ err = crypto_register_ahash(&sunxi_sha1_alg);
++ if (err)
++ goto error_sha1;
++ err = crypto_register_algs(sunxi_cipher_algs,
++ ARRAY_SIZE(sunxi_cipher_algs));
++ if (err)
++ goto error_ciphers;
++
++ return 0;
++error_ciphers:
++ crypto_unregister_ahash(&sunxi_sha1_alg);
++error_sha1:
++ crypto_unregister_ahash(&sunxi_md5_alg);
++error_md5:
++ clk_disable_unprepare(ss->ssclk);
++ clk_disable_unprepare(ss->busclk);
++ return err;
++}
++
++static int __exit sunxi_ss_remove(struct platform_device *pdev)
++{
++ if (!pdev->dev.of_node)
++ return 0;
++
++ crypto_unregister_ahash(&sunxi_md5_alg);
++ crypto_unregister_ahash(&sunxi_sha1_alg);
++ crypto_unregister_algs(sunxi_cipher_algs,
++ ARRAY_SIZE(sunxi_cipher_algs));
++
++ if (ss->buf_in != NULL)
++ kfree(ss->buf_in);
++ if (ss->buf_out != NULL)
++ kfree(ss->buf_out);
++
++ writel(0, ss->base + SS_CTL);
++ clk_disable_unprepare(ss->busclk);
++ clk_disable_unprepare(ss->ssclk);
++ return 0;
++}
++
++/*============================================================================*/
++/*============================================================================*/
++static const struct of_device_id a20ss_crypto_of_match_table[] = {
++ { .compatible = "allwinner,sun7i-a20-crypto" },
++ {}
++};
++MODULE_DEVICE_TABLE(of, a20ss_crypto_of_match_table);
++
++static struct platform_driver sunxi_ss_driver = {
++ .probe = sunxi_ss_probe,
++ .remove = __exit_p(sunxi_ss_remove),
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = "sunxi-ss",
++ .of_match_table = a20ss_crypto_of_match_table,
++ },
++};
++
++module_platform_driver(sunxi_ss_driver);
++
++MODULE_DESCRIPTION("Allwinner Security System cryptographic accelerator");
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Corentin LABBE <clabbe.montjoie@gmail.com>");
+diff --git a/drivers/crypto/sunxi-ss/sunxi-ss-hash.c b/drivers/crypto/sunxi-ss/sunxi-ss-hash.c
+new file mode 100644
+index 0000000..6412bfb
+--- /dev/null
++++ b/drivers/crypto/sunxi-ss/sunxi-ss-hash.c
+@@ -0,0 +1,241 @@
++/*
++ * sunxi-ss-hash.c - hardware cryptographic accelerator for Allwinner A20 SoC
++ *
++ * Copyright (C) 2013-2014 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
++ * This file add support for MD5 and SHA1.
++ *
++ * You could find the datasheet at
++ * http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++#include "sunxi-ss.h"
++
++extern struct sunxi_ss_ctx *ss;
++
++/* sunxi_hash_init: initialize request context
++ * Activate the SS, and configure it for MD5 or SHA1
++ */
++int sunxi_hash_init(struct ahash_request *areq)
++{
++ const char *hash_type;
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ahash_ctx(tfm);
++
++ mutex_lock(&ss->lock);
++
++ hash_type = crypto_tfm_alg_name(areq->base.tfm);
++
++ op->byte_count = 0;
++ op->nbwait = 0;
++ op->waitbuf = 0;
++
++ /* Enable and configure SS for MD5 or SHA1 */
++ if (strcmp(hash_type, "sha1") == 0)
++ op->mode = SS_OP_SHA1;
++ else
++ op->mode = SS_OP_MD5;
++
++ writel(op->mode | SS_ENABLED, ss->base + SS_CTL);
++ return 0;
++}
++
++/*
++ * sunxi_hash_update: update hash engine
++ *
++ * Could be used for both SHA1 and MD5
++ * Write data by step of 32bits and put then in the SS.
++ * The remaining data is stored (nbwait bytes) in op->waitbuf
++ * As an optimisation, we do not check RXFIFO_SPACES, since SS handle
++ * the FIFO faster than our writes
++ */
++int sunxi_hash_update(struct ahash_request *areq)
++{
++ u32 v;
++ unsigned int i = 0;/* bytes read, to be compared to areq->nbytes */
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ahash_ctx(tfm);
++ struct scatterlist *in_sg;
++ unsigned int in_i = 0;/* advancement in the current SG */
++ void *src_addr;
++
++ u8 *waitbuf = (u8 *)(&op->waitbuf);
++
++ if (areq->nbytes == 0)
++ return 0;
++
++ in_sg = areq->src;
++ do {
++ src_addr = kmap(sg_page(in_sg)) + in_sg->offset;
++ /* step 1, if some bytes remains from last SG,
++ * try to complete them to 4 and sent its */
++ if (op->nbwait > 0) {
++ while (op->nbwait < 4 && i < areq->nbytes &&
++ in_i < in_sg->length) {
++ waitbuf[op->nbwait] = *(u8 *)(src_addr + in_i);
++ i++;
++ in_i++;
++ op->nbwait++;
++ }
++ if (op->nbwait == 4) {
++ writel(op->waitbuf, ss->base + SS_RXFIFO);
++ op->byte_count += 4;
++ op->nbwait = 0;
++ op->waitbuf = 0;
++ }
++ }
++ /* step 2, main loop, read data 4bytes at a time */
++ while (i < areq->nbytes && areq->nbytes - i >= 4 &&
++ in_i < in_sg->length &&
++ in_sg->length - in_i >= 4) {
++ v = *(u32 *)(src_addr + in_i);
++ writel_relaxed(v, ss->base + SS_RXFIFO);
++ i += 4;
++ op->byte_count += 4;
++ in_i += 4;
++ }
++ /* step 3, if we have less than 4 bytes, copy them in waitbuf
++ * no need to check for op->nbwait < 4 since we cannot have
++ * more than 4 bytes remaining */
++ if (in_i < in_sg->length && in_sg->length - in_i < 4 &&
++ i < areq->nbytes) {
++ do {
++ waitbuf[op->nbwait] = *(u8 *)(src_addr + in_i);
++ op->nbwait++;
++ in_i++;
++ i++;
++ } while (in_i < in_sg->length && i < areq->nbytes);
++ }
++ /* we have finished the current SG, try next one */
++ kunmap(sg_page(in_sg));
++ in_sg = sg_next(in_sg);
++ in_i = 0;
++ } while (in_sg != NULL && i < areq->nbytes);
++ return 0;
++}
++
++/*
++ * sunxi_hash_final: finalize hashing operation
++ *
++ * If we have some remaining bytes, send it.
++ * Then ask the SS for finalizing the hash
++ */
++int sunxi_hash_final(struct ahash_request *areq)
++{
++ u32 v;
++ unsigned int i;
++ int zeros;
++ unsigned int index, padlen;
++ __be64 bits;
++ struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++ struct sunxi_req_ctx *op = crypto_ahash_ctx(tfm);
++
++ if (op->nbwait > 0) {
++ op->waitbuf |= ((1 << 7) << (op->nbwait * 8));
++ writel(op->waitbuf, ss->base + SS_RXFIFO);
++ } else {
++ writel((1 << 7), ss->base + SS_RXFIFO);
++ }
++
++ /* number of space to pad to obtain 64o minus 8(size) minus 4 (final 1)
++ * example len=0
++ * example len=56
++ * */
++
++ /* we have already send 4 more byte of which nbwait data */
++ if (op->mode == SS_OP_MD5) {
++ index = (op->byte_count + 4) & 0x3f;
++ op->byte_count += op->nbwait;
++ if (index > 56)
++ zeros = (120 - index) / 4;
++ else
++ zeros = (56 - index) / 4;
++ } else {
++ op->byte_count += op->nbwait;
++ index = op->byte_count & 0x3f;
++ padlen = (index < 56) ? (56 - index) : ((64+56) - index);
++ zeros = (padlen - 1) / 4;
++ }
++ for (i = 0; i < zeros; i++)
++ writel(0, ss->base + SS_RXFIFO);
++
++ /* write the lenght */
++ if (op->mode == SS_OP_SHA1) {
++ bits = cpu_to_be64(op->byte_count << 3);
++ writel(bits & 0xffffffff, ss->base + SS_RXFIFO);
++ writel((bits >> 32) & 0xffffffff, ss->base + SS_RXFIFO);
++ } else {
++ writel((op->byte_count << 3) & 0xffffffff,
++ ss->base + SS_RXFIFO);
++ writel((op->byte_count >> 29) & 0xffffffff,
++ ss->base + SS_RXFIFO);
++ }
++
++ /* stop the hashing */
++ v = readl(ss->base + SS_CTL);
++ v |= SS_DATA_END;
++ writel(v, ss->base + SS_CTL);
++
++ /* check the end */
++ /* The timeout could happend only in case of bad overcloking */
++#define SS_TIMEOUT 100
++ i = 0;
++ do {
++ v = readl(ss->base + SS_CTL);
++ i++;
++ } while (i < SS_TIMEOUT && (v & SS_DATA_END) > 0);
++ if (i >= SS_TIMEOUT) {
++ dev_err(ss->dev, "ERROR: hash end timeout %d>%d\n",
++ i, SS_TIMEOUT);
++ writel(0, ss->base + SS_CTL);
++ mutex_unlock(&ss->lock);
++ return -1;
++ }
++
++ if (op->mode == SS_OP_SHA1) {
++ for (i = 0; i < 5; i++) {
++ v = cpu_to_be32(readl(ss->base + SS_MD0 + i * 4));
++ memcpy(areq->result + i * 4, &v, 4);
++ }
++ } else {
++ for (i = 0; i < 4; i++) {
++ v = readl(ss->base + SS_MD0 + i * 4);
++ memcpy(areq->result + i * 4, &v, 4);
++ }
++ }
++ writel(0, ss->base + SS_CTL);
++ mutex_unlock(&ss->lock);
++ return 0;
++}
++
++/* sunxi_hash_finup: finalize hashing operation after an update */
++int sunxi_hash_finup(struct ahash_request *areq)
++{
++ int err;
++
++ err = sunxi_hash_update(areq);
++ if (err != 0)
++ return err;
++
++ return sunxi_hash_final(areq);
++}
++
++/* combo of init/update/final functions */
++int sunxi_hash_digest(struct ahash_request *areq)
++{
++ int err;
++
++ err = sunxi_hash_init(areq);
++ if (err != 0)
++ return err;
++
++ err = sunxi_hash_update(areq);
++ if (err != 0)
++ return err;
++
++ return sunxi_hash_final(areq);
++}
+diff --git a/drivers/crypto/sunxi-ss/sunxi-ss.h b/drivers/crypto/sunxi-ss/sunxi-ss.h
+new file mode 100644
+index 0000000..94aca20
+--- /dev/null
++++ b/drivers/crypto/sunxi-ss/sunxi-ss.h
+@@ -0,0 +1,183 @@
++/*
++ * sunxi-ss.c - hardware cryptographic accelerator for Allwinner A20 SoC
++ *
++ * Copyright (C) 2013-2014 Corentin LABBE <clabbe.montjoie@gmail.com>
++ *
++ * Support AES cipher with 128,192,256 bits keysize.
++ * Support MD5 and SHA1 hash algorithms.
++ * Support DES and 3DES
++ * Support PRNG
++ *
++ * You could find the datasheet at
++ * http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
++ *
++ *
++ * Licensed under the GPL-2.
++ */
++
++#include <linux/clk.h>
++#include <linux/crypto.h>
++#include <linux/io.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <crypto/scatterwalk.h>
++#include <linux/scatterlist.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <crypto/md5.h>
++#include <crypto/sha.h>
++#include <crypto/hash.h>
++#include <crypto/internal/hash.h>
++#include <crypto/aes.h>
++#include <crypto/des.h>
++#include <crypto/internal/rng.h>
++
++#define SS_CTL 0x00
++#define SS_KEY0 0x04
++#define SS_KEY1 0x08
++#define SS_KEY2 0x0C
++#define SS_KEY3 0x10
++#define SS_KEY4 0x14
++#define SS_KEY5 0x18
++#define SS_KEY6 0x1C
++#define SS_KEY7 0x20
++
++#define SS_IV0 0x24
++#define SS_IV1 0x28
++#define SS_IV2 0x2C
++#define SS_IV3 0x30
++
++#define SS_CNT0 0x34
++#define SS_CNT1 0x38
++#define SS_CNT2 0x3C
++#define SS_CNT3 0x40
++
++#define SS_FCSR 0x44
++#define SS_ICSR 0x48
++
++#define SS_MD0 0x4C
++#define SS_MD1 0x50
++#define SS_MD2 0x54
++#define SS_MD3 0x58
++#define SS_MD4 0x5C
++
++#define SS_RXFIFO 0x200
++#define SS_TXFIFO 0x204
++
++/* SS_CTL configuration values */
++
++/* PRNG generator mode - bit 15 */
++#define SS_PRNG_ONESHOT (0 << 15)
++#define SS_PRNG_CONTINUE (1 << 15)
++
++/* SS operation mode - bits 12-13 */
++#define SS_ECB (0 << 12)
++#define SS_CBC (1 << 12)
++#define SS_CNT (2 << 12)
++
++/* Counter width for CNT mode - bits 10-11 */
++#define SS_CNT_16BITS (0 << 10)
++#define SS_CNT_32BITS (1 << 10)
++#define SS_CNT_64BITS (2 << 10)
++
++/* Key size for AES - bits 8-9 */
++#define SS_AES_128BITS (0 << 8)
++#define SS_AES_192BITS (1 << 8)
++#define SS_AES_256BITS (2 << 8)
++
++/* Operation direction - bit 7 */
++#define SS_ENCRYPTION (0 << 7)
++#define SS_DECRYPTION (1 << 7)
++
++/* SS Method - bits 4-6 */
++#define SS_OP_AES (0 << 4)
++#define SS_OP_DES (1 << 4)
++#define SS_OP_3DES (2 << 4)
++#define SS_OP_SHA1 (3 << 4)
++#define SS_OP_MD5 (4 << 4)
++#define SS_OP_PRNG (5 << 4)
++
++/* Data end bit - bit 2 */
++#define SS_DATA_END (1 << 2)
++
++/* PRNG start bit - bit 1 */
++#define SS_PRNG_START (1 << 1)
++
++/* SS Enable bit - bit 0 */
++#define SS_DISABLED (0 << 0)
++#define SS_ENABLED (1 << 0)
++
++/* SS_FCSR configuration values */
++/* RX FIFO status - bit 30 */
++#define SS_RXFIFO_FREE (1 << 30)
++
++/* RX FIFO empty spaces - bits 24-29 */
++#define SS_RXFIFO_SPACES(val) (((val) >> 24) & 0x3f)
++
++/* TX FIFO status - bit 22 */
++#define SS_TXFIFO_AVAILABLE (1 << 22)
++
++/* TX FIFO available spaces - bits 16-21 */
++#define SS_TXFIFO_SPACES(val) (((val) >> 16) & 0x3f)
++
++#define SS_RXFIFO_EMP_INT_PENDING (1 << 10)
++#define SS_TXFIFO_AVA_INT_PENDING (1 << 8)
++#define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
++#define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
++
++/* SS_ICSR configuration values */
++#define SS_ICS_DRQ_ENABLE (1 << 4)
++
++struct sunxi_ss_ctx {
++ void __iomem *base;
++ int irq;
++ struct clk *busclk;
++ struct clk *ssclk;
++ struct device *dev;
++ struct resource *res;
++ void *buf_in; /* pointer to data to be uploaded to the device */
++ size_t buf_in_size; /* size of buf_in */
++ void *buf_out;
++ size_t buf_out_size;
++ struct mutex lock; /* control the use of the device */
++ struct mutex bufout_lock; /* control the use of buf_out*/
++ struct mutex bufin_lock; /* control the sue of buf_in*/
++};
++
++struct sunxi_req_ctx {
++ u32 key[AES_MAX_KEY_SIZE / 4];/* divided by sizeof(u32) */
++ u32 keylen;
++ u32 mode;
++ u64 byte_count; /* number of bytes "uploaded" to the device */
++ u32 waitbuf; /* a partial word waiting to be completed and
++ uploaded to the device */
++ /* number of bytes to be uploaded in the waitbuf word */
++ unsigned int nbwait;
++};
++
++#define SS_SEED_LEN (192/8)
++#define SS_DATA_LEN (160/8)
++
++struct prng_context {
++ u32 seed[SS_SEED_LEN/4];
++ unsigned int slen;
++};
++
++int sunxi_hash_init(struct ahash_request *areq);
++int sunxi_hash_update(struct ahash_request *areq);
++int sunxi_hash_final(struct ahash_request *areq);
++int sunxi_hash_finup(struct ahash_request *areq);
++int sunxi_hash_digest(struct ahash_request *areq);
++
++int sunxi_ss_aes_poll(struct ablkcipher_request *areq);
++int sunxi_ss_des_poll(struct ablkcipher_request *areq);
++int sunxi_ss_cipher_init(struct crypto_tfm *tfm);
++int sunxi_ss_cipher_encrypt(struct ablkcipher_request *areq);
++int sunxi_ss_cipher_decrypt(struct ablkcipher_request *areq);
++int sunxi_ss_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen);
++int sunxi_ss_des_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen);
++int sunxi_ss_des3_setkey(struct crypto_ablkcipher *tfm, const u8 *key,
++ unsigned int keylen);
+--
+1.8.5.5
+
+ \ No newline at end of file
diff --git a/target/linux/sunxi/patches-3.14/300-dt-sun7i-add-pcduino3.patch b/target/linux/sunxi/patches-3.14/300-dt-sun7i-add-pcduino3.patch
new file mode 100644
index 0000000000..55b86d3da9
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/300-dt-sun7i-add-pcduino3.patch
@@ -0,0 +1,47 @@
+From c6c022c42e6b9115cbc36dce3f9100b90c2d2b06 Mon Sep 17 00:00:00 2001
+From: Zoltan HERPAI <wigyori@uid0.hu>
+Date: Tue, 20 May 2014 22:28:49 +0200
+Subject: [PATCH] ARM: sun7i: dt: Add board support for LinkSprite pcDuino V3
+
+The LinkSprite pcDuino V3 is an A20-based revision of the
+earlier pcDuinos. This series will add support for the board,
+along with some of its devices where the driver is accepted or
+soon-to-be-accepted into mainline.
+
+Changes since v2:
+ - update MMC entry to comply with upstream
+ - unify the 4 patches into one
+
+Changes since v1:
+ - fix cosmetic issues
+ - fix i2c entry
+ - remove unnecessary input bindings include
+ - add MMC support
+
+Signed-off-by: Zoltan HERPAI <wigyori@uid0.hu>
+---
+ arch/arm/boot/dts/Makefile | 3 +-
+ arch/arm/boot/dts/sun7i-a20-pcduino3.dts | 119 +++++++++++++++++++++++++++++++
+ 2 files changed, 121 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+
+diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
+index 6967393..b1b59ea 100644
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -353,7 +353,8 @@ dtb-$(CONFIG_MACH_SUN7I) += \
+ sun6i-a31-colombus.dtb \
+ sun7i-a20-cubieboard2.dtb \
+ sun7i-a20-cubietruck.dtb \
+- sun7i-a20-olinuxino-micro.dtb
++ sun7i-a20-olinuxino-micro.dtb \
++ sun7i-a20-pcduino3.dtb
+ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
+ tegra20-iris-512.dtb \
+ tegra20-medcom-wide.dtb \
+diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+new file mode 100644
+index 0000000..fc6a542
+--
+2.0.3
+
diff --git a/target/linux/sunxi/patches-3.14/301-dt-sun7i-update-pcduino3.patch b/target/linux/sunxi/patches-3.14/301-dt-sun7i-update-pcduino3.patch
new file mode 100644
index 0000000000..7a097d7dc3
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/301-dt-sun7i-update-pcduino3.patch
@@ -0,0 +1,13 @@
+diff -ruN old/arch/arm/boot/dts/sun7i-a20-pcduino3.dts new/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+--- old/arch/arm/boot/dts/sun7i-a20-pcduino3.dts 2014-08-01 21:28:06.000000000 +0200
++++ new/arch/arm/boot/dts/sun7i-a20-pcduino3.dts 2014-08-03 16:52:51.621238166 +0200
+@@ -12,8 +12,7 @@
+
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
+-/include/ "sunxi-ahci-reg.dtsi"
+-/include/ "sun4i-a10-usb-vbus-reg.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+ #include <dt-bindings/input/input.h>
+
+ / {
diff --git a/target/linux/sunxi/patches-3.14/302-dt-sun7i-add-bananapi-Makefile.patch b/target/linux/sunxi/patches-3.14/302-dt-sun7i-add-bananapi-Makefile.patch
new file mode 100644
index 0000000000..272b501f44
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/302-dt-sun7i-add-bananapi-Makefile.patch
@@ -0,0 +1,11 @@
+diff -ruN old/arch/arm/boot/dts/Makefile new/arch/arm/boot/dts/Makefile
+--- old/arch/arm/boot/dts/Makefile 2014-08-03 22:59:45.000000000 +0200
++++ new/arch/arm/boot/dts/Makefile 2014-08-03 23:12:30.208474257 +0200
+@@ -290,6 +290,7 @@
+ sun5i-a13-olinuxino.dtb \
+ sun5i-a13-olinuxino-micro.dtb \
+ sun6i-a31-colombus.dtb \
++ sun7i-a20-bananapi.dtb \
+ sun7i-a20-cubieboard2.dtb \
+ sun7i-a20-cubietruck.dtb \
+ sun7i-a20-olinuxino-micro.dtb \
diff --git a/target/linux/sunxi/patches-3.14/303-dt-sun7i-update-bananapi.patch b/target/linux/sunxi/patches-3.14/303-dt-sun7i-update-bananapi.patch
new file mode 100644
index 0000000000..1c8f839c0f
--- /dev/null
+++ b/target/linux/sunxi/patches-3.14/303-dt-sun7i-update-bananapi.patch
@@ -0,0 +1,13 @@
+diff -ruN old/arch/arm/boot/dts/sun7i-a20-bananapi.dts new/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+--- old/arch/arm/boot/dts/sun7i-a20-bananapi.dts 2014-08-01 21:28:06.000000000 +0200
++++ new/arch/arm/boot/dts/sun7i-a20-bananapi.dts 2014-08-04 00:49:24.552906049 +0200
+@@ -12,8 +12,7 @@
+
+ /dts-v1/;
+ /include/ "sun7i-a20.dtsi"
+-/include/ "sunxi-ahci-reg.dtsi"
+-/include/ "sun4i-a10-usb-vbus-reg.dtsi"
++/include/ "sunxi-common-regulators.dtsi"
+ #include <dt-bindings/input/input.h>
+
+ / {