sunxi: delete old kernel versions

Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2016-05-12 17:52:20 +02:00
parent 930195737a
commit be83f982a7
83 changed files with 0 additions and 18234 deletions

View file

@ -1,477 +0,0 @@
CONFIG_ADVISE_SYSCALLS=y
# CONFIG_AHCI_SUNXI is not set
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_SG_CHAIN=y
CONFIG_ARCH_HAS_TICK_BROADCAST=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NR_GPIO=416
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_SUPPORTS_UPROBES=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_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=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_HAS_SG_CHAIN=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
# CONFIG_ARM_LPAE is not set
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_ATA_SFF is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_AUDIT_GENERIC=y
CONFIG_AUTO_ZRELADDR=y
CONFIG_AVERAGE=y
CONFIG_B53=y
# CONFIG_B53_MMAP_DRIVER is not set
CONFIG_B53_PHY_DRIVER=y
CONFIG_B53_PHY_FIXUP=y
# CONFIG_B53_SRAB_DRIVER is not set
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_BPF_SYSCALL is not set
CONFIG_BUILD_BIN2C=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_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_DEFAULT_CFQ=y
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DIRECT_IO=y
CONFIG_DMADEVICES=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_SUN6I=y
CONFIG_DMA_VIRTUAL_CHANNELS=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_EMAC_ROCKCHIP is not set
# CONFIG_EMBEDDED is not set
CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_ENABLE_WARN_DEPRECATED 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_GENERIC_ALLOCATOR=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_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_GLOB=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
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_ARM_ARCH_TIMER=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_I2C_SUN6I_P2WI is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INPUT=y
# CONFIG_INPUT_AXP20X_PEK is not set
CONFIG_INPUT_KEYBOARD=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_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_JBD2=y
CONFIG_KALLSYMS=y
# CONFIG_KEYBOARD_GPIO is not set
CONFIG_KEYBOARD_SUN4I_LRADC=y
CONFIG_KSM=y
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_REGULATOR is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_LIBFDT=y
CONFIG_LOG_BUF_SHIFT=19
CONFIG_LZ4_DECOMPRESS=y
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MACH_SUN4I=y
CONFIG_MACH_SUN5I=y
CONFIG_MACH_SUN6I=y
CONFIG_MACH_SUN7I=y
# CONFIG_MACH_SUN8I is not set
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_MFD_SUN6I_PRCM=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGHT_HAVE_PCI=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
# CONFIG_MMC_DEBUG is not set
CONFIG_MMC_SUNXI=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_PTP_CLASSIFY=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_OF_RESERVED_MEM=y
CONFIG_OF_TOUCHSCREEN=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 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_SUN4I_A10=y
CONFIG_PINCTRL_SUN5I_A10S=y
CONFIG_PINCTRL_SUN5I_A13=y
CONFIG_PINCTRL_SUN6I_A31=y
CONFIG_PINCTRL_SUN6I_A31_R=y
CONFIG_PINCTRL_SUN7I_A20=y
# CONFIG_PINCTRL_SUN8I_A23 is not set
# CONFIG_PINCTRL_SUN8I_A23_R is not set
CONFIG_PINCTRL_SUNXI_COMMON=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_EVENTS=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_PWM=y
# CONFIG_PWM_FSL_FTM is not set
CONFIG_PWM_SUN4I=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_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_IRQ=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_AXP20X=y
# CONFIG_REGULATOR_DEBUG is not set
CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_REGULATOR_PWM is not set
# 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_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_SCHED_HRTICK=y
CONFIG_SCSI=y
CONFIG_SDIO_UART=y
# CONFIG_SECCOMP is not set
CONFIG_SECURITYFS=y
# CONFIG_SENSORS_PWM_FAN is not set
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_8250_NR_UARTS=8
CONFIG_SERIAL_8250_RUNTIME_UARTS=8
CONFIG_SERIO=y
# CONFIG_SERIO_APBPS2 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_SWCONFIG=y
CONFIG_SWIOTLB=y
CONFIG_SWP_EMULATE=y
CONFIG_SYSFS_SYSCALL=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_THUMB2_KERNEL is not set
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TOUCHSCREEN_SUN4I=y
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_NET_DRIVERS=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USELIB=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_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 is not set
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA_FLAG=0

View file

@ -1,560 +0,0 @@
CONFIG_ADVISE_SYSCALLS=y
# CONFIG_AHCI_SUNXI is not set
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAS_RESET_CONTROLLER=y
CONFIG_ARCH_HAS_SG_CHAIN=y
CONFIG_ARCH_HAS_TICK_BROADCAST=y
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=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_NR_GPIO=416
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_SUPPORTS_UPROBES=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_ARCH_WANT_OPTIONAL_GPIOLIB=y
CONFIG_ARM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=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=y
CONFIG_ARM_CRYPTO=y
CONFIG_ARM_GIC=y
CONFIG_ARM_HAS_SG_CHAIN=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
# CONFIG_ARM_LPAE is not set
CONFIG_ARM_PATCH_PHYS_VIRT=y
CONFIG_ARM_PSCI=y
CONFIG_ARM_THUMB=y
# CONFIG_ARM_THUMBEE is not set
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_ATA=y
CONFIG_ATAGS=y
# CONFIG_ATA_SFF is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_AUDIT_GENERIC=y
CONFIG_AUTO_ZRELADDR=y
CONFIG_AVERAGE=y
CONFIG_B53=y
# CONFIG_B53_MMAP_DRIVER is not set
CONFIG_B53_PHY_DRIVER=y
CONFIG_B53_PHY_FIXUP=y
# CONFIG_B53_SRAB_DRIVER is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_GENERIC=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_PWM=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_BPF_SYSCALL is not set
CONFIG_BUILD_BIN2C=y
CONFIG_CACHE_L2X0=y
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_CPUFREQ_DT=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_FREQ=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
CONFIG_CPU_FREQ_GOV_COMMON=y
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
CONFIG_CPU_HAS_ASID=y
# CONFIG_CPU_ICACHE_DISABLE is not set
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_THERMAL=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
CONFIG_CRC_T10DIF=y
CONFIG_CRYPTO_ABLK_HELPER=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_AEAD2=y
CONFIG_CRYPTO_AES_ARM=y
CONFIG_CRYPTO_AES_ARM_CE=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_CRCT10DIF=y
CONFIG_CRYPTO_CRYPTD=y
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_DEV_SUN4I_SS=y
CONFIG_CRYPTO_GHASH_ARM_CE=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_MANAGER=y
CONFIG_CRYPTO_MANAGER2=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA1_ARM=y
CONFIG_CRYPTO_SHA1_ARM_CE=y
CONFIG_CRYPTO_SHA1_ARM_NEON=y
CONFIG_CRYPTO_SHA256_ARM=y
CONFIG_CRYPTO_SHA2_ARM_CE=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_SHA512_ARM_NEON=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_DCACHE_WORD_ACCESS=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_UART_8250 is not set
# CONFIG_DEBUG_USER is not set
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DIRECT_IO=y
CONFIG_DMADEVICES=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_SUN6I=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DNOTIFY=y
CONFIG_DTC=y
CONFIG_DUMMY_CONSOLE=y
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_EXT4_FS=y
CONFIG_FB=y
# CONFIG_FB_BIG_ENDIAN is not set
CONFIG_FB_BOTH_ENDIAN=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_CMDLINE=y
CONFIG_FB_FOREIGN_ENDIAN=y
# CONFIG_FB_LITTLE_ENDIAN is not set
CONFIG_FB_MODE_HELPERS=y
CONFIG_FB_SIMPLE=y
CONFIG_FB_TILEBLITTING=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=y
CONFIG_FONT_SUPPORT=y
CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_FRAME_WARN=2048
CONFIG_FREEZER=y
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_CHIP=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=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_GENERIC_TIME_VSYSCALL=y
CONFIG_GLOB=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_GPIO_SYSFS=y
CONFIG_HANDLE_DOMAIN_IRQ=y
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT_MAP=y
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
CONFIG_HAVE_ARCH_BITREVERSE=y
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_ARM_ARCH_TIMER=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_MOD_ARCH_SPECIFIC=y
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_OPROFILE=y
CONFIG_HAVE_OPTPROBES=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=y
CONFIG_HOTPLUG_CPU=y
CONFIG_HWMON=y
CONFIG_HW_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_TIMERIOMEM=y
CONFIG_HZ_FIXED=0
CONFIG_I2C=y
CONFIG_I2C_BOARDINFO=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_COMPAT=y
CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_MV64XXX=y
# CONFIG_I2C_SUN6I_P2WI is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INPUT=y
CONFIG_INPUT_AXP20X_PEK=y
CONFIG_INPUT_KEYBOARD=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_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_DOMAIN_HIERARCHY=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_JBD2=y
CONFIG_KALLSYMS=y
CONFIG_KEYBOARD_SUN4I_LRADC=y
CONFIG_KSM=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_PLATFORM=y
CONFIG_LEDS_GPIO=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
CONFIG_LIBFDT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LOGO=y
CONFIG_LOGO_LINUX_CLUT224=y
CONFIG_LOGO_LINUX_MONO=y
CONFIG_LOGO_LINUX_VGA16=y
CONFIG_LOG_BUF_SHIFT=19
CONFIG_LZO_COMPRESS=y
CONFIG_LZO_DECOMPRESS=y
CONFIG_MACH_SUN4I=y
CONFIG_MACH_SUN5I=y
CONFIG_MACH_SUN6I=y
CONFIG_MACH_SUN7I=y
CONFIG_MACH_SUN8I=y
CONFIG_MACH_SUN9I=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_MFD_SUN6I_PRCM=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGHT_HAVE_PCI=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_SUNXI=y
CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_SUNXI=y
CONFIG_MTD_OF_NAND_PARTS=y
CONFIG_MULTI_IRQ_HANDLER=y
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NAMESPACES=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEON=y
# CONFIG_NET_CLS_CGROUP is not set
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NET_NS=y
CONFIG_NET_PTP_CLASSIFY=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_OF_RESERVED_MEM=y
CONFIG_OF_TOUCHSCREEN=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_OUTER_CACHE=y
CONFIG_OUTER_CACHE_SYNC=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PARTITION_ADVANCED is not set
# CONFIG_PCI is not set
# CONFIG_PCI_DOMAINS_GENERIC is not set
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_EVENTS=y
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYLIB=y
CONFIG_PHY_SUN4I_USB=y
# CONFIG_PHY_SUN9I_USB is not set
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_SINGLE is not set
CONFIG_PINCTRL_SUN4I_A10=y
CONFIG_PINCTRL_SUN5I_A10S=y
CONFIG_PINCTRL_SUN5I_A13=y
CONFIG_PINCTRL_SUN6I_A31=y
CONFIG_PINCTRL_SUN6I_A31S=y
CONFIG_PINCTRL_SUN6I_A31_R=y
CONFIG_PINCTRL_SUN7I_A20=y
CONFIG_PINCTRL_SUN8I_A23=y
CONFIG_PINCTRL_SUN8I_A23_R=y
CONFIG_PINCTRL_SUN9I_A80=y
CONFIG_PINCTRL_SUNXI_COMMON=y
# CONFIG_PL310_ERRATA_588369 is not set
# CONFIG_PL310_ERRATA_727915 is not set
# CONFIG_PL310_ERRATA_753970 is not set
# CONFIG_PL310_ERRATA_769419 is not set
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_OPP=y
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_POWER_RESET=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_EVENTS=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PROC_PID_CPUSET=y
CONFIG_PTP_1588_CLOCK=y
CONFIG_PWM=y
CONFIG_PWM_SUN4I=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_STALL_COMMON=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_IRQ=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGMAP_SPI=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_AXP20X=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_GPIO=y
CONFIG_RELAY=y
CONFIG_RESET_CONTROLLER=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_SATA_PMP=y
CONFIG_SCHED_HRTICK=y
CONFIG_SCSI=y
CONFIG_SDIO_UART=y
CONFIG_SECURITYFS=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_8250_NR_UARTS=8
CONFIG_SERIAL_8250_RUNTIME_UARTS=8
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIO=y
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_SRCU=y
# CONFIG_STAGING is not set
CONFIG_STMMAC_ETH=y
CONFIG_STMMAC_PLATFORM=y
CONFIG_STOP_MACHINE=y
CONFIG_STRICT_DEVMEM=y
CONFIG_SUN4I_DMA=y
# CONFIG_SUN4I_EMAC is not set
CONFIG_SUN4I_TIMER=y
CONFIG_SUN5I_HSTIMER=y
CONFIG_SUNXI_WATCHDOG=y
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SWCONFIG=y
CONFIG_SWIOTLB=y
CONFIG_SWP_EMULATE=y
CONFIG_SYSFS_SYSCALL=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_THERMAL=y
# CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE is not set
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
# CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE is not set
# CONFIG_THERMAL_EMULATION is not set
# CONFIG_THERMAL_GOV_FAIR_SHARE is not set
CONFIG_THERMAL_GOV_STEP_WISE=y
# CONFIG_THERMAL_GOV_USER_SPACE is not set
CONFIG_THERMAL_HWMON=y
CONFIG_THERMAL_OF=y
# CONFIG_THUMB2_KERNEL is not set
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TOUCHSCREEN_SUN4I=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_DWC2=y
# CONFIG_USB_DWC2_DEBUG is not set
CONFIG_USB_DWC2_HOST=y
CONFIG_USB_DWC2_PLATFORM=y
# CONFIG_USB_DWC2_TRACK_MISSED_SOFS is not set
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USELIB=y
# CONFIG_USER_NS is not set
CONFIG_USE_OF=y
CONFIG_UTS_NS=y
CONFIG_VDSO=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_WQ_POWER_EFFICIENT_DEFAULT is not set
CONFIG_XFRM_ALGO=y
CONFIG_XFRM_USER=y
CONFIG_XPS=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0
CONFIG_ZBOOT_ROM_TEXT=0
CONFIG_ZLIB_INFLATE=y
CONFIG_ZONE_DMA_FLAG=0

View file

@ -1,26 +0,0 @@
From 0253d14782f80cfd1741d4ddd82b83dd7d44a91e Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 28 Jul 2014 22:44:59 +0200
Subject: [PATCH] ARM: dts: sun7i: Add spi0_pins_a pinctrl setting
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -784,6 +784,13 @@
allwinner,pull = <0>;
};
+ spi0_pins_a: spi0@0 {
+ allwinner,pins = "PI10", "PI11", "PI12", "PI13", "PI14";
+ allwinner,function = "spi0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
spi1_pins_a: spi1@0 {
allwinner,pins = "PI16", "PI17", "PI18", "PI19";
allwinner,function = "spi1";

View file

@ -1,29 +0,0 @@
From e37ccbcd4587b7a2b943e23a9943b8917010b336 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 1 Oct 2014 08:39:58 +0200
Subject: [PATCH] ARM: dts: sun7i: Add uart3_pins_b pinctrl setting
The uart3_pins_a multiplexes the uart3 pins to port G, add a pinctrl entry
for mapping them to port H (as used on the Bananapi).
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -677,6 +677,13 @@
allwinner,pull = <0>;
};
+ uart3_pins_b: uart3@1 {
+ allwinner,pins = "PH0", "PH1";
+ allwinner,function = "uart3";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
uart4_pins_a: uart4@0 {
allwinner,pins = "PG10", "PG11";
allwinner,function = "uart4";

View file

@ -1,26 +0,0 @@
From f65624ca1b67c5683317b75da2c09ffadc22fa2e Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 1 Oct 2014 00:40:57 +0200
Subject: [PATCH] ARM: dts: sun7i: Add mmc2_pins_a pinctrl definition
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -833,6 +833,13 @@
allwinner,pull = <1>;
};
+ mmc2_pins_a: mmc2@0 {
+ allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11";
+ allwinner,function = "mmc2";
+ allwinner,drive = <2>;
+ allwinner,pull = <1>;
+ };
+
mmc3_pins_a: mmc3@0 {
allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
allwinner,function = "mmc3";

View file

@ -1,400 +0,0 @@
From 2c1fab89e83245a520871e807e233e66cbdb7c57 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.
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>
--
Changes in v2:
-Change devicetree bindings to use a per key subnode, like gpio-keys does
---
.../devicetree/bindings/input/sun4i-lradc-keys.txt | 62 +++++
MAINTAINERS | 7 +
drivers/input/keyboard/Kconfig | 10 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/sun4i-lradc-keys.c | 258 +++++++++++++++++++++
5 files changed, 338 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
create mode 100644 drivers/input/keyboard/sun4i-lradc-keys.c
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
@@ -0,0 +1,62 @@
+Allwinner sun4i low res adc attached tablet keys
+------------------------------------------------
+
+Required properties:
+ - compatible: "allwinner,sun4i-a10-lradc-keys"
+ - reg: mmio address range of the chip
+ - interrupts: interrupt to which the chip is connected
+ - vref-supply: powersupply for the lradc reference voltage
+
+Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
+
+Required subnode-properties:
+ - label: Descriptive name of the key.
+ - linux,code: Keycode to emit.
+ - channel: Channel this key is attached to, mut be 0 or 1.
+ - voltage: Voltage in µV at lradc input when this key is pressed.
+
+Example:
+
+#include <dt-bindings/input/input.h>
+
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ vref-supply = <&reg_vcc3v0>;
+
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
+
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
+
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
+
+ button@795 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <795090>;
+ };
+
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
+ };
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9002,6 +9002,13 @@ F: arch/m68k/sun3*/
F: arch/m68k/include/asm/sun3*
F: drivers/net/ethernet/i825xx/sun3*
+SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+L: linux-input@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+F: drivers/input/keyboard/sun4i-lradc-keys.c
+
SUNDANCE NETWORK DRIVER
M: Denis Kirjanov <kda@linux-powerpc.org>
L: netdev@vger.kernel.org
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -567,6 +567,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
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-k
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.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
--- /dev/null
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -0,0 +1,258 @@
+/*
+ * 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 channel 0 since
+ * there are no boards known to use channel 1.
+ */
+
+#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/regulator/consumer.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)
+
+struct sun4i_lradc_keymap {
+ u32 voltage;
+ u32 keycode;
+};
+
+struct sun4i_lradc_data {
+ struct device *dev;
+ struct input_dev *input;
+ void __iomem *base;
+ struct regulator *vref_supply;
+ struct sun4i_lradc_keymap *chan0_map;
+ u32 chan0_map_count;
+ u32 chan0_keycode;
+ u32 vref;
+};
+
+static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
+{
+ struct sun4i_lradc_data *lradc = dev_id;
+ u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;
+
+ 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) & 0x3f;
+ voltage = val * lradc->vref / 63;
+
+ for (i = 0; i < lradc->chan0_map_count; i++) {
+ diff = abs(lradc->chan0_map[i].voltage - voltage);
+ if (diff < closest) {
+ closest = diff;
+ keycode = lradc->chan0_map[i].keycode;
+ }
+ }
+
+ lradc->chan0_keycode = keycode;
+ 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);
+ int ret;
+
+ ret = regulator_enable(lradc->vref_supply);
+ if (ret)
+ return ret;
+
+ /* lradc Vref internally is divided by 2/3 */
+ lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
+
+ /*
+ * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
+ * stabilize on press, wait (1 + 1) * 4 ms for key release
+ */
+ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
+ SAMPLE_RATE(0) | 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);
+
+ regulator_disable(lradc->vref_supply);
+}
+
+static int sun4i_lradc_probe(struct platform_device *pdev)
+{
+ struct sun4i_lradc_data *lradc;
+ struct device *dev = &pdev->dev;
+ struct device_node *pp, *np = dev->of_node;
+ u32 channel;
+ int i, ret;
+
+ lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
+ if (!lradc)
+ return -ENOMEM;
+
+ lradc->chan0_map_count = of_get_child_count(np);
+ lradc->chan0_map = devm_kmalloc(dev, lradc->chan0_map_count *
+ sizeof(struct sun4i_lradc_keymap), GFP_KERNEL);
+ if (!lradc->chan0_map)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(np, pp) {
+ struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
+
+ ret = of_property_read_u32(pp, "channel", &channel);
+ if (ret || channel != 0) {
+ dev_err(dev, "%s: Inval channel prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(pp, "voltage", &map->voltage);
+ if (ret) {
+ dev_err(dev, "%s: Inval voltage prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(pp, "linux,code", &map->keycode);
+ if (ret) {
+ dev_err(dev, "%s: Inval linux,code prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ lradc->vref_supply = devm_regulator_get(dev, "vref");
+ if (IS_ERR(lradc->vref_supply))
+ return PTR_ERR(lradc->vref_supply);
+
+ 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 < lradc->chan0_map_count; i++)
+ set_bit(lradc->chan0_map[i].keycode, 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-a10-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-a10-lradc-keys", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
+
+static struct platform_driver sun4i_lradc_driver = {
+ .driver = {
+ .name = "sun4i-a10-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");

View file

@ -1,26 +0,0 @@
From f39ea4358d2e4b939b8ca55ee344d3c8fdfc0a6a 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(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -669,6 +669,13 @@
status = "disabled";
};
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;

View file

@ -1,167 +0,0 @@
From 3bf1194692f3a275e0776d3c0b6f17826cc01baa 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 | 45 ++++++++++++++++++++++--
arch/arm/boot/dts/sun5i-a10s.dtsi | 7 ++++
arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 45 ++++++++++++++++++++++--
arch/arm/boot/dts/sun5i-a13.dtsi | 7 ++++
4 files changed, 100 insertions(+), 4 deletions(-)
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -12,8 +12,9 @@
*/
/dts-v1/;
-/include/ "sun5i-a10s.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/input/input.h>
/ {
model = "Olimex A10s-Olinuxino Micro";
@@ -98,6 +99,46 @@
};
};
+ lradc: lradc@01c22800 {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
+
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
+
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
+
+ button@795 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <795090>;
+ };
+
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
+ };
+
uart0: serial@01c28000 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -520,6 +520,13 @@
reg = <0x01c20c90 0x10>;
};
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -12,8 +12,9 @@
*/
/dts-v1/;
-/include/ "sun5i-a13.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/input/input.h>
/ {
model = "Olimex A13-Olinuxino";
@@ -66,6 +67,46 @@
};
};
+ lradc: lradc@01c22800 {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
+
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
+
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
+
+ button@795 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <795090>;
+ };
+
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
+ };
+
uart1: serial@01c28400 {
pinctrl-names = "default";
pinctrl-0 = <&uart1_pins_b>;
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -468,6 +468,13 @@
reg = <0x01c20c90 0x10>;
};
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <31>;
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;

View file

@ -1,102 +0,0 @@
From a735a9b354ebc1a17b648ef8c3482c71fdbf40da 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 | 59 ++++++++++++++++++++++++-
arch/arm/boot/dts/sun7i-a20.dtsi | 7 +++
2 files changed, 64 insertions(+), 2 deletions(-)
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -12,8 +12,9 @@
*/
/dts-v1/;
-/include/ "sun7i-a20.dtsi"
-/include/ "sunxi-common-regulators.dtsi"
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/input/input.h>
/ {
model = "Olimex A20-Olinuxino Micro";
@@ -100,6 +101,60 @@
};
};
+ lradc: lradc@01c22800 {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@191 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <191274>;
+ };
+
+ button@392 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <392644>;
+ };
+
+ button@601 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <601151>;
+ };
+
+ button@795 {
+ label = "Search";
+ linux,code = <KEY_SEARCH>;
+ channel = <0>;
+ voltage = <795090>;
+ };
+
+ button@987 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <987387>;
+ };
+
+ button@1184 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1184678>;
+ };
+
+ button@1398 {
+ label = "Enter";
+ linux,code = <KEY_ENTER>;
+ channel = <0>;
+ voltage = <1398804>;
+ };
+ };
+
uart0: serial@01c28000 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_a>;
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -911,6 +911,13 @@
status = "disabled";
};
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <0 31 4>;
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun7i-a20-sid";
reg = <0x01c23800 0x200>;

View file

@ -1,79 +0,0 @@
From 2e2493cd07405dfa88e53199b47bdbbb5336fdce Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 16 Jun 2014 20:01:12 +0200
Subject: [PATCH] touchscreen: sun4i-ts: A10 (sun4i) has a different
temperature curve
Testing has revealed that the temperature in the rtp controller of the A10
(sun4i) SoC has a different curve then on the A13 (sun5i) and later models.
Add a new sun5i-a13-ts compatible to differentiate the newer models and
set the curve based on the compatible string.
This fixes the temperature reported on the A10 being much higher then
expected.
Note the new curve is still not ideal on all A10-s, that seems to have to
do with there being a large spread between different A10-s out there.
Reported-by: Tong Zhang <lovewilliam@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
.../devicetree/bindings/input/touchscreen/sun4i.txt | 2 +-
drivers/input/touchscreen/sun4i-ts.c | 13 ++++++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
--- a/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/sun4i.txt
@@ -2,7 +2,7 @@ sun4i resistive touchscreen controller
--------------------------------------
Required properties:
- - compatible: "allwinner,sun4i-a10-ts"
+ - compatible: "allwinner,sun4i-a10-ts" or "allwinner,sun5i-a13-ts"
- reg: mmio address range of the chip
- interrupts: interrupt to which the chip is connected
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -111,6 +111,8 @@ struct sun4i_ts_data {
unsigned int irq;
bool ignore_fifo_data;
int temp_data;
+ int temp_offset;
+ int temp_step;
};
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
@@ -189,7 +191,8 @@ static ssize_t show_temp(struct device *
if (ts->temp_data == -1)
return -EAGAIN;
- return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
+ return sprintf(buf, "%d\n",
+ (ts->temp_data - ts->temp_offset) * ts->temp_step);
}
static ssize_t show_temp_label(struct device *dev,
@@ -224,6 +227,13 @@ static int sun4i_ts_probe(struct platfor
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1;
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts")) {
+ ts->temp_offset = 1900;
+ ts->temp_step = 100;
+ } else {
+ ts->temp_offset = 1447;
+ ts->temp_step = 100;
+ }
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
if (ts_attached) {
@@ -318,6 +328,7 @@ static int sun4i_ts_remove(struct platfo
static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", },
+ { .compatible = "allwinner,sun5i-a13-ts", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);

View file

@ -1,51 +0,0 @@
From ff774d842a2bf9136b9c7ddd7f5085a9062705ac Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 16 Jun 2014 20:06:43 +0200
Subject: [PATCH] ARM: dts: sunxi: Adjust touchscreen compatible for sun5i and
later
The touchscreen controller in the A13 and later has a different temperature
curve than the one in the original A10, change the compatible for the A13 and
later so that the kernel will use the correct curve.
Reported-by: Tong Zhang <lovewilliam@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun5i-a10s.dtsi | 2 +-
arch/arm/boot/dts/sun5i-a13.dtsi | 2 +-
arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -533,7 +533,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
+ compatible = "allwinner,sun5i-a13-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -481,7 +481,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
+ compatible = "allwinner,sun5i-a13-ts";
reg = <0x01c25000 0x100>;
interrupts = <29>;
};
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -924,7 +924,7 @@
};
rtp: rtp@01c25000 {
- compatible = "allwinner,sun4i-a10-ts";
+ compatible = "allwinner,sun5i-a13-ts";
reg = <0x01c25000 0x100>;
interrupts = <0 29 4>;
};

View file

@ -1,332 +0,0 @@
From 63d559304a15ffead2fa1014b93dbcabf516c257 Mon Sep 17 00:00:00 2001
From: Carlo Caione <carlo@caione.org>
Date: Mon, 19 May 2014 21:47:45 +0200
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>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
drivers/input/misc/Kconfig | 11 ++
drivers/input/misc/Makefile | 1 +
drivers/input/misc/axp20x-pek.c | 281 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 293 insertions(+)
create mode 100644 drivers/input/misc/axp20x-pek.c
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -404,6 +404,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
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_INPUT_POWERMATE) += powerm
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
--- /dev/null
+++ b/drivers/input/misc/axp20x-pek.c
@@ -0,0 +1,281 @@
+/*
+ * 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)
+
+struct axp20x_pek {
+ struct axp20x_dev *axp20x;
+ struct input_dev *input;
+ int irq_dbr;
+ int irq_dbf;
+};
+
+struct axp20x_time {
+ unsigned int time;
+ unsigned int idx;
+};
+
+static const struct axp20x_time startup_time[] = {
+ { .time = 128, .idx = 0 },
+ { .time = 1000, .idx = 2 },
+ { .time = 3000, .idx = 1 },
+ { .time = 2000, .idx = 3 },
+};
+
+static const struct axp20x_time shutdown_time[] = {
+ { .time = 4000, .idx = 0 },
+ { .time = 6000, .idx = 1 },
+ { .time = 8000, .idx = 2 },
+ { .time = 10000, .idx = 3 },
+};
+
+struct axp20x_pek_ext_attr {
+ const struct axp20x_time *p_time;
+ unsigned int mask;
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
+ .p_time = startup_time,
+ .mask = AXP20X_PEK_STARTUP_MASK,
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
+ .p_time = 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;
+}
+
+static 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;
+
+ 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 == axp20x_ea->p_time[i].idx)
+ val = axp20x_ea->p_time[i].time;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static 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];
+ size_t len;
+ int ret, i;
+ unsigned int val, idx = 0;
+ unsigned int best_err = UINT_MAX;
+
+ 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';
+
+ ret = kstrtouint(val_str, 10, &val);
+ if (ret)
+ return ret;
+
+ for (i = 3; i >= 0; i--) {
+ unsigned int err;
+
+ err = abs(axp20x_ea->p_time[i].time - val);
+ if (err < best_err) {
+ best_err = err;
+ idx = axp20x_ea->p_time[i].idx;
+ }
+
+ if (!err)
+ break;
+ }
+
+ idx <<= ffs(axp20x_ea->mask) - 1;
+ ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
+ AXP20X_PEK_KEY,
+ axp20x_ea->mask, idx);
+ if (ret != 0)
+ return -EINVAL;
+ return count;
+}
+
+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 = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
+ .var = &axp20x_pek_shutdown_ext_attr
+};
+
+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_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbr", idev);
+ if (error < 0) {
+ dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
+ axp20x_pek->irq_dbr, error);
+
+ return error;
+ }
+
+ error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbf", idev);
+ if (error < 0) {
+ dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
+ axp20x_pek->irq_dbf, error);
+ return error;
+ }
+
+ error = device_create_file(&pdev->dev, &axp20x_dev_attr_startup.attr);
+ if (error)
+ return error;
+
+ error = device_create_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr);
+ if (error)
+ goto clear_startup_attr;
+
+ error = input_register_device(idev);
+ if (error) {
+ dev_err(axp20x->dev, "Can't register input device: %d\n", error);
+ goto clear_attr;
+ }
+
+ platform_set_drvdata(pdev, axp20x_pek);
+
+ return 0;
+
+clear_attr:
+ device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr);
+
+clear_startup_attr:
+ device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr);
+
+ return error;
+}
+
+int axp20x_pek_remove(struct platform_device *pdev)
+{
+ device_remove_file(&pdev->dev, &axp20x_dev_attr_shutdown.attr);
+ device_remove_file(&pdev->dev, &axp20x_dev_attr_startup.attr);
+
+ return 0;
+}
+
+static struct platform_driver axp20x_pek_driver = {
+ .probe = axp20x_pek_probe,
+ .remove = axp20x_pek_remove,
+ .driver = {
+ .name = "axp20x-pek",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(axp20x_pek_driver);
+
+MODULE_DESCRIPTION("axp20x Power Button");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");

View file

@ -1,402 +0,0 @@
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -263,6 +263,15 @@ config PWM_STI
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
+config PWM_SUN4I
+ tristate "Allwinner sun4i PWM support"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ Generic PWM framework driver for Allwinner sun4i and sun7i SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sun4i.
+
config PWM_TEGRA
tristate "NVIDIA Tegra PWM support"
depends on ARCH_TEGRA
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockch
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
+obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
--- /dev/null
+++ b/drivers/pwm/pwm-sun4i.c
@@ -0,0 +1,371 @@
+/*
+ * Driver for Allwinner sun4i 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/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define PWM_CTRL_REG 0x0
+
+#define PWM_CH_PRD_BASE 0x4
+#define PWM_CH_PRD_OFFSET 0x4
+#define PWM_CH_PRD(ch) (PWM_CH_PRD_BASE + PWM_CH_PRD_OFFSET * (ch))
+
+#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_OFFSET 1
+#define PWM_RDY(ch) BIT(PWM_RDY_BASE + PWM_RDY_OFFSET * (ch))
+
+#define PWM_PRD(prd) (((prd) - 1) << 16)
+#define PWM_PRD_MASK GENMASK(15, 0)
+
+#define PWM_DTY_MASK GENMASK(15, 0)
+
+#define BIT_CH(bit, chan) ((bit) << ((chan) * PWMCH_OFFSET))
+
+static const u32 prescaler_table[] = {
+ 120,
+ 180,
+ 240,
+ 360,
+ 480,
+ 0,
+ 0,
+ 0,
+ 12000,
+ 24000,
+ 36000,
+ 48000,
+ 72000,
+ 0,
+ 0,
+ 0, /* Actually 1 but tested separately */
+};
+
+struct sun4i_pwm_data {
+ bool has_prescaler_bypass;
+ bool has_rdy;
+};
+
+struct sun4i_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+ struct mutex ctrl_lock;
+ const struct sun4i_pwm_data *data;
+};
+
+static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct sun4i_pwm_chip, chip);
+}
+
+static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *chip,
+ unsigned long offset)
+{
+ return readl(chip->base + offset);
+}
+
+static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
+ u32 val, unsigned long offset)
+{
+ writel(val, chip->base + offset);
+}
+
+static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 clk_rate, prd, dty, val, clk_gate;
+ u64 div = 0;
+ unsigned int prescaler = 0;
+ int err;
+
+ clk_rate = clk_get_rate(sun4i_pwm->clk);
+
+ if (sun4i_pwm->data->has_prescaler_bypass) {
+ /* First, test without any prescaler when available */
+ prescaler = PWM_PRESCAL_MASK;
+ /*
+ * When not using any prescaler, the clock period in nanoseconds
+ * is not an integer so round it half up instead of
+ * truncating to get less surprising values.
+ */
+ div = clk_rate * (u64)period_ns + NSEC_PER_SEC/2;
+ do_div(div, NSEC_PER_SEC);
+ if (div - 1 > PWM_PRD_MASK)
+ prescaler = 0;
+ }
+
+ if (prescaler == 0) {
+ /* Go up from the first divider */
+ for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
+ if (!prescaler_table[prescaler])
+ continue;
+ div = clk_rate / prescaler_table[prescaler];
+ div = div * (u64)period_ns;
+ do_div(div, NSEC_PER_SEC);
+ if (div - 1 <= PWM_PRD_MASK)
+ break;
+ }
+
+ if (div - 1 > PWM_PRD_MASK) {
+ dev_err(chip->dev, "period exceeds the maximum value\n");
+ return -EINVAL;
+ }
+ }
+
+ prd = div;
+ div *= duty_ns;
+ do_div(div, period_ns);
+ dty = div;
+
+ err = clk_prepare_enable(sun4i_pwm->clk);
+ if (err) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return err;
+ }
+
+ mutex_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+
+ if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
+ mutex_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_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);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ }
+
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
+ val |= BIT_CH(prescaler, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+
+ val = (dty & PWM_DTY_MASK) | PWM_PRD(prd);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
+
+ if (clk_gate) {
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val |= clk_gate;
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ }
+
+ mutex_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_pwm->clk);
+
+ return 0;
+}
+
+static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+ int ret;
+
+ ret = clk_prepare_enable(sun4i_pwm->clk);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+
+ mutex_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_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);
+
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+
+ mutex_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_pwm->clk);
+
+ return 0;
+}
+
+static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+ int ret;
+
+ ret = clk_prepare_enable(sun4i_pwm->clk);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+
+ mutex_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val |= BIT_CH(PWM_EN, pwm->hwpwm);
+ val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ mutex_unlock(&sun4i_pwm->ctrl_lock);
+
+ return 0;
+}
+
+static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+
+ mutex_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
+ val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ mutex_unlock(&sun4i_pwm->ctrl_lock);
+
+ clk_disable_unprepare(sun4i_pwm->clk);
+}
+
+static const struct pwm_ops sun4i_pwm_ops = {
+ .config = sun4i_pwm_config,
+ .set_polarity = sun4i_pwm_set_polarity,
+ .enable = sun4i_pwm_enable,
+ .disable = sun4i_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
+ .has_prescaler_bypass = false,
+ .has_rdy = false,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
+ .has_prescaler_bypass = true,
+ .has_rdy = true,
+};
+
+static const struct of_device_id sun4i_pwm_dt_ids[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-pwm",
+ .data = &sun4i_pwm_data_a10,
+ }, {
+ .compatible = "allwinner,sun7i-a20-pwm",
+ .data = &sun4i_pwm_data_a20,
+ }, {
+ /* sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
+
+static int sun4i_pwm_probe(struct platform_device *pdev)
+{
+ struct sun4i_pwm_chip *pwm;
+ struct resource *res;
+ u32 val;
+ int i, ret;
+ const struct of_device_id *match;
+
+ match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev);
+
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm->base))
+ return PTR_ERR(pwm->base);
+
+ pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm->clk))
+ return PTR_ERR(pwm->clk);
+
+ pwm->chip.dev = &pdev->dev;
+ pwm->chip.ops = &sun4i_pwm_ops;
+ pwm->chip.base = -1;
+ pwm->chip.npwm = 2;
+ pwm->chip.can_sleep = true;
+ pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+ pwm->chip.of_pwm_n_cells = 3;
+ pwm->data = match->data;
+
+ mutex_init(&pwm->ctrl_lock);
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+ goto error;
+ }
+
+ platform_set_drvdata(pdev, pwm);
+
+ ret = clk_prepare_enable(pwm->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable PWM clock\n");
+ goto clk_error;
+ }
+
+ val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
+ for (i = 0; i < pwm->chip.npwm; i++) {
+ if (!(val & BIT_CH(PWM_ACT_STATE, i)))
+ pwm->chip.pwms[i].polarity = PWM_POLARITY_INVERSED;
+ }
+ clk_disable_unprepare(pwm->clk);
+
+ return 0;
+
+clk_error:
+ pwmchip_remove(&pwm->chip);
+
+error:
+ mutex_destroy(&pwm->ctrl_lock);
+ return ret;
+}
+
+static int sun4i_pwm_remove(struct platform_device *pdev)
+{
+ struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+ mutex_destroy(&pwm->ctrl_lock);
+
+ return pwmchip_remove(&pwm->chip);
+}
+
+static struct platform_driver sun4i_pwm_driver = {
+ .driver = {
+ .name = "sun4i-pwm",
+ .of_match_table = sun4i_pwm_dt_ids,
+ },
+ .probe = sun4i_pwm_probe,
+ .remove = sun4i_pwm_remove,
+};
+module_platform_driver(sun4i_pwm_driver);
+
+MODULE_ALIAS("platform:sun4i-pwm");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner sun4i PWM driver");
+MODULE_LICENSE("GPL v2");

View file

@ -1,140 +0,0 @@
From 8c2057afe84c074ef7cd3ee2ec8e9bed835b9e93 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <s.hauer@pengutronix.de>
Date: Wed, 21 May 2014 19:50:04 +0200
Subject: [PATCH] mmc: Add SDIO function devicetree subnode parsing
This adds SDIO devicetree subnode parsing to the mmc core. While
SDIO devices are runtime probable they sometimes need nonprobable
additional information on embedded systems, like an additional gpio
interrupt or a clock. This patch makes it possible to supply this
information from the devicetree. SDIO drivers will find a pointer
to the devicenode in their devices of_node pointer.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
[hdegoede@redhat.com: Misc. cleanups]
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mmc/core/bus.c | 4 ++++
drivers/mmc/core/core.c | 28 ++++++++++++++++++++++++++++
drivers/mmc/core/core.h | 3 +++
drivers/mmc/core/sdio_bus.c | 11 +++++++++++
4 files changed, 46 insertions(+)
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
@@ -352,6 +353,8 @@ int mmc_add_card(struct mmc_card *card)
#endif
mmc_init_context_info(card->host);
+ card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+
ret = device_add(&card->dev);
if (ret)
return ret;
@@ -380,6 +383,7 @@ void mmc_remove_card(struct mmc_card *ca
mmc_hostname(card->host), card->rca);
}
device_del(&card->dev);
+ of_node_put(card->dev.of_node);
}
put_device(&card->dev);
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1231,6 +1231,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage);
#endif /* CONFIG_OF */
+static int mmc_of_get_func_num(struct device_node *node)
+{
+ u32 reg;
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", &reg);
+ if (ret < 0)
+ return ret;
+
+ return reg;
+}
+
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+ unsigned func_num)
+{
+ struct device_node *node;
+
+ if (!host->parent || !host->parent->of_node)
+ return NULL;
+
+ for_each_child_of_node(host->parent->of_node, node) {
+ if (mmc_of_get_func_num(node) == func_num)
+ return node;
+ }
+
+ return NULL;
+}
+
#ifdef CONFIG_REGULATOR
/**
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -32,6 +32,9 @@ struct mmc_bus_ops {
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+ unsigned func_num);
+
void mmc_init_erase(struct mmc_card *card);
void mmc_set_chip_select(struct mmc_host *host, int mode);
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -22,7 +22,9 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
+#include <linux/of.h>
+#include "core.h"
#include "sdio_cis.h"
#include "sdio_bus.h"
@@ -303,6 +305,13 @@ static void sdio_acpi_set_handle(struct
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
#endif
+static void sdio_set_of_node(struct sdio_func *func)
+{
+ struct mmc_host *host = func->card->host;
+
+ func->dev.of_node = mmc_of_find_child_device(host, func->num);
+}
+
/*
* Register a new SDIO function with the driver model.
*/
@@ -312,6 +321,7 @@ int sdio_add_func(struct sdio_func *func
dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
+ sdio_set_of_node(func);
sdio_acpi_set_handle(func);
ret = device_add(&func->dev);
if (ret == 0) {
@@ -335,6 +345,7 @@ void sdio_remove_func(struct sdio_func *
dev_pm_domain_detach(&func->dev, false);
device_del(&func->dev);
+ of_node_put(func->dev.of_node);
put_device(&func->dev);
}

View file

@ -1,64 +0,0 @@
From e4127db9b980a5684c537d9010ed2aaa05a1e79a Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sat, 24 May 2014 20:53:49 +0200
Subject: [PATCH] ARM: dts: sun7i: Add OOB irq support to boards with broadcom
sdio wifi
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 11 +++++++++++
arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts | 11 +++++++++++
2 files changed, 22 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -31,12 +31,23 @@
};
mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
};
usbphy: phy@01c13400 {
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -29,12 +29,23 @@
};
mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
};
usbphy: phy@01c13400 {

View file

@ -1,73 +0,0 @@
From c6e2b7dad39a7887f935458d1c8de84db06243e1 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(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -103,6 +103,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>;
+ };
};
pwm: pwm@01c20e00 {
@@ -123,6 +137,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>;
@@ -214,4 +234,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>;
+ };
+ };
};

View file

@ -1,17 +0,0 @@
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -577,6 +577,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>;

File diff suppressed because it is too large Load diff

View file

@ -1,245 +0,0 @@
From 29b4146ec174f0f598d6b454caa335e8f57e392b Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 28 Jul 2014 23:05:14 +0200
Subject: [PATCH] ARM: dts: sun7i: Add Banana Pi board
The Banana Pi is an A20 based development board using Raspberry Pi compatible
IO headers. It comes with 1 GB RAM, 1 Gb ethernet, 2x USB host, sata, hdmi
and stereo audio out + various expenansion headers:
http://www.lemaker.org/
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/sun7i-a20-bananapi.dts | 214 +++++++++++++++++++++++++++++++
2 files changed, 215 insertions(+)
create mode 100644 arch/arm/boot/dts/sun7i-a20-bananapi.dts
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -435,6 +435,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-hummingbird.dtb \
sun6i-a31-m9.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
+ sun7i-a20-bananapi.dtb \
sun7i-a20-cubieboard2.dtb \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "LeMaker Banana Pi";
+ compatible = "lemaker,bananapi", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ spi0: spi@01c05000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>;
+ status = "okay";
+ };
+
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 0>; /* PH10 */
+ cd-inverted;
+ 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";
+ };
+
+ ahci: sata@01c18000 {
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <0>;
+ allwinner,pull = <1>;
+ };
+
+ gmac_power_pin_bananapi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_bananapi: led_pins@0 {
+ allwinner,pins = "PH24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart3: serial@01c28c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_b>;
+ status = "okay";
+ };
+
+ uart7: serial@01c29c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ i2c2: i2c@01c2b400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_bananapi>;
+
+ green {
+ label = "bananapi:green:usr";
+ gpios = <&pio 7 24 0>;
+ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_bananapi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <50000>;
+ enable-active-high;
+ gpio = <&pio 7 23 0>;
+ };
+};

View file

@ -1,291 +0,0 @@
From 3613d535a77270eaf15a5f988a48434c7d1530f2 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 7 Jan 2015 20:44:52 +0100
Subject: [PATCH] ARM: dts: sun7i: Add dts file for Bananapro board
Add support for the new Bananapro A20 development board from lemaker.org.
This board features 1G RAM, 2 USB A receptacles, 1 micro USB receptacle for
OTG, 1 micro USB receptacle for power, HDMI, sata, Gbit ethernet, ir receiver,
3.5 mm jack for a/v out, on board microphone, 40 gpio pins and sdio wifi.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/sun7i-a20-bananapro.dts | 261 ++++++++++++++++++++++++++++++
2 files changed, 262 insertions(+)
create mode 100644 arch/arm/boot/dts/sun7i-a20-bananapro.dts
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -436,6 +436,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-m9.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-bananapi.dtb \
+ sun7i-a20-bananapro.dtb \
sun7i-a20-cubieboard2.dtb \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-bananapro.dts
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file 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 file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "LeMaker Banana Pro";
+ compatible = "lemaker,bananapro", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ spi0: spi@01c05000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>;
+ status = "okay";
+ };
+
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 0>; /* PH10 */
+ cd-inverted;
+ status = "okay";
+ };
+
+ mmc3: mmc@01c12000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>;
+ vmmc-supply = <&reg_vmmc3>;
+ bus-width = <4>;
+ non-removable;
+ 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";
+ };
+
+ ahci: sata@01c18000 {
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ usb1_vbus_pin_bananapro: usb1_vbus_pin@0 {
+ allwinner,pins = "PH0";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ usb2_vbus_pin_bananapro: usb2_vbus_pin@0 {
+ allwinner,pins = "PH1";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <0>;
+ allwinner,pull = <1>;
+ };
+
+ vmmc3_pin_bananapro: vmmc3_pin@0 {
+ allwinner,pins = "PH22";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ gmac_power_pin_bananapi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_bananapi: led_pins@0 {
+ allwinner,pins = "PH24", "PG2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart2: serial@01c28800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins_a>;
+ status = "okay";
+ };
+
+ uart7: serial@01c29c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ i2c2: i2c@01c2b400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_bananapi>;
+
+ green {
+ label = "bananapi:green:usr";
+ gpios = <&pio 7 24 0>;
+ };
+ blue {
+ label = "bananapi:blue:usr";
+ gpios = <&pio 6 2 0>;
+ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ pinctrl-0 = <&usb1_vbus_pin_bananapro>;
+ gpio = <&pio 7 0 0>; /* PH0 */
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ pinctrl-0 = <&usb2_vbus_pin_bananapro>;
+ gpio = <&pio 7 1 0>; /* PH1 */
+ status = "okay";
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_bananapi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 0>;
+ };
+
+ reg_vmmc3: vmmc3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&vmmc3_pin_bananapro>;
+ regulator-name = "vmmc3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 7 22 0>;
+ };
+};

View file

@ -1,248 +0,0 @@
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -441,6 +441,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
+ sun7i-a20-lamobo-r1.dtb \
sun7i-a20-olinuxino-lime.dtb \
sun7i-a20-olinuxino-micro.dtb \
sun7i-a20-pcduino3.dtb
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2015 Daniel Golle <daniel@makrotopia.org>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Lamobo R1";
+ compatible = "lamobo,lamobo-r1", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ spi0: spi@01c05000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>;
+ status = "okay";
+ };
+
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_lamobo>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 0>; /* PH10 */
+ cd-inverted;
+ 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";
+ };
+
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ mmc0_cd_pin_lamobo: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <0>;
+ allwinner,pull = <1>;
+ };
+
+ gmac_power_pin_lamobo: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_lamobo: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <1>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ 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";
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart3: serial@01c28c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_b>;
+ status = "okay";
+ };
+
+ uart7: serial@01c29c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ 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";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_lamobo>;
+
+ green {
+ label = "lamobo:green:usr";
+ gpios = <&pio 7 24 0>;
+ default-state = "on";
+ };
+ };
+
+ reg_ahci_5v: ahci-5v {
+ status = "okay";
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_lamobo>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 0>;
+ status = "okay";
+ };
+};

View file

@ -1,330 +0,0 @@
From f05be589ff32e87821b86845625ed3d402d37dc7 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Fri, 10 Apr 2015 12:09:01 +0800
Subject: [PATCH] mfd: axp20x: Add AXP22x PMIC support
Add support for the AXP22x PMIC devices to the existing AXP20x driver.
This includes the AXP221 and AXP223, which are identical except for
the external data bus. Only AXP221 is added for now. AXP223 will be
added after it's Reduced Serial Bus (RSB) interface is supported.
AXP22x defines a new set of registers, power supplies and regulators,
but most of the API is similar to the AXP20x ones.
A new irq chip definition is used, even though the available interrupts
on AXP22x is a subset of those on AXP20x. This is done so the interrupt
numbers match those on the datasheet.
This patch only enables the interrupts, system power-off function, and PEK
sub-device. The regulator driver must first support different variants
before we enable it from the mfd driver.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
[wens@csie.org: fix interrupts and move regulators to separate patch]
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/axp20x.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 86 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 184 insertions(+)
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -32,6 +32,7 @@
static const char * const axp20x_model_names[] = {
"AXP202",
"AXP209",
+ "AXP221",
"AXP288",
};
@@ -54,6 +55,25 @@ static const struct regmap_access_table
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
+static const struct regmap_range axp22x_writeable_ranges[] = {
+ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP22X_BATLOW_THRES1),
+};
+
+static const struct regmap_range axp22x_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
+};
+
+static const struct regmap_access_table axp22x_writeable_table = {
+ .yes_ranges = axp22x_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp22x_writeable_ranges),
+};
+
+static const struct regmap_access_table axp22x_volatile_table = {
+ .yes_ranges = axp22x_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp22x_volatile_ranges),
+};
+
static const struct regmap_range axp288_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
@@ -87,6 +107,20 @@ static struct resource axp20x_pek_resour
},
};
+static struct resource axp22x_pek_resources[] = {
+ {
+ .name = "PEK_DBR",
+ .start = AXP22X_IRQ_PEK_RIS_EDGE,
+ .end = AXP22X_IRQ_PEK_RIS_EDGE,
+ .flags = IORESOURCE_IRQ,
+ }, {
+ .name = "PEK_DBF",
+ .start = AXP22X_IRQ_PEK_FAL_EDGE,
+ .end = AXP22X_IRQ_PEK_FAL_EDGE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static struct resource axp288_fuel_gauge_resources[] = {
{
.start = AXP288_IRQ_QWBTU,
@@ -129,6 +163,15 @@ static const struct regmap_config axp20x
.cache_type = REGCACHE_RBTREE,
};
+static const struct regmap_config axp22x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp22x_writeable_table,
+ .volatile_table = &axp22x_volatile_table,
+ .max_register = AXP22X_BATLOW_THRES1,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static const struct regmap_config axp288_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -181,6 +224,34 @@ static const struct regmap_irq axp20x_re
INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
};
+static const struct regmap_irq axp22x_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP22X, ACIN_OVER_V, 0, 7),
+ INIT_REGMAP_IRQ(AXP22X, ACIN_PLUGIN, 0, 6),
+ INIT_REGMAP_IRQ(AXP22X, ACIN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP22X, VBUS_OVER_V, 0, 4),
+ INIT_REGMAP_IRQ(AXP22X, VBUS_PLUGIN, 0, 3),
+ INIT_REGMAP_IRQ(AXP22X, VBUS_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP22X, VBUS_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP22X, BATT_PLUGIN, 1, 7),
+ INIT_REGMAP_IRQ(AXP22X, BATT_REMOVAL, 1, 6),
+ INIT_REGMAP_IRQ(AXP22X, BATT_ENT_ACT_MODE, 1, 5),
+ INIT_REGMAP_IRQ(AXP22X, BATT_EXIT_ACT_MODE, 1, 4),
+ INIT_REGMAP_IRQ(AXP22X, CHARG, 1, 3),
+ INIT_REGMAP_IRQ(AXP22X, CHARG_DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_HIGH, 1, 1),
+ INIT_REGMAP_IRQ(AXP22X, BATT_TEMP_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP22X, DIE_TEMP_HIGH, 2, 7),
+ INIT_REGMAP_IRQ(AXP22X, PEK_SHORT, 2, 1),
+ INIT_REGMAP_IRQ(AXP22X, PEK_LONG, 2, 0),
+ INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP22X, LOW_PWR_LVL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP22X, TIMER, 4, 7),
+ INIT_REGMAP_IRQ(AXP22X, PEK_RIS_EDGE, 4, 6),
+ INIT_REGMAP_IRQ(AXP22X, PEK_FAL_EDGE, 4, 5),
+ INIT_REGMAP_IRQ(AXP22X, GPIO1_INPUT, 4, 1),
+ INIT_REGMAP_IRQ(AXP22X, GPIO0_INPUT, 4, 0),
+};
+
/* some IRQs are compatible with axp20x models */
static const struct regmap_irq axp288_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2),
@@ -224,6 +295,7 @@ static const struct regmap_irq axp288_re
static const struct of_device_id axp20x_of_match[] = {
{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
+ { .compatible = "x-powers,axp221", .data = (void *) AXP221_ID },
{ },
};
MODULE_DEVICE_TABLE(of, axp20x_of_match);
@@ -258,6 +330,18 @@ static const struct regmap_irq_chip axp2
};
+static const struct regmap_irq_chip axp22x_regmap_irq_chip = {
+ .name = "axp22x_irq_chip",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
+ .mask_invert = true,
+ .init_ack_masked = true,
+ .irqs = axp22x_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp22x_regmap_irqs),
+ .num_regs = 5,
+};
+
static const struct regmap_irq_chip axp288_regmap_irq_chip = {
.name = "axp288_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
@@ -281,6 +365,14 @@ static struct mfd_cell axp20x_cells[] =
},
};
+static struct mfd_cell axp22x_cells[] = {
+ {
+ .name = "axp20x-pek",
+ .num_resources = ARRAY_SIZE(axp22x_pek_resources),
+ .resources = axp22x_pek_resources,
+ },
+};
+
static struct resource axp288_adc_resources[] = {
{
.name = "GPADC",
@@ -426,6 +518,12 @@ static int axp20x_match_device(struct ax
axp20x->regmap_cfg = &axp20x_regmap_config;
axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
break;
+ case AXP221_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp22x_cells);
+ axp20x->cells = axp22x_cells;
+ axp20x->regmap_cfg = &axp22x_regmap_config;
+ axp20x->regmap_irq_chip = &axp22x_regmap_irq_chip;
+ break;
case AXP288_ID:
axp20x->cells = axp288_cells;
axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -14,6 +14,7 @@
enum {
AXP202_ID = 0,
AXP209_ID,
+ AXP221_ID,
AXP288_ID,
NR_AXP20X_VARIANTS,
};
@@ -45,6 +46,28 @@ enum {
#define AXP20X_V_LTF_DISCHRG 0x3c
#define AXP20X_V_HTF_DISCHRG 0x3d
+#define AXP22X_PWR_OUT_CTRL1 0x10
+#define AXP22X_PWR_OUT_CTRL2 0x12
+#define AXP22X_PWR_OUT_CTRL3 0x13
+#define AXP22X_DLDO1_V_OUT 0x15
+#define AXP22X_DLDO2_V_OUT 0x16
+#define AXP22X_DLDO3_V_OUT 0x17
+#define AXP22X_DLDO4_V_OUT 0x18
+#define AXP22X_ELDO1_V_OUT 0x19
+#define AXP22X_ELDO2_V_OUT 0x1a
+#define AXP22X_ELDO3_V_OUT 0x1b
+#define AXP22X_DC5LDO_V_OUT 0x1c
+#define AXP22X_DCDC1_V_OUT 0x21
+#define AXP22X_DCDC2_V_OUT 0x22
+#define AXP22X_DCDC3_V_OUT 0x23
+#define AXP22X_DCDC4_V_OUT 0x24
+#define AXP22X_DCDC5_V_OUT 0x25
+#define AXP22X_DCDC23_V_RAMP_CTRL 0x27
+#define AXP22X_ALDO1_V_OUT 0x28
+#define AXP22X_ALDO2_V_OUT 0x29
+#define AXP22X_ALDO3_V_OUT 0x2a
+#define AXP22X_CHRG_CTRL3 0x35
+
/* Interrupt */
#define AXP20X_IRQ1_EN 0x40
#define AXP20X_IRQ2_EN 0x41
@@ -100,6 +123,9 @@ enum {
#define AXP20X_VBUS_MON 0x8b
#define AXP20X_OVER_TMP 0x8f
+#define AXP22X_PWREN_CTRL1 0x8c
+#define AXP22X_PWREN_CTRL2 0x8d
+
/* GPIO */
#define AXP20X_GPIO0_CTRL 0x90
#define AXP20X_LDO5_V_OUT 0x91
@@ -108,6 +134,11 @@ enum {
#define AXP20X_GPIO20_SS 0x94
#define AXP20X_GPIO3_CTRL 0x95
+#define AXP22X_LDO_IO0_V_OUT 0x91
+#define AXP22X_LDO_IO1_V_OUT 0x93
+#define AXP22X_GPIO_STATE 0x94
+#define AXP22X_GPIO_PULL_DOWN 0x95
+
/* Battery */
#define AXP20X_CHRG_CC_31_24 0xb0
#define AXP20X_CHRG_CC_23_16 0xb1
@@ -120,6 +151,9 @@ enum {
#define AXP20X_CC_CTRL 0xb8
#define AXP20X_FG_RES 0xb9
+/* AXP22X specific registers */
+#define AXP22X_BATLOW_THRES1 0xe6
+
/* AXP288 specific registers */
#define AXP288_PMIC_ADC_H 0x56
#define AXP288_PMIC_ADC_L 0x57
@@ -158,6 +192,30 @@ enum {
AXP20X_REG_ID_MAX,
};
+enum {
+ AXP22X_DCDC1 = 0,
+ AXP22X_DCDC2,
+ AXP22X_DCDC3,
+ AXP22X_DCDC4,
+ AXP22X_DCDC5,
+ AXP22X_DC1SW,
+ AXP22X_DC5LDO,
+ AXP22X_ALDO1,
+ AXP22X_ALDO2,
+ AXP22X_ALDO3,
+ AXP22X_ELDO1,
+ AXP22X_ELDO2,
+ AXP22X_ELDO3,
+ AXP22X_DLDO1,
+ AXP22X_DLDO2,
+ AXP22X_DLDO3,
+ AXP22X_DLDO4,
+ AXP22X_RTC_LDO,
+ AXP22X_LDO_IO0,
+ AXP22X_LDO_IO1,
+ AXP22X_REG_ID_MAX,
+};
+
/* IRQs */
enum {
AXP20X_IRQ_ACIN_OVER_V = 1,
@@ -199,6 +257,34 @@ enum {
AXP20X_IRQ_GPIO0_INPUT,
};
+enum axp22x_irqs {
+ AXP22X_IRQ_ACIN_OVER_V = 1,
+ AXP22X_IRQ_ACIN_PLUGIN,
+ AXP22X_IRQ_ACIN_REMOVAL,
+ AXP22X_IRQ_VBUS_OVER_V,
+ AXP22X_IRQ_VBUS_PLUGIN,
+ AXP22X_IRQ_VBUS_REMOVAL,
+ AXP22X_IRQ_VBUS_V_LOW,
+ AXP22X_IRQ_BATT_PLUGIN,
+ AXP22X_IRQ_BATT_REMOVAL,
+ AXP22X_IRQ_BATT_ENT_ACT_MODE,
+ AXP22X_IRQ_BATT_EXIT_ACT_MODE,
+ AXP22X_IRQ_CHARG,
+ AXP22X_IRQ_CHARG_DONE,
+ AXP22X_IRQ_BATT_TEMP_HIGH,
+ AXP22X_IRQ_BATT_TEMP_LOW,
+ AXP22X_IRQ_DIE_TEMP_HIGH,
+ AXP22X_IRQ_PEK_SHORT,
+ AXP22X_IRQ_PEK_LONG,
+ AXP22X_IRQ_LOW_PWR_LVL1,
+ AXP22X_IRQ_LOW_PWR_LVL2,
+ AXP22X_IRQ_TIMER,
+ AXP22X_IRQ_PEK_RIS_EDGE,
+ AXP22X_IRQ_PEK_FAL_EDGE,
+ AXP22X_IRQ_GPIO1_INPUT,
+ AXP22X_IRQ_GPIO0_INPUT,
+};
+
enum axp288_irqs {
AXP288_IRQ_VBUS_FALL = 2,
AXP288_IRQ_VBUS_RISE,

View file

@ -1,278 +0,0 @@
From f95b73ba272eac5495e69e12795d5ea8bc81d2cd Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Fri, 10 Apr 2015 12:09:03 +0800
Subject: [PATCH] regulator: axp20x: Prepare support for multiple AXP chip
families
Rework the AXP20X_ macros and probe function to support the several chip
families, so that each family can define it's own set of regulators.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
[wens@csie.org: Support different DC-DC work frequency ranges]
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/regulator/axp20x-regulator.c | 143 +++++++++++++++++++++++------------
1 file changed, 94 insertions(+), 49 deletions(-)
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -32,15 +32,15 @@
#define AXP20X_FREQ_DCDC_MASK 0x0f
-#define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \
- _ereg, _emask, _enable_val, _disable_val) \
- [AXP20X_##_id] = { \
+#define AXP_DESC_IO(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask, _enable_val, _disable_val) \
+ [_family##_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
- .id = AXP20X_##_id, \
+ .id = _family##_##_id, \
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
.owner = THIS_MODULE, \
.min_uV = (_min) * 1000, \
@@ -54,15 +54,15 @@
.ops = &axp20x_ops, \
}
-#define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \
- _ereg, _emask) \
- [AXP20X_##_id] = { \
+#define AXP_DESC(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask) \
+ [_family##_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
- .id = AXP20X_##_id, \
+ .id = _family##_##_id, \
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
.owner = THIS_MODULE, \
.min_uV = (_min) * 1000, \
@@ -74,29 +74,29 @@
.ops = &axp20x_ops, \
}
-#define AXP20X_DESC_FIXED(_id, _match, _supply, _volt) \
- [AXP20X_##_id] = { \
+#define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \
+ [_family##_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
- .id = AXP20X_##_id, \
+ .id = _family##_##_id, \
.n_voltages = 1, \
.owner = THIS_MODULE, \
.min_uV = (_volt) * 1000, \
.ops = &axp20x_ops_fixed \
}
-#define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg, \
- _emask) \
- [AXP20X_##_id] = { \
+#define AXP_DESC_TABLE(_family, _id, _match, _supply, _table, _vreg, _vmask, \
+ _ereg, _emask) \
+ [_family##_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
.of_match = of_match_ptr(_match), \
.regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
- .id = AXP20X_##_id, \
+ .id = _family##_##_id, \
.n_voltages = ARRAY_SIZE(_table), \
.owner = THIS_MODULE, \
.vsel_reg = (_vreg), \
@@ -136,37 +136,57 @@ static struct regulator_ops axp20x_ops =
};
static const struct regulator_desc axp20x_regulators[] = {
- AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT,
- 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
- AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT,
- 0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
- AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300),
- AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
- AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
- AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT,
- 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
- AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
- AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
- AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
- AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
- AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
+ AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
+ AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
+ AXP_DESC(AXP20X, DCDC3, "dcdc3", "vin3", 700, 3500, 25,
+ AXP20X_DCDC3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
+ AXP_DESC_FIXED(AXP20X, LDO1, "ldo1", "acin", 1300),
+ AXP_DESC(AXP20X, LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
+ AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
+ AXP_DESC(AXP20X, LDO3, "ldo3", "ldo3in", 700, 3500, 25,
+ AXP20X_LDO3_V_OUT, 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
+ AXP_DESC_TABLE(AXP20X, LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
+ AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
+ AXP_DESC_IO(AXP20X, LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
+ AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
+ AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
};
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ u32 min, max, def, step;
- if (dcdcfreq < 750) {
- dcdcfreq = 750;
- dev_warn(&pdev->dev, "DCDC frequency too low. Set to 750kHz\n");
+ switch (axp20x->variant) {
+ case AXP202_ID:
+ case AXP209_ID:
+ min = 750;
+ max = 1875;
+ def = 1500;
+ step = 75;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "Setting DCDC frequency for unsupported AXP variant\n");
+ return -EINVAL;
}
- if (dcdcfreq > 1875) {
- dcdcfreq = 1875;
- dev_warn(&pdev->dev, "DCDC frequency too high. Set to 1875kHz\n");
+ if (dcdcfreq == 0)
+ dcdcfreq = def;
+
+ if (dcdcfreq < min) {
+ dcdcfreq = min;
+ dev_warn(&pdev->dev, "DCDC frequency too low. Set to %ukHz\n",
+ min);
}
- dcdcfreq = (dcdcfreq - 750) / 75;
+ if (dcdcfreq > max) {
+ dcdcfreq = max;
+ dev_warn(&pdev->dev, "DCDC frequency too high. Set to %ukHz\n",
+ max);
+ }
+
+ dcdcfreq = (dcdcfreq - min) / step;
return regmap_update_bits(axp20x->regmap, AXP20X_DCDC_FREQ,
AXP20X_FREQ_DCDC_MASK, dcdcfreq);
@@ -176,7 +196,7 @@ static int axp20x_regulator_parse_dt(str
{
struct device_node *np, *regulators;
int ret;
- u32 dcdcfreq;
+ u32 dcdcfreq = 0;
np = of_node_get(pdev->dev.parent->of_node);
if (!np)
@@ -186,7 +206,6 @@ static int axp20x_regulator_parse_dt(str
if (!regulators) {
dev_warn(&pdev->dev, "regulators node not found\n");
} else {
- dcdcfreq = 1500;
of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
if (ret < 0) {
@@ -202,15 +221,27 @@ static int axp20x_regulator_parse_dt(str
static int axp20x_set_dcdc_workmode(struct regulator_dev *rdev, int id, u32 workmode)
{
- unsigned int mask = AXP20X_WORKMODE_DCDC2_MASK;
+ struct axp20x_dev *axp20x = rdev_get_drvdata(rdev);
+ unsigned int mask;
- if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
+ switch (axp20x->variant) {
+ case AXP202_ID:
+ case AXP209_ID:
+ if ((id != AXP20X_DCDC2) && (id != AXP20X_DCDC3))
+ return -EINVAL;
+
+ mask = AXP20X_WORKMODE_DCDC2_MASK;
+ if (id == AXP20X_DCDC3)
+ mask = AXP20X_WORKMODE_DCDC3_MASK;
+
+ workmode <<= ffs(mask) - 1;
+ break;
+
+ default:
+ /* should not happen */
+ WARN_ON(1);
return -EINVAL;
-
- if (id == AXP20X_DCDC3)
- mask = AXP20X_WORKMODE_DCDC3_MASK;
-
- workmode <<= ffs(mask) - 1;
+ }
return regmap_update_bits(rdev->regmap, AXP20X_DCDC_MODE, mask, workmode);
}
@@ -219,22 +250,36 @@ static int axp20x_regulator_probe(struct
{
struct regulator_dev *rdev;
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+ const struct regulator_desc *regulators;
struct regulator_config config = {
.dev = pdev->dev.parent,
.regmap = axp20x->regmap,
+ .driver_data = axp20x,
};
- int ret, i;
+ int ret, i, nregulators;
u32 workmode;
+ switch (axp20x->variant) {
+ case AXP202_ID:
+ case AXP209_ID:
+ regulators = axp20x_regulators;
+ nregulators = AXP20X_REG_ID_MAX;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
+ axp20x->variant);
+ return -EINVAL;
+ }
+
/* This only sets the dcdc freq. Ignore any errors */
axp20x_regulator_parse_dt(pdev);
- for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
- rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
+ for (i = 0; i < nregulators; i++) {
+ rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "Failed to register %s\n",
- axp20x_regulators[i].name);
+ regulators[i].name);
return PTR_ERR(rdev);
}
@@ -245,7 +290,7 @@ static int axp20x_regulator_probe(struct
if (!ret) {
if (axp20x_set_dcdc_workmode(rdev, i, workmode))
dev_err(&pdev->dev, "Failed to set workmode on %s\n",
- axp20x_regulators[i].name);
+ rdev->desc->name);
}
}

View file

@ -1,170 +0,0 @@
From c3f89434c9d778572cf09e8327bd047b11d48b90 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Fri, 10 Apr 2015 12:09:04 +0800
Subject: [PATCH] regulator: axp20x: Add support for AXP22X regulators
Add AXP22X regulator definitions and variant id associations.
This introduces a new "switch" type output for one of the regulators.
It is a switchable secondary output of one regulator, with the same
voltage level as the primary output.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
[wens@csie.org: Moved variant choosing to multi family support patch]
[wens@csie.org: Add dc-dc work frequency range]
[wens@csie.org: Add "switch" type output regulator DC1SW]
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/regulator/axp20x-regulator.c | 96 ++++++++++++++++++++++++++++++++++++
1 file changed, 96 insertions(+)
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -27,8 +27,12 @@
#define AXP20X_IO_ENABLED 0x03
#define AXP20X_IO_DISABLED 0x07
+#define AXP22X_IO_ENABLED 0x04
+#define AXP22X_IO_DISABLED 0x03
+
#define AXP20X_WORKMODE_DCDC2_MASK BIT(2)
#define AXP20X_WORKMODE_DCDC3_MASK BIT(1)
+#define AXP22X_WORKMODE_DCDCX_MASK(x) BIT(x)
#define AXP20X_FREQ_DCDC_MASK 0x0f
@@ -74,6 +78,26 @@
.ops = &axp20x_ops, \
}
+#define AXP_DESC_SW(_family, _id, _match, _supply, _min, _max, _step, _vreg, \
+ _vmask, _ereg, _emask) \
+ [_family##_##_id] = { \
+ .name = #_id, \
+ .supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _family##_##_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_sw, \
+ }
+
#define AXP_DESC_FIXED(_family, _id, _match, _supply, _volt) \
[_family##_##_id] = { \
.name = #_id, \
@@ -135,6 +159,14 @@ static struct regulator_ops axp20x_ops =
.is_enabled = regulator_is_enabled_regmap,
};
+static struct regulator_ops axp20x_ops_sw = {
+ .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,
+};
+
static const struct regulator_desc axp20x_regulators[] = {
AXP_DESC(AXP20X, DCDC2, "dcdc2", "vin2", 700, 2275, 25,
AXP20X_DCDC2_V_OUT, 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
@@ -152,6 +184,52 @@ static const struct regulator_desc axp20
AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
};
+static const struct regulator_desc axp22x_regulators[] = {
+ AXP_DESC(AXP22X, DCDC1, "dcdc1", "vin1", 1600, 3400, 100,
+ AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(1)),
+ AXP_DESC(AXP22X, DCDC2, "dcdc2", "vin2", 600, 1540, 20,
+ AXP22X_DCDC2_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(2)),
+ AXP_DESC(AXP22X, DCDC3, "dcdc3", "vin3", 600, 1860, 20,
+ AXP22X_DCDC3_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)),
+ AXP_DESC(AXP22X, DCDC4, "dcdc4", "vin4", 600, 1540, 20,
+ AXP22X_DCDC4_V_OUT, 0x3f, AXP22X_PWR_OUT_CTRL1, BIT(3)),
+ AXP_DESC(AXP22X, DCDC5, "dcdc5", "vin5", 1000, 2550, 50,
+ AXP22X_DCDC5_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(4)),
+ /* secondary switchable output of DCDC1 */
+ AXP_DESC_SW(AXP22X, DC1SW, "dc1sw", "dcdc1", 1600, 3400, 100,
+ AXP22X_DCDC1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(7)),
+ /* LDO regulator internally chained to DCDC5 */
+ AXP_DESC(AXP22X, DC5LDO, "dc5ldo", "dcdc5", 700, 1400, 100,
+ AXP22X_DC5LDO_V_OUT, 0x7, AXP22X_PWR_OUT_CTRL1, BIT(0)),
+ AXP_DESC(AXP22X, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
+ AXP22X_ALDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(6)),
+ AXP_DESC(AXP22X, ALDO2, "aldo2", "aldoin", 700, 3300, 100,
+ AXP22X_ALDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL1, BIT(7)),
+ AXP_DESC(AXP22X, ALDO3, "aldo3", "aldoin", 700, 3300, 100,
+ AXP22X_ALDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL3, BIT(7)),
+ AXP_DESC(AXP22X, DLDO1, "dldo1", "dldoin", 700, 3300, 100,
+ AXP22X_DLDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(3)),
+ AXP_DESC(AXP22X, DLDO2, "dldo2", "dldoin", 700, 3300, 100,
+ AXP22X_DLDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(4)),
+ AXP_DESC(AXP22X, DLDO3, "dldo3", "dldoin", 700, 3300, 100,
+ AXP22X_DLDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(5)),
+ AXP_DESC(AXP22X, DLDO4, "dldo4", "dldoin", 700, 3300, 100,
+ AXP22X_DLDO4_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(6)),
+ AXP_DESC(AXP22X, ELDO1, "eldo1", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO1_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(0)),
+ AXP_DESC(AXP22X, ELDO2, "eldo2", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO2_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(1)),
+ AXP_DESC(AXP22X, ELDO3, "eldo3", "eldoin", 700, 3300, 100,
+ AXP22X_ELDO3_V_OUT, 0x1f, AXP22X_PWR_OUT_CTRL2, BIT(2)),
+ AXP_DESC_IO(AXP22X, LDO_IO0, "ldo_io0", "ips", 1800, 3300, 100,
+ AXP22X_LDO_IO0_V_OUT, 0x1f, AXP20X_GPIO0_CTRL, 0x07,
+ AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+ AXP_DESC_IO(AXP22X, LDO_IO1, "ldo_io1", "ips", 1800, 3300, 100,
+ AXP22X_LDO_IO1_V_OUT, 0x1f, AXP20X_GPIO1_CTRL, 0x07,
+ AXP22X_IO_ENABLED, AXP22X_IO_DISABLED),
+ AXP_DESC_FIXED(AXP22X, RTC_LDO, "rtc_ldo", "ips", 3000),
+};
+
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
{
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
@@ -165,6 +243,12 @@ static int axp20x_set_dcdc_freq(struct p
def = 1500;
step = 75;
break;
+ case AXP221_ID:
+ min = 1800;
+ max = 4050;
+ def = 3000;
+ step = 150;
+ break;
default:
dev_err(&pdev->dev,
"Setting DCDC frequency for unsupported AXP variant\n");
@@ -237,6 +321,14 @@ static int axp20x_set_dcdc_workmode(stru
workmode <<= ffs(mask) - 1;
break;
+ case AXP221_ID:
+ if (id < AXP22X_DCDC1 || id > AXP22X_DCDC5)
+ return -EINVAL;
+
+ mask = AXP22X_WORKMODE_DCDCX_MASK(id - AXP22X_DCDC1);
+ workmode <<= id - AXP22X_DCDC1;
+ break;
+
default:
/* should not happen */
WARN_ON(1);
@@ -265,6 +357,10 @@ static int axp20x_regulator_probe(struct
regulators = axp20x_regulators;
nregulators = AXP20X_REG_ID_MAX;
break;
+ case AXP221_ID:
+ regulators = axp22x_regulators;
+ nregulators = AXP22X_REG_ID_MAX;
+ break;
default:
dev_err(&pdev->dev, "Unsupported AXP variant: %ld\n",
axp20x->variant);

View file

@ -1,71 +0,0 @@
From 5469e15c9a0025e8822762ab9acfc3ee50e55c2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= <bonbons@linux-vserver.org>
Date: Tue, 9 Jun 2015 08:30:48 +0200
Subject: [PATCH] mfd: axp20x: Add missing registers, and mark more registers
volatile
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add an extra set of registers which is necessary tu support the PMICs
battery charger function, and mark registers which contain status bits,
gpio status, and adc readings as volatile.
Cc: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
Changes in v2:
-Add a AXP20X_OCV_MAX define
Changes in v3:
-Add Bruno's S-o-b
---
drivers/mfd/axp20x.c | 8 +++++++-
include/linux/mfd/axp20x.h | 6 ++++++
2 files changed, 13 insertions(+), 1 deletion(-)
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -39,10 +39,16 @@ static const char * const axp20x_model_n
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),
+ regmap_reg_range(AXP20X_RDC_H, AXP20X_OCV(15)),
};
static const struct regmap_range axp20x_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_USB_OTG_STATUS),
+ regmap_reg_range(AXP20X_CHRG_CTRL1, AXP20X_CHRG_CTRL2),
regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE),
+ regmap_reg_range(AXP20X_ACIN_V_ADC_H, AXP20X_IPSOUT_V_HIGH_L),
+ regmap_reg_range(AXP20X_GPIO20_SS, AXP20X_GPIO3_CTRL),
+ regmap_reg_range(AXP20X_FG_RES, AXP20X_RDC_L),
};
static const struct regmap_access_table axp20x_writeable_table = {
@@ -159,7 +165,7 @@ static const struct regmap_config axp20x
.val_bits = 8,
.wr_table = &axp20x_writeable_table,
.volatile_table = &axp20x_volatile_table,
- .max_register = AXP20X_FG_RES,
+ .max_register = AXP20X_OCV(AXP20X_OCV_MAX),
.cache_type = REGCACHE_RBTREE,
};
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -151,6 +151,12 @@ enum {
#define AXP20X_CC_CTRL 0xb8
#define AXP20X_FG_RES 0xb9
+/* OCV */
+#define AXP20X_RDC_H 0xba
+#define AXP20X_RDC_L 0xbb
+#define AXP20X_OCV(m) (0xc0 + (m))
+#define AXP20X_OCV_MAX 0xf
+
/* AXP22X specific registers */
#define AXP22X_BATLOW_THRES1 0xe6

View file

@ -1,26 +0,0 @@
From 6d4fa89dcd85e2427da83319ce75e5df5febcc96 Mon Sep 17 00:00:00 2001
From: Chen-Yu Tsai <wens@csie.org>
Date: Fri, 10 Apr 2015 12:09:06 +0800
Subject: [PATCH] mfd: axp20x: Enable AXP22X regulators
Now that the axp20x-regulators driver supports different variants of the
AXP family, we can enable regulator support for AXP22X without the risk
of incorrectly configuring regulators.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/axp20x.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -376,6 +376,8 @@ static struct mfd_cell axp22x_cells[] =
.name = "axp20x-pek",
.num_resources = ARRAY_SIZE(axp22x_pek_resources),
.resources = axp22x_pek_resources,
+ }, {
+ .name = "axp20x-regulator",
},
};

View file

@ -1,261 +0,0 @@
From a50e5abe10c95108ece5d3a91027570e66b5f238 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <hramrach@gmail.com>
Date: Sat, 11 Jul 2015 14:59:56 +0200
Subject: [PATCH] mfd: axp20x: Add axp152 support
The axp152 is a stripped down version of the axp202 pmic with the battery
charging function removed as it is intended for top-set boxes.
Signed-off-by: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
---
drivers/mfd/axp20x.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/axp20x.h | 61 +++++++++++++++++++++++++++++++++-
2 files changed, 143 insertions(+), 1 deletion(-)
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -30,12 +30,34 @@
#define AXP20X_OFF 0x80
static const char * const axp20x_model_names[] = {
+ "AXP152",
"AXP202",
"AXP209",
"AXP221",
"AXP288",
};
+static const struct regmap_range axp152_writeable_ranges[] = {
+ regmap_reg_range(AXP152_LDO3456_DC1234_CTRL, AXP152_IRQ3_STATE),
+ regmap_reg_range(AXP152_DCDC_MODE, AXP152_PWM1_DUTY_CYCLE),
+};
+
+static const struct regmap_range axp152_volatile_ranges[] = {
+ regmap_reg_range(AXP152_PWR_OP_MODE, AXP152_PWR_OP_MODE),
+ regmap_reg_range(AXP152_IRQ1_EN, AXP152_IRQ3_STATE),
+ regmap_reg_range(AXP152_GPIO_INPUT, AXP152_GPIO_INPUT),
+};
+
+static const struct regmap_access_table axp152_writeable_table = {
+ .yes_ranges = axp152_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp152_writeable_ranges),
+};
+
+static const struct regmap_access_table axp152_volatile_table = {
+ .yes_ranges = axp152_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp152_volatile_ranges),
+};
+
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),
@@ -99,6 +121,11 @@ static const struct regmap_access_table
.n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
};
+static struct resource axp152_pek_resources[] = {
+ DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_RIS_EDGE, "PEK_DBR"),
+ DEFINE_RES_IRQ_NAMED(AXP152_IRQ_PEK_FAL_EDGE, "PEK_DBF"),
+};
+
static struct resource axp20x_pek_resources[] = {
{
.name = "PEK_DBR",
@@ -160,6 +187,15 @@ static struct resource axp288_fuel_gauge
},
};
+static const struct regmap_config axp152_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp152_writeable_table,
+ .volatile_table = &axp152_volatile_table,
+ .max_register = AXP152_PWM1_DUTY_CYCLE,
+ .cache_type = REGCACHE_RBTREE,
+};
+
static const struct regmap_config axp20x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -190,6 +226,26 @@ static const struct regmap_config axp288
#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
[_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+static const struct regmap_irq axp152_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP152, LDO0IN_CONNECT, 0, 6),
+ INIT_REGMAP_IRQ(AXP152, LDO0IN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP152, ALDO0IN_CONNECT, 0, 3),
+ INIT_REGMAP_IRQ(AXP152, ALDO0IN_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP152, DCDC1_V_LOW, 1, 5),
+ INIT_REGMAP_IRQ(AXP152, DCDC2_V_LOW, 1, 4),
+ INIT_REGMAP_IRQ(AXP152, DCDC3_V_LOW, 1, 3),
+ INIT_REGMAP_IRQ(AXP152, DCDC4_V_LOW, 1, 2),
+ INIT_REGMAP_IRQ(AXP152, PEK_SHORT, 1, 1),
+ INIT_REGMAP_IRQ(AXP152, PEK_LONG, 1, 0),
+ INIT_REGMAP_IRQ(AXP152, TIMER, 2, 7),
+ INIT_REGMAP_IRQ(AXP152, PEK_RIS_EDGE, 2, 6),
+ INIT_REGMAP_IRQ(AXP152, PEK_FAL_EDGE, 2, 5),
+ INIT_REGMAP_IRQ(AXP152, GPIO3_INPUT, 2, 3),
+ INIT_REGMAP_IRQ(AXP152, GPIO2_INPUT, 2, 2),
+ INIT_REGMAP_IRQ(AXP152, GPIO1_INPUT, 2, 1),
+ INIT_REGMAP_IRQ(AXP152, GPIO0_INPUT, 2, 0),
+};
+
static const struct regmap_irq axp20x_regmap_irqs[] = {
INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
@@ -299,6 +355,7 @@ static const struct regmap_irq axp288_re
};
static const struct of_device_id axp20x_of_match[] = {
+ { .compatible = "x-powers,axp152", .data = (void *) AXP152_ID },
{ .compatible = "x-powers,axp202", .data = (void *) AXP202_ID },
{ .compatible = "x-powers,axp209", .data = (void *) AXP209_ID },
{ .compatible = "x-powers,axp221", .data = (void *) AXP221_ID },
@@ -323,6 +380,18 @@ static const struct acpi_device_id axp20
};
MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
+static const struct regmap_irq_chip axp152_regmap_irq_chip = {
+ .name = "axp152_irq_chip",
+ .status_base = AXP152_IRQ1_STATE,
+ .ack_base = AXP152_IRQ1_STATE,
+ .mask_base = AXP152_IRQ1_EN,
+ .mask_invert = true,
+ .init_ack_masked = true,
+ .irqs = axp152_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp152_regmap_irqs),
+ .num_regs = 3,
+};
+
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
.name = "axp20x_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
@@ -381,6 +450,14 @@ static struct mfd_cell axp22x_cells[] =
},
};
+static struct mfd_cell axp152_cells[] = {
+ {
+ .name = "axp20x-pek",
+ .num_resources = ARRAY_SIZE(axp152_pek_resources),
+ .resources = axp152_pek_resources,
+ },
+};
+
static struct resource axp288_adc_resources[] = {
{
.name = "GPADC",
@@ -519,6 +596,12 @@ static int axp20x_match_device(struct ax
}
switch (axp20x->variant) {
+ case AXP152_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp152_cells);
+ axp20x->cells = axp152_cells;
+ axp20x->regmap_cfg = &axp152_regmap_config;
+ axp20x->regmap_irq_chip = &axp152_regmap_irq_chip;
+ break;
case AXP202_ID:
case AXP209_ID:
axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -12,7 +12,8 @@
#define __LINUX_MFD_AXP20X_H
enum {
- AXP202_ID = 0,
+ AXP152_ID = 0,
+ AXP202_ID,
AXP209_ID,
AXP221_ID,
AXP288_ID,
@@ -22,6 +23,24 @@ enum {
#define AXP20X_DATACACHE(m) (0x04 + (m))
/* Power supply */
+#define AXP152_PWR_OP_MODE 0x01
+#define AXP152_LDO3456_DC1234_CTRL 0x12
+#define AXP152_ALDO_OP_MODE 0x13
+#define AXP152_LDO0_CTRL 0x15
+#define AXP152_DCDC2_V_OUT 0x23
+#define AXP152_DCDC2_V_SCAL 0x25
+#define AXP152_DCDC1_V_OUT 0x26
+#define AXP152_DCDC3_V_OUT 0x27
+#define AXP152_ALDO12_V_OUT 0x28
+#define AXP152_DLDO1_V_OUT 0x29
+#define AXP152_DLDO2_V_OUT 0x2a
+#define AXP152_DCDC4_V_OUT 0x2b
+#define AXP152_V_OFF 0x31
+#define AXP152_OFF_CTRL 0x32
+#define AXP152_PEK_KEY 0x36
+#define AXP152_DCDC_FREQ 0x37
+#define AXP152_DCDC_MODE 0x80
+
#define AXP20X_PWR_INPUT_STATUS 0x00
#define AXP20X_PWR_OP_MODE 0x01
#define AXP20X_USB_OTG_STATUS 0x02
@@ -69,6 +88,13 @@ enum {
#define AXP22X_CHRG_CTRL3 0x35
/* Interrupt */
+#define AXP152_IRQ1_EN 0x40
+#define AXP152_IRQ2_EN 0x41
+#define AXP152_IRQ3_EN 0x42
+#define AXP152_IRQ1_STATE 0x48
+#define AXP152_IRQ2_STATE 0x49
+#define AXP152_IRQ3_STATE 0x4a
+
#define AXP20X_IRQ1_EN 0x40
#define AXP20X_IRQ2_EN 0x41
#define AXP20X_IRQ3_EN 0x42
@@ -127,6 +153,19 @@ enum {
#define AXP22X_PWREN_CTRL2 0x8d
/* GPIO */
+#define AXP152_GPIO0_CTRL 0x90
+#define AXP152_GPIO1_CTRL 0x91
+#define AXP152_GPIO2_CTRL 0x92
+#define AXP152_GPIO3_CTRL 0x93
+#define AXP152_LDOGPIO2_V_OUT 0x96
+#define AXP152_GPIO_INPUT 0x97
+#define AXP152_PWM0_FREQ_X 0x98
+#define AXP152_PWM0_FREQ_Y 0x99
+#define AXP152_PWM0_DUTY_CYCLE 0x9a
+#define AXP152_PWM1_FREQ_X 0x9b
+#define AXP152_PWM1_FREQ_Y 0x9c
+#define AXP152_PWM1_DUTY_CYCLE 0x9d
+
#define AXP20X_GPIO0_CTRL 0x90
#define AXP20X_LDO5_V_OUT 0x91
#define AXP20X_GPIO1_CTRL 0x92
@@ -224,6 +263,26 @@ enum {
/* IRQs */
enum {
+ AXP152_IRQ_LDO0IN_CONNECT = 1,
+ AXP152_IRQ_LDO0IN_REMOVAL,
+ AXP152_IRQ_ALDO0IN_CONNECT,
+ AXP152_IRQ_ALDO0IN_REMOVAL,
+ AXP152_IRQ_DCDC1_V_LOW,
+ AXP152_IRQ_DCDC2_V_LOW,
+ AXP152_IRQ_DCDC3_V_LOW,
+ AXP152_IRQ_DCDC4_V_LOW,
+ AXP152_IRQ_PEK_SHORT,
+ AXP152_IRQ_PEK_LONG,
+ AXP152_IRQ_TIMER,
+ AXP152_IRQ_PEK_RIS_EDGE,
+ AXP152_IRQ_PEK_FAL_EDGE,
+ AXP152_IRQ_GPIO3_INPUT,
+ AXP152_IRQ_GPIO2_INPUT,
+ AXP152_IRQ_GPIO1_INPUT,
+ AXP152_IRQ_GPIO0_INPUT,
+};
+
+enum {
AXP20X_IRQ_ACIN_OVER_V = 1,
AXP20X_IRQ_ACIN_PLUGIN,
AXP20X_IRQ_ACIN_REMOVAL,

View file

@ -1,135 +0,0 @@
From 3282055a7d0a304d541dbdbe2e32167e1a2f117c Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:20:54 +0200
Subject: [PATCH] mtd: nand: Take nand_ecc_ctrl initialization out of
nand_scan_tail
Take ECC initialization code portion out of nand_scan_tail so that we can
re-use this implementation.
This commit only moves some code around and makes no functional changes.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 91 +++++++++++++++++++++++++++-----------------
1 file changed, 56 insertions(+), 35 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3892,42 +3892,15 @@ static bool nand_ecc_strength_good(struc
return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds;
}
-/**
- * nand_scan_tail - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- *
- * This is the second phase of the normal nand_scan() function. It fills out
- * all the uninitialized function pointers with the defaults and scans for a
- * bad block table if appropriate.
+/*
+ * Initialize ECC struct:
+ * - fill ECC struct with default function/values when these ones are undefined
+ * - fill ECC infos based on MTD device
*/
-int nand_scan_tail(struct mtd_info *mtd)
+static int nand_ecc_ctrl_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc)
{
int i;
- struct nand_chip *chip = mtd->priv;
- struct nand_ecc_ctrl *ecc = &chip->ecc;
- struct nand_buffers *nbuf;
- /* New bad blocks should be marked in OOB, flash-based BBT, or both */
- BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
- !(chip->bbt_options & NAND_BBT_USE_FLASH));
-
- if (!(chip->options & NAND_OWN_BUFFERS)) {
- nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
- + mtd->oobsize * 3, GFP_KERNEL);
- if (!nbuf)
- return -ENOMEM;
- nbuf->ecccalc = (uint8_t *)(nbuf + 1);
- nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
- nbuf->databuf = nbuf->ecccode + mtd->oobsize;
-
- chip->buffers = nbuf;
- } else {
- if (!chip->buffers)
- return -ENOMEM;
- }
-
- /* Set the internal oob buffer location, just after the page data */
- chip->oob_poi = chip->buffers->databuf + mtd->writesize;
/*
* If no default placement scheme is given, select an appropriate one.
@@ -3953,9 +3926,6 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
- if (!chip->write_page)
- chip->write_page = nand_write_page;
-
/*
* Check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
@@ -4125,6 +4095,57 @@ int nand_scan_tail(struct mtd_info *mtd)
}
ecc->total = ecc->steps * ecc->bytes;
+ return 0;
+}
+
+/**
+ * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ *
+ * This is the second phase of the normal nand_scan() function. It fills out
+ * all the uninitialized function pointers with the defaults and scans for a
+ * bad block table if appropriate.
+ */
+int nand_scan_tail(struct mtd_info *mtd)
+{
+ int ret;
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_buffers *nbuf;
+
+ /* New bad blocks should be marked in OOB, flash-based BBT, or both */
+ BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
+ !(chip->bbt_options & NAND_BBT_USE_FLASH));
+
+ if (!(chip->options & NAND_OWN_BUFFERS)) {
+ nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+ + mtd->oobsize * 3, GFP_KERNEL);
+ if (!nbuf)
+ return -ENOMEM;
+ nbuf->ecccalc = (uint8_t *)(nbuf + 1);
+ nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
+ nbuf->databuf = nbuf->ecccode + mtd->oobsize;
+ chip->buffers = nbuf;
+ } else {
+ if (!chip->buffers)
+ return -ENOMEM;
+ }
+
+ /* Set the internal oob buffer location, just after the page data */
+ chip->oob_poi = chip->buffers->databuf + mtd->writesize;
+
+ if (!chip->write_page)
+ chip->write_page = nand_write_page;
+
+ /* Initialize ECC struct */
+ ret = nand_ecc_ctrl_init(mtd, ecc);
+ if (ret) {
+ if (!(chip->options & NAND_OWN_BUFFERS))
+ kfree(chip->buffers);
+
+ return ret;
+ }
+
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
switch (ecc->steps) {

View file

@ -1,152 +0,0 @@
From 0460e9868fd82a3675db02f6ceb6edfd8501c194 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:31:42 +0200
Subject: [PATCH] mtd: nand: Add DT NAND partition parser
Add a of_nandpart_parse function to help parsing NAND partitions from DT.
This function should be called from NAND controller drivers just after the
nand_scan_tail in place of mtd_device_parse_register.
The caller can specify a parser function to retrieve HW specific
informations from the DT.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/ofnandpart.c | 104 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 17 +++++++
2 files changed, 121 insertions(+)
create mode 100644 drivers/mtd/nand/ofnandpart.c
--- /dev/null
+++ b/drivers/mtd/nand/ofnandpart.c
@@ -0,0 +1,104 @@
+/*
+ * NAND Flash partitions described by the OF (or flattened) device tree
+ *
+ * Copyright © 2014 Boris BREZILLON <b.brezillon.dev@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 (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/mtd/nand.h>
+
+static inline bool node_has_compatible(struct device_node *pp)
+{
+ return of_get_property(pp, "compatible", NULL);
+}
+
+int ofnandpart_parse(struct mtd_info *master,
+ const struct ofnandpart_data *data)
+{
+ struct device_node *node;
+ const char *partname;
+ struct device_node *pp;
+ int i;
+
+ if (!data)
+ return 0;
+
+ node = data->node;
+ if (!node)
+ return 0;
+
+ i = 0;
+ for_each_child_of_node(node, pp) {
+ const __be32 *reg;
+ int len;
+ int a_cells, s_cells;
+ uint64_t offset, size;
+ uint32_t mask_flags = 0;
+ struct nand_part *part;
+
+ if (node_has_compatible(pp))
+ continue;
+
+ reg = of_get_property(pp, "reg", &len);
+ if (!reg)
+ continue;
+
+ a_cells = of_n_addr_cells(pp);
+ s_cells = of_n_size_cells(pp);
+ offset = of_read_number(reg, a_cells);
+ size = of_read_number(reg + a_cells, s_cells);
+
+ partname = of_get_property(pp, "label", &len);
+ if (!partname)
+ partname = of_get_property(pp, "name", &len);
+
+ if (of_get_property(pp, "read-only", &len))
+ mask_flags |= MTD_WRITEABLE;
+
+ if (of_get_property(pp, "lock", &len))
+ mask_flags |= MTD_POWERUP_LOCK;
+
+ if (data->parse)
+ part = data->parse(data->priv, master, pp);
+ else
+ part = nandpart_alloc();
+
+ if (IS_ERR(part))
+ continue;
+
+ part->offset = offset;
+ part->master = master;
+ part->mtd.name = partname;
+ part->mtd.size = size;
+ part->mtd.flags = mask_flags;
+
+ if (nand_add_partition(master, part)) {
+ if (part->release)
+ part->release(part);
+ continue;
+ }
+
+ i++;
+ }
+
+ if (!i) {
+ of_node_put(pp);
+ pr_err("No valid partition found on %s\n", node->full_name);
+ }
+
+ return i;
+}
+EXPORT_SYMBOL(ofnandpart_parse);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Parser for NAND flash partitioning information in device tree");
+MODULE_AUTHOR("Boris BREZILLON");
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -1014,6 +1014,23 @@ static inline int jedec_feature(struct n
: 0;
}
+/**
+ * struct ofnandpart_data - struct used to retrieve NAND partitions from a DT
+ * node
+ * @parse: driver specific parser function
+ * @priv: driver private data
+ * @node: OF node containing NAND partitions
+ */
+struct ofnandpart_data {
+ struct nand_part *(*parse)(void *priv, struct mtd_info *master,
+ struct device_node *pp);
+ void *priv;
+ struct device_node *node;
+};
+
+int ofnandpart_parse(struct mtd_info *master,
+ const struct ofnandpart_data *data);
+
/*
* struct nand_sdr_timings - SDR NAND chip timings
*

View file

@ -1,261 +0,0 @@
From bec69bb8e85151729014d859106dcc3fe652b1d4 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:45:40 +0200
Subject: [PATCH] mtd: nand: Add page status table (pst)
Page status table is an byte array storing pages status.
It defines 3 status:
- unknown: the page has not been read yet and we do not know its current
state
- empty: the page contains only FFs
- filled: the page has been filled with data
Care must be taken: an empty page does not mean it can be written, because
it might have already been written with only FFs.
These page status are useful to check wether the controller should try to
correct errors (using ECC) or a derandomize data (using a randomizer
block).
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 154 +++++++++++++++++++++++++++++++++++++++++++
include/linux/mtd/nand.h | 21 ++++++
2 files changed, 175 insertions(+)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1102,6 +1102,138 @@ out:
EXPORT_SYMBOL(nand_lock);
/**
+ * nand_page_is_empty - check wether a NAND page contains only FFs
+ * @mtd: mtd info
+ * @data: data buffer
+ * @oob: oob buffer
+ *
+ * Reads the data stored in the databuf buffer and check if it contains only
+ * FFs.
+ *
+ * Return true if it does else return false.
+ */
+bool nand_page_is_empty(struct mtd_info *mtd, void *data, void *oob)
+{
+ u8 *buf;
+ int length;
+ u32 pattern = 0xffffffff;
+ int bitflips = 0;
+ int cnt;
+
+ buf = data;
+ length = mtd->writesize;
+ while (length) {
+ cnt = length < sizeof(pattern) ? length : sizeof(pattern);
+ if (memcmp(&pattern, buf, cnt)) {
+ int i;
+ for (i = 0; i < cnt * BITS_PER_BYTE; i++) {
+ if (!(buf[i / BITS_PER_BYTE] &
+ (1 << (i % BITS_PER_BYTE)))) {
+ bitflips++;
+ if (bitflips > mtd->ecc_strength)
+ return false;
+ }
+ }
+ }
+
+ buf += sizeof(pattern);
+ length -= sizeof(pattern);
+ }
+
+ buf = oob;
+ length = mtd->oobsize;
+ while (length) {
+ cnt = length < sizeof(pattern) ? length : sizeof(pattern);
+ if (memcmp(&pattern, buf, cnt)) {
+ int i;
+ for (i = 0; i < cnt * BITS_PER_BYTE; i++) {
+ if (!(buf[i / BITS_PER_BYTE] &
+ (1 << (i % BITS_PER_BYTE)))) {
+ bitflips++;
+ if (bitflips > mtd->ecc_strength)
+ return false;
+ }
+ }
+ }
+
+ buf += sizeof(pattern);
+ length -= sizeof(pattern);
+ }
+
+ return true;
+}
+EXPORT_SYMBOL(nand_page_is_empty);
+
+/**
+ * nand_page_get_status - retrieve page status from the page status table (pst)
+ * @mtd: mtd info
+ * @page: page you want to get status on
+ *
+ * Return the page status.
+ */
+int nand_page_get_status(struct mtd_info *mtd, int page)
+{
+ struct nand_chip *chip = mtd->priv;
+ u8 shift = (page % 4) * 2;
+ uint64_t offset = page / 4;
+ int ret = NAND_PAGE_STATUS_UNKNOWN;
+
+ if (chip->pst)
+ ret = (chip->pst[offset] >> shift) & 0x3;
+
+ return ret;
+}
+EXPORT_SYMBOL(nand_page_get_status);
+
+/**
+ * nand_page_set_status - assign page status from in the page status table
+ * @mtd: mtd info
+ * @page: page you want to get status on
+ * @status: new status to assign
+ */
+void nand_page_set_status(struct mtd_info *mtd, int page,
+ enum nand_page_status status)
+{
+ struct nand_chip *chip = mtd->priv;
+ u8 shift;
+ uint64_t offset;
+
+ if (!chip->pst)
+ return;
+
+ shift = (page % 4) * 2;
+ offset = page / 4;
+ chip->pst[offset] &= ~(0x3 << shift);
+ chip->pst[offset] |= (status & 0x3) << shift;
+}
+EXPORT_SYMBOL(nand_page_set_status);
+
+/**
+ * nand_pst_create - create a page status table
+ * @mtd: mtd info
+ *
+ * Allocate a page status table and assign it to the mtd device.
+ *
+ * Returns 0 in case of success or -ERRNO in case of error.
+ */
+int nand_pst_create(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (chip->pst)
+ return 0;
+
+ chip->pst = kzalloc(mtd->size >>
+ (chip->page_shift + mtd->subpage_sft + 2),
+ GFP_KERNEL);
+ if (!chip->pst)
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL(nand_pst_create);
+
+/**
* nand_read_page_raw - [INTERN] read raw page data without ecc
* @mtd: mtd info structure
* @chip: nand chip info structure
@@ -2539,6 +2671,7 @@ static int nand_do_write_ops(struct mtd_
uint8_t *wbuf = buf;
int use_bufpoi;
int part_pagewr = (column || writelen < (mtd->writesize - 1));
+ int subpage;
if (part_pagewr)
use_bufpoi = 1;
@@ -2574,6 +2707,14 @@ static int nand_do_write_ops(struct mtd_
if (ret)
break;
+ for (subpage = column / chip->subpagesize;
+ subpage < (column + writelen) / chip->subpagesize;
+ subpage++)
+ nand_page_set_status(mtd,
+ (page << mtd->subpage_sft) +
+ subpage,
+ NAND_PAGE_FILLED);
+
writelen -= bytes;
if (!writelen)
break;
@@ -2979,6 +3120,7 @@ int nand_erase_nand(struct mtd_info *mtd
int page, status, pages_per_block, ret, chipnr;
struct nand_chip *chip = mtd->priv;
loff_t len;
+ int i;
pr_debug("%s: start = 0x%012llx, len = %llu\n",
__func__, (unsigned long long)instr->addr,
@@ -3051,6 +3193,18 @@ int nand_erase_nand(struct mtd_info *mtd
goto erase_exit;
}
+ for (i = 0; i < pages_per_block; i++) {
+ int subpage;
+ for (subpage = 0;
+ subpage < 1 << mtd->subpage_sft;
+ subpage++) {
+ nand_page_set_status(mtd,
+ ((page + i) << mtd->subpage_sft) +
+ subpage,
+ NAND_PAGE_EMPTY);
+ }
+ }
+
/* Increment page address and decrement length */
len -= (1ULL << chip->phys_erase_shift);
page += pages_per_block;
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -521,6 +521,24 @@ struct nand_ecc_ctrl {
int page);
};
+/*
+ * Constants for page status
+ */
+enum nand_page_status {
+ NAND_PAGE_STATUS_UNKNOWN,
+ NAND_PAGE_EMPTY,
+ NAND_PAGE_FILLED,
+};
+
+bool nand_page_is_empty(struct mtd_info *mtd, void *data, void *oob);
+
+int nand_page_get_status(struct mtd_info *mtd, int page);
+
+void nand_page_set_status(struct mtd_info *mtd, int page,
+ enum nand_page_status status);
+
+int nand_pst_create(struct mtd_info *mtd);
+
/**
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer pointer for calculated ECC, size is oobsize.
@@ -630,6 +648,7 @@ struct nand_buffers {
* @bbt_md: [REPLACEABLE] bad block table mirror descriptor
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
* bad block scan.
+ * @pst: [INTERN] page status table
* @controller: [REPLACEABLE] a pointer to a hardware controller
* structure which is shared among multiple independent
* devices.
@@ -718,6 +737,8 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern;
+ uint8_t *pst;
+
struct list_head partitions;
struct mutex part_lock;

View file

@ -1,847 +0,0 @@
From 293984c7f167a08285596ef2166d8ab9cb571778 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:46:26 +0200
Subject: [PATCH] mtd: nand: Introduce a randomizer layer in the NAND framework
This patch introduce a new layer in the NAND framework to support both HW
and SW randomizers.
This randomization is required on some MLC/TLC NAND chips which do not
support large islands of same patterns.
The randomizer layer defines a nand_rnd_ctrl struct which is intended to
be used by NAND core functions or NAND drivers to randomize/derandomize
data stored on NAND chips.
The implementation can implement any of these functions:
- config: prepare a random transfer to/from the NAND chip
- write_buf: randomize and write data to the NAND chip
- read_buf: read and derandomize data from the NAND chip
read/write_buf functions are always called after a config call.
The config call specify the page, the column within the page and the action
that will take place after the config (either read or write).
If column is set to -1, the randomizer is disabled.
If page is set to -1, we keep working on the same page.
The randomizer layer provides helper functions that choose wether the
randomizer or the chip read/write_buf should be used.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 278 ++++++++++++++++++++++++++++++++++---------
include/linux/mtd/nand.h | 98 +++++++++++++++
2 files changed, 321 insertions(+), 55 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1102,6 +1102,62 @@ out:
EXPORT_SYMBOL(nand_lock);
/**
+ * nand_rnd_is_activ - check wether a region of a NAND page requires NAND
+ * randomizer to be disabled
+ * @mtd: mtd info
+ * @page: NAND page
+ * @column: offset within the page
+ * @len: len of the region
+ *
+ * Returns 1 if the randomizer should be enabled, 0 if not, or -ERR in case of
+ * error.
+ *
+ * In case of success len will contain the size of the region:
+ * - if the requested region fits in a NAND random region len will not change
+ * - else len will be replaced by the available length within the NAND random
+ * region
+ */
+int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_rnd_layout *layout = chip->cur_rnd->layout;
+ struct nand_rndfree *range;
+ int ret = 1;
+ int tmp;
+ int i;
+
+ if (!len || *len < 0 || column < 0 ||
+ column + *len > mtd->writesize + mtd->oobsize)
+ return -EINVAL;
+
+ if (layout) {
+ for (i = 0; i < layout->nranges; i++) {
+ range = &layout->ranges[i];
+ if (column + *len <= range->offset) {
+ break;
+ } else if (column >= range->offset + range->length) {
+ continue;
+ } else if (column < range->offset) {
+ tmp = range->offset - column;
+ if (*len > tmp)
+ *len = tmp;
+ break;
+ } else {
+ tmp = range->offset + range->length - column;
+ if (*len > tmp)
+ *len = tmp;
+ ret = 0;
+ break;
+ }
+
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(nand_rnd_is_activ);
+
+/**
* nand_page_is_empty - check wether a NAND page contains only FFs
* @mtd: mtd info
* @data: data buffer
@@ -1246,9 +1302,14 @@ EXPORT_SYMBOL(nand_pst_create);
static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- chip->read_buf(mtd, buf, mtd->writesize);
- if (oob_required)
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, page, 0, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, buf, mtd->writesize);
+ if (oob_required) {
+ nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ }
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
return 0;
}
@@ -1270,28 +1331,40 @@ static int nand_read_page_raw_syndrome(s
int eccbytes = chip->cur_ecc->bytes;
uint8_t *oob = chip->oob_poi;
int steps, size;
+ int column = 0;
for (steps = chip->cur_ecc->steps; steps > 0; steps--) {
- chip->read_buf(mtd, buf, eccsize);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, buf, eccsize);
buf += eccsize;
+ column += eccsize;
if (chip->cur_ecc->prepad) {
- chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->prepad);
oob += chip->cur_ecc->prepad;
+ column += chip->cur_ecc->prepad;
}
- chip->read_buf(mtd, oob, eccbytes);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, eccbytes);
oob += eccbytes;
+ column += eccbytes;
if (chip->cur_ecc->postpad) {
- chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->postpad);
oob += chip->cur_ecc->postpad;
+ column += chip->cur_ecc->postpad;
}
}
size = mtd->oobsize - (oob - chip->oob_poi);
- if (size)
- chip->read_buf(mtd, oob, size);
+ if (size) {
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, size);
+ }
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return 0;
}
@@ -1380,7 +1453,8 @@ static int nand_read_subpage(struct mtd_
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_col_addr, -1);
p = bufpoi + data_col_addr;
- chip->read_buf(mtd, p, datafrag_len);
+ nand_rnd_config(mtd, -1, data_col_addr, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, p, datafrag_len);
/* Calculate ECC */
for (i = 0; i < eccfrag_len;
@@ -1399,7 +1473,8 @@ static int nand_read_subpage(struct mtd_
}
if (gaps) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, -1, mtd->writesize, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
} else {
/*
* Send the command to read the particular ECC bytes take care
@@ -1415,7 +1490,8 @@ static int nand_read_subpage(struct mtd_
chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
mtd->writesize + aligned_pos, -1);
- chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
+ nand_rnd_config(mtd, -1, mtd->writesize + aligned_pos, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len);
}
for (i = 0; i < eccfrag_len; i++)
@@ -1436,6 +1512,7 @@ static int nand_read_subpage(struct mtd_
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return max_bitflips;
}
@@ -1460,13 +1537,17 @@ static int nand_read_page_hwecc(struct m
uint8_t *ecc_code = chip->buffers->ecccode;
uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
unsigned int max_bitflips = 0;
+ int column = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, p, eccsize);
chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
+ column += eccsize;
}
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
for (i = 0; i < chip->cur_ecc->total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1486,6 +1567,7 @@ static int nand_read_page_hwecc(struct m
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return max_bitflips;
}
@@ -1514,11 +1596,14 @@ static int nand_read_page_hwecc_oob_firs
uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
uint8_t *ecc_calc = chip->buffers->ecccalc;
unsigned int max_bitflips = 0;
+ int column = 0;
/* Read the OOB area first */
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+ column = 0;
for (i = 0; i < chip->cur_ecc->total; i++)
ecc_code[i] = chip->oob_poi[eccpos[i]];
@@ -1527,7 +1612,8 @@ static int nand_read_page_hwecc_oob_firs
int stat;
chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, p, eccsize);
chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
stat = chip->cur_ecc->correct(mtd, p, &ecc_code[i], NULL);
@@ -1538,6 +1624,7 @@ static int nand_read_page_hwecc_oob_firs
max_bitflips = max_t(unsigned int, max_bitflips, stat);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return max_bitflips;
}
@@ -1561,20 +1648,27 @@ static int nand_read_page_syndrome(struc
uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
unsigned int max_bitflips = 0;
+ int column = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
int stat;
chip->cur_ecc->hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, p, eccsize);
+ column += eccsize;
if (chip->cur_ecc->prepad) {
- chip->read_buf(mtd, oob, chip->cur_ecc->prepad);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->prepad);
oob += chip->cur_ecc->prepad;
}
chip->cur_ecc->hwctl(mtd, NAND_ECC_READSYN);
- chip->read_buf(mtd, oob, eccbytes);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, eccbytes);
+ column += eccbytes;
+
stat = chip->cur_ecc->correct(mtd, p, oob, NULL);
if (stat < 0) {
@@ -1587,29 +1681,36 @@ static int nand_read_page_syndrome(struc
oob += eccbytes;
if (chip->cur_ecc->postpad) {
- chip->read_buf(mtd, oob, chip->cur_ecc->postpad);
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, chip->cur_ecc->postpad);
+ column += chip->cur_ecc->postpad;
oob += chip->cur_ecc->postpad;
}
}
/* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi);
- if (i)
- chip->read_buf(mtd, oob, i);
+ if (i) {
+ nand_rnd_config(mtd, page, column, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, i);
+ }
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return max_bitflips;
}
/**
* nand_transfer_oob - [INTERN] Transfer oob to client buffer
- * @chip: nand chip structure
+ * @mtd: mtd structure
* @oob: oob destination address
* @ops: oob ops structure
* @len: size of oob to transfer
*/
-static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
+static uint8_t *nand_transfer_oob(struct mtd_info *mtd, uint8_t *oob,
struct mtd_oob_ops *ops, size_t len)
{
+ struct nand_chip *chip = mtd->priv;
+
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@@ -1737,6 +1838,7 @@ read_retry:
* Now read the page into the buffer. Absent an error,
* the read methods return max bitflips per ecc step.
*/
+ nand_rnd_config(mtd, page, -1, NAND_RND_READ);
if (unlikely(ops->mode == MTD_OPS_RAW))
ret = chip->cur_ecc->read_page_raw(mtd, chip,
bufpoi,
@@ -1753,6 +1855,8 @@ read_retry:
bufpoi,
oob_required,
page);
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
if (ret < 0) {
if (use_bufpoi)
/* Invalidate page cache */
@@ -1780,8 +1884,8 @@ read_retry:
int toread = min(oobreadlen, max_oobsize);
if (toread) {
- oob = nand_transfer_oob(chip,
- oob, ops, toread);
+ oob = nand_transfer_oob(mtd, oob, ops,
+ toread);
oobreadlen -= toread;
}
}
@@ -1909,12 +2013,15 @@ static int nand_part_read(struct mtd_inf
nand_get_device(part->master, FL_READING);
if (part->ecc)
chip->cur_ecc = part->ecc;
+ if (part->rnd)
+ chip->cur_rnd = part->rnd;
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_read_ops(part->master, from, &ops);
*retlen = ops.retlen;
+ chip->cur_rnd = &chip->rnd;
chip->cur_ecc = &chip->ecc;
nand_release_device(part->master);
return ret;
@@ -1930,7 +2037,9 @@ static int nand_read_oob_std(struct mtd_
int page)
{
chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return 0;
}
@@ -1949,7 +2058,7 @@ static int nand_read_oob_syndrome(struct
chip->cur_ecc->postpad;
int eccsize = chip->cur_ecc->size;
uint8_t *bufpoi = chip->oob_poi;
- int i, toread, sndrnd = 0, pos;
+ int i, toread, sndrnd = 0, pos = eccsize;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->cur_ecc->size, page);
for (i = 0; i < chip->cur_ecc->steps; i++) {
@@ -1962,12 +2071,17 @@ static int nand_read_oob_syndrome(struct
} else
sndrnd = 1;
toread = min_t(int, length, chunk);
- chip->read_buf(mtd, bufpoi, toread);
+ nand_rnd_config(mtd, page, pos, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, bufpoi, toread);
bufpoi += toread;
length -= toread;
}
- if (length > 0)
- chip->read_buf(mtd, bufpoi, length);
+ if (length > 0) {
+ pos = mtd->writesize + mtd->oobsize - length;
+ nand_rnd_config(mtd, page, pos, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, bufpoi, length);
+ }
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
return 0;
}
@@ -1986,7 +2100,9 @@ static int nand_write_oob_std(struct mtd
int length = mtd->oobsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
- chip->write_buf(mtd, buf, length);
+ nand_rnd_config(mtd, page, mtd->writesize, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, buf, length);
+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
/* Send command to program the OOB data */
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
@@ -2042,12 +2158,18 @@ static int nand_write_oob_syndrome(struc
} else
sndcmd = 1;
len = min_t(int, length, chunk);
- chip->write_buf(mtd, bufpoi, len);
+ nand_rnd_config(mtd, page, pos, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, bufpoi, len);
bufpoi += len;
length -= len;
}
- if (length > 0)
- chip->write_buf(mtd, bufpoi, length);
+ if (length > 0) {
+ pos = mtd->writesize + mtd->oobsize - length;
+ nand_rnd_config(mtd, page, pos, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, bufpoi, length);
+ }
+
+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
status = chip->waitfunc(mtd, chip);
@@ -2116,7 +2238,7 @@ static int nand_do_read_oob(struct mtd_i
break;
len = min(len, readlen);
- buf = nand_transfer_oob(chip, buf, ops, len);
+ buf = nand_transfer_oob(mtd, buf, ops, len);
if (chip->options & NAND_NEED_READRDY) {
/* Apply delay or wait for ready/busy pin */
@@ -2226,6 +2348,8 @@ static int nand_part_read_oob(struct mtd
nand_get_device(part->master, FL_READING);
if (part->ecc)
chip->cur_ecc = part->ecc;
+ if (part->rnd)
+ chip->cur_rnd = part->rnd;
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@@ -2243,6 +2367,7 @@ static int nand_part_read_oob(struct mtd
ret = nand_do_read_ops(part->master, from, ops);
out:
+ chip->cur_rnd = &chip->rnd;
chip->cur_ecc = &chip->ecc;
nand_release_device(part->master);
return ret;
@@ -2261,9 +2386,11 @@ out:
static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
const uint8_t *buf, int oob_required)
{
- chip->write_buf(mtd, buf, mtd->writesize);
- if (oob_required)
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_write_buf(mtd, buf, mtd->writesize);
+ if (oob_required) {
+ nand_rnd_config(mtd, -1, mtd->writesize, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ }
return 0;
}
@@ -2285,28 +2412,39 @@ static int nand_write_page_raw_syndrome(
int eccbytes = chip->cur_ecc->bytes;
uint8_t *oob = chip->oob_poi;
int steps, size;
+ int column = 0;
for (steps = chip->cur_ecc->steps; steps > 0; steps--) {
- chip->write_buf(mtd, buf, eccsize);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, buf, eccsize);
buf += eccsize;
+ column += eccsize;
if (chip->cur_ecc->prepad) {
- chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->prepad);
oob += chip->cur_ecc->prepad;
+ column += chip->cur_ecc->prepad;
}
- chip->write_buf(mtd, oob, eccbytes);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, eccbytes);
oob += eccbytes;
+ column += eccbytes;
if (chip->cur_ecc->postpad) {
- chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->postpad);
oob += chip->cur_ecc->postpad;
+ column += chip->cur_ecc->postpad;
}
}
size = mtd->oobsize - (oob - chip->oob_poi);
- if (size)
- chip->write_buf(mtd, oob, size);
+ if (size) {
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, size);
+ }
return 0;
}
@@ -2353,17 +2491,21 @@ static int nand_write_page_hwecc(struct
uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
uint32_t *eccpos = chip->cur_ecc->layout->eccpos;
+ int column = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, p, eccsize);
chip->cur_ecc->calculate(mtd, p, &ecc_calc[i]);
+ column += eccsize;
}
for (i = 0; i < chip->cur_ecc->total; i++)
chip->oob_poi[eccpos[i]] = ecc_calc[i];
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
@@ -2399,7 +2541,9 @@ static int nand_write_subpage_hwecc(stru
chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
/* write data (untouched subpages already masked by 0xFF) */
- chip->write_buf(mtd, buf, ecc_size);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, buf, ecc_size);
+ offset += ecc_size;
/* mask ECC of un-touched subpages by padding 0xFF */
if ((step < start_step) || (step > end_step))
@@ -2424,7 +2568,8 @@ static int nand_write_subpage_hwecc(stru
chip->oob_poi[eccpos[i]] = ecc_calc[i];
/* write OOB buffer to NAND device */
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, chip->oob_poi, mtd->oobsize);
return 0;
}
@@ -2449,31 +2594,42 @@ static int nand_write_page_syndrome(stru
int eccsteps = chip->cur_ecc->steps;
const uint8_t *p = buf;
uint8_t *oob = chip->oob_poi;
+ int column = 0;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
chip->cur_ecc->hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, p, eccsize);
+ column += eccsize;
if (chip->cur_ecc->prepad) {
- chip->write_buf(mtd, oob, chip->cur_ecc->prepad);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->prepad);
oob += chip->cur_ecc->prepad;
+ column += chip->cur_ecc->prepad;
}
chip->cur_ecc->calculate(mtd, p, oob);
- chip->write_buf(mtd, oob, eccbytes);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, eccbytes);
oob += eccbytes;
+ column += eccbytes;
if (chip->cur_ecc->postpad) {
- chip->write_buf(mtd, oob, chip->cur_ecc->postpad);
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, chip->cur_ecc->postpad);
oob += chip->cur_ecc->postpad;
+ column += chip->cur_ecc->postpad;
}
}
/* Calculate remaining oob bytes */
i = mtd->oobsize - (oob - chip->oob_poi);
- if (i)
- chip->write_buf(mtd, oob, i);
+ if (i) {
+ nand_rnd_config(mtd, -1, column, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, i);
+ }
return 0;
}
@@ -2504,6 +2660,7 @@ static int nand_write_page(struct mtd_in
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+ nand_rnd_config(mtd, page, 0, NAND_RND_WRITE);
if (unlikely(raw))
status = chip->cur_ecc->write_page_raw(mtd, chip, buf,
oob_required);
@@ -2514,6 +2671,7 @@ static int nand_write_page(struct mtd_in
else
status = chip->cur_ecc->write_page(mtd, chip, buf,
oob_required);
+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
if (status < 0)
return status;
@@ -2803,6 +2961,8 @@ static int panic_nand_part_write(struct
panic_nand_get_device(chip, part->master, FL_WRITING);
if (part->ecc)
chip->cur_ecc = part->ecc;
+ if (part->rnd)
+ chip->cur_rnd = part->rnd;
ops.len = len;
ops.datbuf = (uint8_t *)buf;
@@ -2811,6 +2971,7 @@ static int panic_nand_part_write(struct
ret = nand_do_write_ops(part->master, to, &ops);
+ chip->cur_rnd = &chip->rnd;
chip->cur_ecc = &chip->ecc;
*retlen = ops.retlen;
return ret;
@@ -2865,12 +3026,15 @@ static int nand_part_write(struct mtd_in
nand_get_device(part->master, FL_WRITING);
if (part->ecc)
chip->cur_ecc = part->ecc;
+ if (part->rnd)
+ chip->cur_rnd = part->rnd;
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(part->master, to, &ops);
*retlen = ops.retlen;
+ chip->cur_rnd = &chip->rnd;
chip->cur_ecc = &chip->ecc;
nand_release_device(part->master);
return ret;
@@ -3032,6 +3196,8 @@ static int nand_part_write_oob(struct mt
nand_get_device(part->master, FL_WRITING);
if (part->ecc)
chip->cur_ecc = part->ecc;
+ if (part->rnd)
+ chip->cur_rnd = part->rnd;
switch (ops->mode) {
case MTD_OPS_PLACE_OOB:
@@ -3049,6 +3215,7 @@ static int nand_part_write_oob(struct mt
ret = nand_do_write_ops(part->master, to, ops);
out:
+ chip->cur_rnd = &chip->rnd;
chip->cur_ecc = &chip->ecc;
nand_release_device(part->master);
return ret;
@@ -4749,6 +4916,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mutex_init(&chip->part_lock);
chip->cur_ecc = &chip->ecc;
+ chip->cur_rnd = &chip->rnd;
/* Allow subpage writes up to ecc.steps. Not possible for MLC flash */
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && nand_is_slc(chip)) {
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -539,6 +539,64 @@ void nand_page_set_status(struct mtd_inf
int nand_pst_create(struct mtd_info *mtd);
+/*
+ * Constants for randomizer modes
+ */
+typedef enum {
+ NAND_RND_NONE,
+ NAND_RND_SOFT,
+ NAND_RND_HW,
+} nand_rnd_modes_t;
+
+/*
+ * Constants for randomizer actions
+ */
+enum nand_rnd_action {
+ NAND_RND_NO_ACTION,
+ NAND_RND_READ,
+ NAND_RND_WRITE,
+};
+
+/**
+ * struct nand_rndfree - Structure defining a NAND page region where the
+ * randomizer should be disabled
+ * @offset: range offset
+ * @length: range length
+ */
+struct nand_rndfree {
+ u32 offset;
+ u32 length;
+};
+
+/**
+ * struct nand_rnd_layout - Structure defining rndfree regions
+ * @nranges: number of ranges
+ * @ranges: array defining the rndfree regions
+ */
+struct nand_rnd_layout {
+ int nranges;
+ struct nand_rndfree ranges[0];
+};
+
+/**
+ * struct nand_rnd_ctrl - Randomizer Control structure
+ * @mode: Randomizer mode
+ * @config: function to prepare the randomizer (i.e.: set the appropriate
+ * seed/init value).
+ * @read_buf: function that read from the NAND and descramble the retrieved
+ * data.
+ * @write_buf: function that scramble data before writing it to the NAND.
+ */
+struct nand_rnd_ctrl {
+ nand_rnd_modes_t mode;
+ struct nand_rnd_layout *layout;
+ void *priv;
+ int (*config)(struct mtd_info *mtd, int page, int column,
+ enum nand_rnd_action action);
+ void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
+ void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
+};
+
/**
* struct nand_buffers - buffer structure for read/write
* @ecccalc: buffer pointer for calculated ECC, size is oobsize.
@@ -731,6 +789,9 @@ struct nand_chip {
struct nand_buffers *buffers;
struct nand_hw_control hwcontrol;
+ struct nand_rnd_ctrl rnd;
+ struct nand_rnd_ctrl *cur_rnd;
+
uint8_t *bbt;
struct nand_bbt_descr *bbt_td;
struct nand_bbt_descr *bbt_md;
@@ -752,6 +813,7 @@ struct nand_chip {
* @master: MTD device representing the NAND chip
* @offset: partition offset
* @ecc: partition specific ECC struct
+ * @rnd: partition specific randomizer struct
* @release: function used to release this nand_part struct
*
* NAND partitions work as standard MTD partitions except it can override
@@ -765,6 +827,7 @@ struct nand_part {
struct mtd_info *master;
uint64_t offset;
struct nand_ecc_ctrl *ecc;
+ struct nand_rnd_ctrl *rnd;
void (*release)(struct nand_part *part);
};
@@ -902,6 +965,41 @@ extern int nand_erase_nand(struct mtd_in
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, uint8_t *buf);
+static inline int nand_rnd_config(struct mtd_info *mtd, int page, int column,
+ enum nand_rnd_action action)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (chip->cur_rnd && chip->cur_rnd->config)
+ return chip->cur_rnd->config(mtd, page, column, action);
+
+ return 0;
+}
+
+static inline void nand_rnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+ int len)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (chip->cur_rnd && chip->cur_rnd->read_buf)
+ chip->cur_rnd->write_buf(mtd, buf, len);
+ else
+ chip->write_buf(mtd, buf, len);
+}
+
+static inline void nand_rnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
+ int len)
+{
+ struct nand_chip *chip = mtd->priv;
+
+ if (chip->cur_rnd && chip->cur_rnd->read_buf)
+ chip->cur_rnd->read_buf(mtd, buf, len);
+ else
+ chip->read_buf(mtd, buf, len);
+}
+
+int nand_rnd_is_activ(struct mtd_info *mtd, int page, int column, int *len);
+
/**
* struct platform_nand_chip - chip level device structure
* @nr_chips: max. number of chips to scan for

View file

@ -1,80 +0,0 @@
From eb7f9115409710732ebc4dfe1be629252280910e Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:47:04 +0200
Subject: [PATCH] of: mtd: Add NAND randomizer mode retrieval
Add a of_get_nand_rnd_mode() helper function.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/of/of_mtd.c | 35 +++++++++++++++++++++++++++++++++++
include/linux/of_mtd.h | 6 ++++++
2 files changed, 41 insertions(+)
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -84,6 +84,41 @@ int of_get_nand_ecc_strength(struct devi
EXPORT_SYMBOL_GPL(of_get_nand_ecc_strength);
/**
+ * It maps 'enum nand_rnd_modes_t' found in include/linux/mtd/nand.h
+ * into the device tree binding of 'nand-rnd', so that MTD
+ * device driver can get nand rnd from device tree.
+ */
+static const char *nand_rnd_modes[] = {
+ [NAND_RND_NONE] = "none",
+ [NAND_RND_SOFT] = "soft",
+ [NAND_RND_HW] = "hw",
+};
+
+/**
+ * of_get_nand_rnd_mode - Get nand randomizer mode for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * The function gets randomizer mode string from property 'nand-rnd-mode',
+ * and return its index in nand_rnd_modes table, or errno in error case.
+ */
+int of_get_nand_rnd_mode(struct device_node *np)
+{
+ const char *pm;
+ int err, i;
+
+ err = of_property_read_string(np, "nand-rnd-mode", &pm);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(nand_rnd_modes); i++)
+ if (!strcasecmp(pm, nand_rnd_modes[i]))
+ return i;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_rnd_mode);
+
+/**
* of_get_nand_bus_width - Get nand bus witdh for given device_node
* @np: Pointer to the given device_node
*
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -15,6 +15,7 @@
int of_get_nand_ecc_mode(struct device_node *np);
int of_get_nand_ecc_step_size(struct device_node *np);
int of_get_nand_ecc_strength(struct device_node *np);
+int of_get_nand_rnd_mode(struct device_node *np);
int of_get_nand_bus_width(struct device_node *np);
bool of_get_nand_on_flash_bbt(struct device_node *np);
@@ -34,6 +35,11 @@ static inline int of_get_nand_ecc_streng
{
return -ENOSYS;
}
+
+static inline int of_get_nand_rnd_mode(struct device_node *np)
+{
+ return -ENOSYS;
+}
static inline int of_get_nand_bus_width(struct device_node *np)
{

View file

@ -1,51 +0,0 @@
From 95430662a26332474f4a03a7f8f44fd8d80890b3 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <b.brezillon.dev@gmail.com>
Date: Mon, 24 Feb 2014 16:28:32 +0100
Subject: [PATCH] mtd: nand: Add manufacturer specific init code infrastructure
Add new fields in nand_manufacturers and nand_chip struct to provide
manufacturer specific handling like read retries.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 7 +++++++
include/linux/mtd/nand.h | 4 ++++
2 files changed, 11 insertions(+)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4382,6 +4382,13 @@ ident_done:
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
+ if (nand_manuf_ids[maf_idx].init) {
+ int err;
+ err = nand_manuf_ids[maf_idx].init(mtd, id_data);
+ if (err)
+ return ERR_PTR(err);
+ }
+
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
*maf_id, *dev_id);
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -748,6 +748,9 @@ struct nand_chip {
int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
int feature_addr, uint8_t *subfeature_para);
int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
+ void (*manuf_cleanup)(struct mtd_info *mtd);
+
+ void *manuf_priv;
int chip_delay;
unsigned int options;
@@ -950,6 +953,7 @@ struct nand_flash_dev {
struct nand_manufacturers {
int id;
char *name;
+ int (*init)(struct mtd_info *mtd, const uint8_t *id);
};
extern struct nand_flash_dev nand_flash_ids[];

View file

@ -1,220 +0,0 @@
From 5c5e3963a1b58be1669da5da93f51dc339cd73d7 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <b.brezillon.dev@gmail.com>
Date: Mon, 24 Feb 2014 16:30:22 +0100
Subject: [PATCH] mtd: nand: Add hynix specific initializer
Add an hynix initiliazer to manage read retries on h27uxgt8t2a chip.
Signed-off-by: Boris BREZILLON <b.brezillon.dev@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/Makefile | 2 +-
drivers/mtd/nand/nand_hynix.c | 159 ++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/nand/nand_ids.c | 3 +-
include/linux/mtd/nand.h | 2 +
4 files changed, 164 insertions(+), 2 deletions(-)
create mode 100644 drivers/mtd/nand/nand_hynix.c
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
-obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
+obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o nand_hynix.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
--- /dev/null
+++ b/drivers/mtd/nand/nand_hynix.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 Boris BREZILLON <b.brezillon.dev@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
+ * (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/module.h>
+#include <linux/mtd/nand.h>
+#include <linux/slab.h>
+
+static u8 h27ucg8t2a_read_retry_regs[] = {
+ 0xcc, 0xbf, 0xaa, 0xab, 0xcd, 0xad, 0xae, 0xaf
+};
+
+struct hynix_read_retry {
+ u8 *regs;
+ u8 values[64];
+};
+
+struct hynix_nand {
+ struct hynix_read_retry read_retry;
+};
+
+int nand_setup_read_retry_hynix(struct mtd_info *mtd, int retry_mode)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hynix_nand *hynix = chip->manuf_priv;
+ int offset = retry_mode * 8;
+ int status;
+ int i;
+
+ chip->cmdfunc(mtd, 0x36, -1, -1);
+ for (i = 0; i < 8; i++) {
+ int column = hynix->read_retry.regs[i];
+ column |= column << 8;
+ chip->cmdfunc(mtd, NAND_CMD_NONE, column, -1);
+ chip->write_byte(mtd, hynix->read_retry.values[offset + i]);
+ }
+ chip->cmdfunc(mtd, 0x16, -1, -1);
+
+ status = chip->waitfunc(mtd, chip);
+ if (status & NAND_STATUS_FAIL)
+ return -EIO;
+
+ return 0;
+}
+
+static void h27ucg8t2a_cleanup(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ kfree(chip->manuf_priv);
+}
+
+static int h27ucg8t2a_init(struct mtd_info *mtd, const uint8_t *id)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hynix_nand *hynix;
+ u8 * buf = NULL;
+ int i, j;
+ int ret;
+
+ buf = kzalloc(1024, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ chip->select_chip(mtd, 0);
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->cmdfunc(mtd, 0x36, 0xff, -1);
+ chip->write_byte(mtd, 0x40);
+ chip->cmdfunc(mtd, NAND_CMD_NONE, 0xcc, -1);
+ chip->write_byte(mtd, 0x4d);
+ chip->cmdfunc(mtd, 0x16, -1, -1);
+ chip->cmdfunc(mtd, 0x17, -1, -1);
+ chip->cmdfunc(mtd, 0x04, -1, -1);
+ chip->cmdfunc(mtd, 0x19, -1, -1);
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0x0, 0x200);
+
+ chip->read_buf(mtd, buf, 2);
+ if (buf[0] != 0x8 || buf[1] != 0x8) {
+ ret = -EINVAL;
+ goto leave;
+ }
+ chip->read_buf(mtd, buf, 1024);
+
+ ret = 0;
+ for (j = 0; j < 8; j++) {
+ for (i = 0; i < 64; i++) {
+ u8 *tmp = buf + (128 * j);
+ if ((tmp[i] | tmp[i + 64]) != 0xff) {
+ ret = -EINVAL;
+ goto leave;
+ }
+ }
+ }
+
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+ chip->cmdfunc(mtd, 0x38, -1, -1);
+ chip->select_chip(mtd, -1);
+
+ if (!ret) {
+ hynix = kzalloc(sizeof(*hynix), GFP_KERNEL);
+ if (!hynix) {
+ ret = -ENOMEM;
+ goto leave;
+ }
+
+ hynix->read_retry.regs = h27ucg8t2a_read_retry_regs;
+ memcpy(hynix->read_retry.values, buf, 64);
+ chip->manuf_priv = hynix;
+ chip->setup_read_retry = nand_setup_read_retry_hynix;
+ chip->read_retries = 8;
+ chip->manuf_cleanup = h27ucg8t2a_cleanup;
+ }
+
+leave:
+ kfree(buf);
+
+ return ret;
+}
+
+struct hynix_nand_initializer {
+ u8 id[6];
+ int (*init)(struct mtd_info *mtd, const uint8_t *id);
+};
+
+struct hynix_nand_initializer initializers[] = {
+ {
+ .id = {NAND_MFR_HYNIX, 0xde, 0x94, 0xda, 0x74, 0xc4},
+ .init = h27ucg8t2a_init,
+ },
+};
+
+int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(initializers); i++) {
+ struct hynix_nand_initializer *initializer = &initializers[i];
+ if (memcmp(id, initializer->id, sizeof(initializer->id)))
+ continue;
+
+ return initializer->init(mtd, id);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(hynix_nand_init);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Boris BREZILLON <b.brezillon.dev@gmail.com>");
+MODULE_DESCRIPTION("Hynix NAND specific code");
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -163,6 +163,7 @@ struct nand_flash_dev nand_flash_ids[] =
{NULL}
};
+
/* Manufacturer IDs */
struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_TOSHIBA, "Toshiba"},
@@ -171,7 +172,7 @@ struct nand_manufacturers nand_manuf_ids
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
- {NAND_MFR_HYNIX, "Hynix"},
+ {NAND_MFR_HYNIX, "Hynix", hynix_nand_init},
{NAND_MFR_MICRON, "Micron"},
{NAND_MFR_AMD, "AMD/Spansion"},
{NAND_MFR_MACRONIX, "Macronix"},
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -959,6 +959,8 @@ struct nand_manufacturers {
extern struct nand_flash_dev nand_flash_ids[];
extern struct nand_manufacturers nand_manuf_ids[];
+int hynix_nand_init(struct mtd_info *mtd, const uint8_t *id);
+
extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_default_bbt(struct mtd_info *mtd);
extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);

View file

@ -1,68 +0,0 @@
From 3fecbdac2fe503fb6896ec08dd2474958d198d62 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sun, 24 May 2015 12:01:16 +0200
Subject: [PATCH] mtd: nand: nand_decode_ext_id(): Fill in ecc strength and
size for Samsung
On some nand controllers with hw-ecc the controller code wants to know the
ecc strength and size and having these as 0, 0 is not accepted.
Specifying these in devicetree is possible but undesirable as the nand
may be different in different production runs of the same board, so it
is better to get this info from the nand id where possible.
This commit adds code to read the ecc strength and size from the nand for
Samsung extended-id nands. This code is based on the info for the 5th
id byte in the datasheets for the following Samsung nands: K9GAG08U0E,
K9GAG08U0F, K9GAG08X0D, K9GBG08U0A, K9GBG08U0B. These all use these bits
in the exact same way.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4063,6 +4063,41 @@ static void nand_decode_ext_id(struct mt
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));
*busw = 0;
+ /* Calc ecc strength and size from 5th id byte*/
+ switch ((id_data[4] >> 4) & 0x07) {
+ case 0:
+ chip->ecc_strength_ds = 1;
+ chip->ecc_step_ds = 512;
+ break;
+ case 1:
+ chip->ecc_strength_ds = 2;
+ chip->ecc_step_ds = 512;
+ break;
+ case 2:
+ chip->ecc_strength_ds = 4;
+ chip->ecc_step_ds = 512;
+ break;
+ case 3:
+ chip->ecc_strength_ds = 8;
+ chip->ecc_step_ds = 512;
+ break;
+ case 4:
+ chip->ecc_strength_ds = 16;
+ chip->ecc_step_ds = 512;
+ break;
+ case 5:
+ chip->ecc_strength_ds = 24;
+ chip->ecc_step_ds = 1024;
+ break;
+ case 6:
+ chip->ecc_strength_ds = 40;
+ chip->ecc_step_ds = 1024;
+ break;
+ case 7:
+ chip->ecc_strength_ds = 60;
+ chip->ecc_step_ds = 1024;
+ break;
+ }
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
!nand_is_slc(chip)) {
unsigned int tmp;

View file

@ -1,29 +0,0 @@
From ec6cde9ea451ffa94b4d0ccbbcbe15c0d35f73d8 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 25 May 2015 12:57:48 +0200
Subject: [PATCH] mtd: nand: nand_get_flash_type: Print detected ECC strength
and size
Print the detected ECC strength and size from nand_get_flash_type().
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4437,9 +4437,11 @@ ident_done:
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
type->name);
- pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n",
+ pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, "
+ "OOB size: %d, ECC strength %d size %d\n",
(int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
- mtd->erasesize >> 10, mtd->writesize, mtd->oobsize);
+ mtd->erasesize >> 10, mtd->writesize, mtd->oobsize,
+ chip->ecc_strength_ds, chip->ecc_step_ds);
return type;
}

View file

@ -1,67 +0,0 @@
From fb177d5b534f263735dc6955703e3c711b950f35 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <hramrach@gmail.com>
Date: Thu, 1 Jan 2015 00:57:46 +0100
Subject: [PATCH] mtd: nand: print full chip ID
Full chip ID is printed so user has data to paste from syslog in case
of chip misidentification.
Signed-off-by: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/nand_base.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4247,7 +4247,7 @@ static inline bool is_full_id_nand(struc
}
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
- struct nand_flash_dev *type, u8 *id_data, int *busw)
+ struct nand_flash_dev *type, const u8 *id_data, int *busw)
{
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
@@ -4273,6 +4273,21 @@ static bool find_full_id_nand(struct mtd
}
/*
+ * Print full detail of chip ID read from chip.
+ */
+static void print_nand_chip_info(int maf_id, int dev_id, u8 id_data[8])
+{
+ u8 delim[8] = { [0 ... 7] = ',' };
+ pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", maf_id, dev_id);
+ delim[7] = ' ';
+ delim[nand_id_len(id_data, 8) - 1] = ';';
+ /* This sucks. Kernel seems to insert newline after every other printk so format in one go. */
+ pr_info("chip id data: 0x%02x%c 0x%02x%c 0x%02x%c 0x%02x%c 0x%02x%c 0x%02x%c 0x%02x%c 0x%02x%c\n",
+ id_data[0], delim[0], id_data[1], delim[1], id_data[2], delim[2], id_data[3], delim[3],
+ id_data[4], delim[4], id_data[5], delim[5], id_data[6], delim[6], id_data[7], delim[7]);
+}
+
+/*
* Get the flash and manufacturer id and lookup if the type is supported.
*/
static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
@@ -4385,8 +4400,7 @@ ident_done:
* Check, if buswidth is correct. Hardware drivers should set
* chip correct!
*/
- pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
- *maf_id, *dev_id);
+ print_nand_chip_info(*maf_id, *dev_id, id_data);
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
pr_warn("bus width %d instead %d bit\n",
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -4424,8 +4438,7 @@ ident_done:
return ERR_PTR(err);
}
- pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
- *maf_id, *dev_id);
+ print_nand_chip_info(*maf_id, *dev_id, id_data);
if (chip->onfi_version)
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,

View file

@ -1,160 +0,0 @@
From 5cb31780791d0f6b68e3712f1b35f1a28c47add0 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@free-electrons.com>
Date: Tue, 21 Oct 2014 14:37:15 +0200
Subject: [PATCH] mtd: nand: sunxi: Add NAND partition support
Add NAND partition support to the sunxi_nand driver.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/Kconfig | 1 +
drivers/mtd/nand/sunxi_nand.c | 73 +++++++++++++++++++++++++++++++++++++------
2 files changed, 65 insertions(+), 9 deletions(-)
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -525,6 +525,7 @@ config MTD_NAND_XWAY
config MTD_NAND_SUNXI
tristate "Support for NAND on Allwinner SoCs"
depends on ARCH_SUNXI
+ select MTD_OF_NAND_PARTS
help
Enables support for NAND Flash chips on Allwinner SoCs.
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -206,6 +206,23 @@ struct sunxi_nand_hw_ecc {
};
/*
+ * sunxi NAND partition structure: stores NAND partitions information
+ *
+ * @part: base paritition structure
+ * @ecc: per-partition ECC info
+ */
+struct sunxi_nand_part {
+ struct nand_part part;
+ struct nand_ecc_ctrl ecc;
+};
+
+static inline struct sunxi_nand_part *
+to_sunxi_nand_part(struct nand_part *part)
+{
+ return container_of(part, struct sunxi_nand_part, part);
+}
+
+/*
* NAND chip structure: stores NAND chip device related information
*
* @node: used to store NAND chips into a list
@@ -525,7 +542,7 @@ static int sunxi_nfc_hw_ecc_read_page(st
int oob_required, int page)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct nand_ecclayout *layout = ecc->layout;
struct sunxi_nand_hw_ecc *data = ecc->priv;
unsigned int max_bitflips = 0;
@@ -611,7 +628,7 @@ static int sunxi_nfc_hw_ecc_write_page(s
const uint8_t *buf, int oob_required)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct nand_ecclayout *layout = ecc->layout;
struct sunxi_nand_hw_ecc *data = ecc->priv;
int offset;
@@ -679,7 +696,7 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
int page)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct sunxi_nand_hw_ecc *data = ecc->priv;
unsigned int max_bitflips = 0;
uint8_t *oob = chip->oob_poi;
@@ -747,7 +764,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
int oob_required)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
- struct nand_ecc_ctrl *ecc = &chip->ecc;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct sunxi_nand_hw_ecc *data = ecc->priv;
uint8_t *oob = chip->oob_poi;
int offset = 0;
@@ -1091,8 +1108,13 @@ static int sunxi_nand_ecc_init(struct mt
ecc->strength = nand->ecc_strength_ds;
}
- if (!ecc->size || !ecc->strength)
- return -EINVAL;
+ if (!ecc->size || !ecc->strength) {
+ if (ecc == &nand->ecc)
+ return -EINVAL;
+
+ ecc->size = nand->ecc.size;
+ ecc->strength = nand->ecc.strength;
+ }
ecc->mode = NAND_ECC_HW;
@@ -1127,12 +1149,39 @@ static int sunxi_nand_ecc_init(struct mt
return 0;
}
+static void sunxi_nand_part_release(struct nand_part *part)
+{
+ kfree(to_sunxi_nand_part(part));
+}
+
+struct nand_part *sunxi_ofnandpart_parse(void *priv, struct mtd_info *master,
+ struct device_node *pp)
+{
+ struct sunxi_nand_part *part;
+ int ret;
+
+ part = kzalloc(sizeof(*part), GFP_KERNEL);
+ part->part.release = sunxi_nand_part_release;
+
+ ret = sunxi_nand_ecc_init(master, &part->ecc, pp);
+ if (ret)
+ goto err;
+
+ part->part.ecc = &part->ecc;
+
+ return &part->part;
+
+err:
+ kfree(part);
+ return ERR_PTR(ret);
+}
+
static int sunxi_nand_chip_init(struct device *dev, struct sunxi_nfc *nfc,
struct device_node *np)
{
const struct nand_sdr_timings *timings;
struct sunxi_nand_chip *chip;
- struct mtd_part_parser_data ppdata;
+ struct ofnandpart_data ppdata;
struct mtd_info *mtd;
struct nand_chip *nand;
int nsels;
@@ -1261,8 +1310,14 @@ static int sunxi_nand_chip_init(struct d
return ret;
}
- ppdata.of_node = np;
- ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ ppdata.node = np;
+ ppdata.parse = sunxi_ofnandpart_parse;
+ ret = ofnandpart_parse(mtd, &ppdata);
+ if (!ret)
+ ret = mtd_device_register(mtd, NULL, 0);
+ else if (ret > 0)
+ ret = 0;
+
if (ret) {
dev_err(dev, "failed to register mtd device: %d\n", ret);
nand_release(mtd);

View file

@ -1,887 +0,0 @@
From ef4bc8ab68979e5c1c30f061c5af1a7d6ec8eb52 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@free-electrons.com>
Date: Tue, 21 Oct 2014 14:40:42 +0200
Subject: [PATCH] mtd: nand: sunxi: Add HW randomizer support
Add support for the HW randomizer available on the sunxi nand controller.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/sunxi_nand.c | 603 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 585 insertions(+), 18 deletions(-)
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -210,10 +210,12 @@ struct sunxi_nand_hw_ecc {
*
* @part: base paritition structure
* @ecc: per-partition ECC info
+ * @rnd: per-partition randomizer info
*/
struct sunxi_nand_part {
struct nand_part part;
struct nand_ecc_ctrl ecc;
+ struct nand_rnd_ctrl rnd;
};
static inline struct sunxi_nand_part *
@@ -223,6 +225,29 @@ to_sunxi_nand_part(struct nand_part *par
}
/*
+ * sunxi NAND randomizer structure: stores NAND randomizer information
+ *
+ * @page: current page
+ * @column: current column
+ * @nseeds: seed table size
+ * @seeds: seed table
+ * @subseeds: pre computed sub seeds
+ * @step: step function
+ * @left: number of remaining bytes in the page
+ * @state: current randomizer state
+ */
+struct sunxi_nand_hw_rnd {
+ int page;
+ int column;
+ int nseeds;
+ u16 *seeds;
+ u16 *subseeds;
+ u16 (*step)(struct mtd_info *mtd, u16 state, int column, int *left);
+ int left;
+ u16 state;
+};
+
+/*
* NAND chip structure: stores NAND chip device related information
*
* @node: used to store NAND chips into a list
@@ -237,6 +262,7 @@ struct sunxi_nand_chip {
struct list_head node;
struct nand_chip nand;
struct mtd_info mtd;
+ void *buffer;
unsigned long clk_rate;
int selected;
int nsels;
@@ -493,6 +519,185 @@ static void sunxi_nfc_write_buf(struct m
}
}
+static u16 sunxi_nfc_hwrnd_step(struct sunxi_nand_hw_rnd *rnd, u16 state, int count)
+{
+ state &= 0x7fff;
+ count *= 8;
+ while (count--)
+ state = ((state >> 1) |
+ ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+ return state;
+}
+
+static u16 sunxi_nfc_hwrnd_single_step(u16 state, int count)
+{
+ state &= 0x7fff;
+ while (count--)
+ state = ((state >> 1) |
+ ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff;
+
+ return state;
+}
+
+static int sunxi_nfc_hwrnd_config(struct mtd_info *mtd, int page, int column,
+ enum nand_rnd_action action)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
+ u16 state;
+
+ if (page < 0 && column < 0) {
+ rnd->page = -1;
+ rnd->column = -1;
+ return 0;
+ }
+
+ if (column < 0)
+ column = 0;
+ if (page < 0)
+ page = rnd->page;
+
+ if (page < 0)
+ return -EINVAL;
+
+ if (page != rnd->page && action == NAND_RND_READ) {
+ int status;
+
+ status = nand_page_get_status(mtd, page);
+ if (status == NAND_PAGE_STATUS_UNKNOWN) {
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
+ mtd->writesize + mtd->oobsize);
+
+ if (nand_page_is_empty(mtd, sunxi_nand->buffer,
+ sunxi_nand->buffer +
+ mtd->writesize))
+ status = NAND_PAGE_EMPTY;
+ else
+ status = NAND_PAGE_FILLED;
+
+ nand_page_set_status(mtd, page, status);
+ nand->cmdfunc(mtd, NAND_CMD_RNDOUT, column, -1);
+ }
+ }
+
+ state = rnd->seeds[page % rnd->nseeds];
+ rnd->page = page;
+ rnd->column = column;
+
+ if (rnd->step) {
+ rnd->state = rnd->step(mtd, state, column, &rnd->left);
+ } else {
+ rnd->state = sunxi_nfc_hwrnd_step(rnd, state, column % 4096);
+ rnd->left = mtd->oobsize + mtd->writesize - column;
+ }
+
+ return 0;
+}
+
+static void sunxi_nfc_hwrnd_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+ int len)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
+ u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ int cnt;
+ int offs = 0;
+ int rndactiv;
+
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ if (rnd->page < 0) {
+ sunxi_nfc_write_buf(mtd, buf, len);
+ return;
+ }
+
+ while (len > offs) {
+ cnt = len - offs;
+ if (cnt > 1024)
+ cnt = 1024;
+
+ rndactiv = nand_rnd_is_activ(mtd, rnd->page, rnd->column,
+ &cnt);
+ if (rndactiv > 0) {
+ writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
+ nfc->regs + NFC_REG_ECC_CTL);
+ if (rnd->left < cnt)
+ cnt = rnd->left;
+ }
+
+ sunxi_nfc_write_buf(mtd, buf + offs, cnt);
+
+ if (rndactiv > 0)
+ writel(tmp & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+
+ offs += cnt;
+ if (len <= offs)
+ break;
+
+ sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_WRITE);
+ }
+}
+
+static void sunxi_nfc_hwrnd_read_buf(struct mtd_info *mtd, uint8_t *buf,
+ int len)
+{
+ struct nand_chip *nand = mtd->priv;
+ struct sunxi_nfc *nfc = to_sunxi_nfc(nand->controller);
+ struct sunxi_nand_hw_rnd *rnd = nand->cur_rnd->priv;
+ u32 tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ int cnt;
+ int offs = 0;
+ int rndactiv;
+
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_RANDOM_SEED | NFC_RANDOM_EN);
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+
+ if (rnd->page < 0) {
+ sunxi_nfc_read_buf(mtd, buf, len);
+ return;
+ }
+
+ while (len > offs) {
+ cnt = len - offs;
+ if (cnt > 1024)
+ cnt = 1024;
+
+ if (nand_page_get_status(mtd, rnd->page) != NAND_PAGE_EMPTY &&
+ nand_rnd_is_activ(mtd, rnd->page, rnd->column, &cnt) > 0)
+ rndactiv = 1;
+ else
+ rndactiv = 0;
+
+ if (rndactiv > 0) {
+ writel(tmp | NFC_RANDOM_EN | (rnd->state << 16),
+ nfc->regs + NFC_REG_ECC_CTL);
+ if (rnd->left < cnt)
+ cnt = rnd->left;
+ }
+
+ if (buf)
+ sunxi_nfc_read_buf(mtd, buf + offs, cnt);
+ else
+ sunxi_nfc_read_buf(mtd, NULL, cnt);
+
+ if (rndactiv > 0)
+ writel(tmp & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+
+ offs += cnt;
+ if (len <= offs)
+ break;
+
+ sunxi_nfc_hwrnd_config(mtd, -1, rnd->column + cnt, NAND_RND_READ);
+ }
+}
+
static uint8_t sunxi_nfc_read_byte(struct mtd_info *mtd)
{
uint8_t ret;
@@ -542,16 +747,43 @@ static int sunxi_nfc_hw_ecc_read_page(st
int oob_required, int page)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct nand_ecclayout *layout = ecc->layout;
struct sunxi_nand_hw_ecc *data = ecc->priv;
unsigned int max_bitflips = 0;
+ int status;
int offset;
int ret;
u32 tmp;
int i;
int cnt;
+ status = nand_page_get_status(mtd, page);
+ if (status == NAND_PAGE_STATUS_UNKNOWN) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
+ mtd->writesize + mtd->oobsize);
+
+ if (nand_page_is_empty(mtd, sunxi_nand->buffer,
+ sunxi_nand->buffer +
+ mtd->writesize)) {
+ status = NAND_PAGE_EMPTY;
+ } else {
+ status = NAND_PAGE_FILLED;
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ }
+
+ nand_page_set_status(mtd, page, status);
+ }
+
+ if (status == NAND_PAGE_EMPTY) {
+ memset(buf, 0xff, mtd->writesize);
+ if (oob_required)
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+ return 0;
+ }
+
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
@@ -560,12 +792,15 @@ static int sunxi_nfc_hw_ecc_read_page(st
writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
for (i = 0; i < ecc->steps; i++) {
+ bool rndactiv = false;
+
if (i)
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, i * ecc->size, -1);
offset = mtd->writesize + layout->eccpos[i * ecc->bytes] - 4;
- chip->read_buf(mtd, NULL, ecc->size);
+ nand_rnd_config(mtd, page, i * ecc->size, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, NULL, ecc->size);
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
@@ -573,6 +808,25 @@ static int sunxi_nfc_hw_ecc_read_page(st
if (ret)
return ret;
+ if (i) {
+ cnt = ecc->bytes + 4;
+ if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
+ cnt == ecc->bytes + 4)
+ rndactiv = true;
+ } else {
+ cnt = ecc->bytes + 2;
+ if (nand_rnd_is_activ(mtd, page, offset + 2, &cnt) > 0 &&
+ cnt == ecc->bytes + 2)
+ rndactiv = true;
+ }
+
+ if (rndactiv) {
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
+ tmp |= NFC_RANDOM_EN;
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+ }
+
tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
writel(tmp, nfc->regs + NFC_REG_CMD);
@@ -583,6 +837,9 @@ static int sunxi_nfc_hw_ecc_read_page(st
memcpy_fromio(buf + (i * ecc->size),
nfc->regs + NFC_RAM0_BASE, ecc->size);
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+
if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
mtd->ecc_stats.failed++;
} else {
@@ -598,9 +855,10 @@ static int sunxi_nfc_hw_ecc_read_page(st
if (ret)
return ret;
+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
offset -= mtd->writesize;
- chip->read_buf(mtd, chip->oob_poi + offset,
- ecc->bytes + 4);
+ nand_rnd_read_buf(mtd, chip->oob_poi + offset,
+ ecc->bytes + 4);
}
}
@@ -610,11 +868,14 @@ static int sunxi_nfc_hw_ecc_read_page(st
offset = mtd->writesize +
ecc->layout->oobfree[ecc->steps].offset;
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
offset -= mtd->writesize;
- chip->read_buf(mtd, chip->oob_poi + offset, cnt);
+ nand_rnd_read_buf(mtd, chip->oob_poi + offset, cnt);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~NFC_ECC_EN;
@@ -631,6 +892,7 @@ static int sunxi_nfc_hw_ecc_write_page(s
struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct nand_ecclayout *layout = ecc->layout;
struct sunxi_nand_hw_ecc *data = ecc->priv;
+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
int offset;
int ret;
u32 tmp;
@@ -645,17 +907,57 @@ static int sunxi_nfc_hw_ecc_write_page(s
writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
for (i = 0; i < ecc->steps; i++) {
+ bool rndactiv = false;
+ u8 oob_buf[4];
+
if (i)
chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
- chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
+ nand_rnd_config(mtd, -1, i * ecc->size, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
/* Fill OOB data in */
- writel(NFC_BUF_TO_USER_DATA(chip->oob_poi +
- layout->oobfree[i].offset),
- nfc->regs + NFC_REG_USER_DATA_BASE);
+ if (!oob_required)
+ memset(oob_buf, 0xff, 4);
+ else
+ memcpy(oob_buf,
+ chip->oob_poi + layout->oobfree[i].offset,
+ 4);
+
+
+ memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
+
+ if (i) {
+ cnt = ecc->bytes + 4;
+ if (rnd &&
+ nand_rnd_is_activ(mtd, -1, offset, &cnt) > 0 &&
+ cnt == ecc->bytes + 4)
+ rndactiv = true;
+ } else {
+ cnt = ecc->bytes + 2;
+ if (rnd &&
+ nand_rnd_is_activ(mtd, -1, offset + 2, &cnt) > 0 &&
+ cnt == ecc->bytes + 2)
+ rndactiv = true;
+ }
+
+ if (rndactiv) {
+ /* pre randomize to generate FF patterns on the NAND */
+ if (!i) {
+ u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
+ state = sunxi_nfc_hwrnd_single_step(state, 15);
+ oob_buf[0] ^= state;
+ state = sunxi_nfc_hwrnd_step(rnd, state, 1);
+ oob_buf[1] ^= state;
+ memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
+ }
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
+ tmp |= NFC_RANDOM_EN;
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+ }
chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
@@ -669,6 +971,9 @@ static int sunxi_nfc_hw_ecc_write_page(s
ret = sunxi_nfc_wait_int(nfc, NFC_CMD_INT_FLAG, 0);
if (ret)
return ret;
+
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
}
if (oob_required) {
@@ -677,11 +982,14 @@ static int sunxi_nfc_hw_ecc_write_page(s
offset = mtd->writesize +
ecc->layout->oobfree[i].offset;
chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
offset -= mtd->writesize;
- chip->write_buf(mtd, chip->oob_poi + offset, cnt);
+ nand_rnd_write_buf(mtd, chip->oob_poi + offset, cnt);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
+
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~NFC_ECC_EN;
@@ -690,22 +998,76 @@ static int sunxi_nfc_hw_ecc_write_page(s
return 0;
}
+static u16 sunxi_nfc_hw_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
+ int column, int *left)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
+ int nblks = mtd->writesize / ecc->size;
+ int modsize = ecc->size;
+ int steps;
+
+ if (column < mtd->writesize) {
+ steps = column % modsize;
+ *left = modsize - steps;
+ } else if (column < mtd->writesize +
+ (nblks * (ecc->bytes + 4))) {
+ column -= mtd->writesize;
+ steps = column % (ecc->bytes + 4);
+ *left = ecc->bytes + 4 - steps;
+ state = rnd->subseeds[rnd->page % rnd->nseeds];
+ } else {
+ steps = column % 4096;
+ *left = mtd->writesize + mtd->oobsize - column;
+ }
+
+ return sunxi_nfc_hwrnd_step(rnd, state, steps);
+}
+
static int sunxi_nfc_hw_syndrome_ecc_read_page(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf, int oob_required,
int page)
{
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
+ struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(chip);
struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct sunxi_nand_hw_ecc *data = ecc->priv;
unsigned int max_bitflips = 0;
uint8_t *oob = chip->oob_poi;
int offset = 0;
int ret;
+ int status;
int cnt;
u32 tmp;
int i;
+ status = nand_page_get_status(mtd, page);
+ if (status == NAND_PAGE_STATUS_UNKNOWN) {
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ sunxi_nfc_read_buf(mtd, sunxi_nand->buffer,
+ mtd->writesize + mtd->oobsize);
+
+ if (nand_page_is_empty(mtd, sunxi_nand->buffer,
+ sunxi_nand->buffer +
+ mtd->writesize)) {
+ status = NAND_PAGE_EMPTY;
+ } else {
+ status = NAND_PAGE_FILLED;
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0, -1);
+ }
+
+ nand_page_set_status(mtd, page, status);
+ }
+
+ if (status == NAND_PAGE_EMPTY) {
+ memset(buf, 0xff, mtd->writesize);
+ if (oob_required)
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+ return 0;
+ }
+
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~(NFC_ECC_MODE | NFC_ECC_PIPELINE | NFC_ECC_BLOCK_SIZE);
tmp |= NFC_ECC_EN | (data->mode << NFC_ECC_MODE_SHIFT) |
@@ -714,7 +1076,17 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
for (i = 0; i < ecc->steps; i++) {
- chip->read_buf(mtd, NULL, ecc->size);
+ nand_rnd_config(mtd, page, offset, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, NULL, ecc->size);
+
+ cnt = ecc->bytes + 4;
+ if (nand_rnd_is_activ(mtd, page, offset, &cnt) > 0 &&
+ cnt == ecc->bytes + 4) {
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
+ tmp |= NFC_RANDOM_EN;
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+ }
tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | (1 << 30);
writel(tmp, nfc->regs + NFC_REG_CMD);
@@ -727,6 +1099,9 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
buf += ecc->size;
offset += ecc->size;
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+
if (readl(nfc->regs + NFC_REG_ECC_ST) & 0x1) {
mtd->ecc_stats.failed++;
} else {
@@ -737,7 +1112,8 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
if (oob_required) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
- chip->read_buf(mtd, oob, ecc->bytes + ecc->prepad);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, ecc->bytes + ecc->prepad);
oob += ecc->bytes + ecc->prepad;
}
@@ -748,10 +1124,13 @@ static int sunxi_nfc_hw_syndrome_ecc_rea
cnt = mtd->oobsize - (oob - chip->oob_poi);
if (cnt > 0) {
chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
- chip->read_buf(mtd, oob, cnt);
+ nand_rnd_config(mtd, page, offset, NAND_RND_READ);
+ nand_rnd_read_buf(mtd, oob, cnt);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_READ);
+
writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_ECC_EN,
nfc->regs + NFC_REG_ECC_CTL);
@@ -766,6 +1145,7 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
struct sunxi_nfc *nfc = to_sunxi_nfc(chip->controller);
struct nand_ecc_ctrl *ecc = chip->cur_ecc;
struct sunxi_nand_hw_ecc *data = ecc->priv;
+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
uint8_t *oob = chip->oob_poi;
int offset = 0;
int ret;
@@ -781,13 +1161,24 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
for (i = 0; i < ecc->steps; i++) {
- chip->write_buf(mtd, buf + (i * ecc->size), ecc->size);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, buf + (i * ecc->size), ecc->size);
offset += ecc->size;
/* Fill OOB data in */
writel(NFC_BUF_TO_USER_DATA(oob),
nfc->regs + NFC_REG_USER_DATA_BASE);
+ cnt = ecc->bytes + 4;
+ if (rnd &&
+ nand_rnd_is_activ(mtd, rnd->page, offset, &cnt) > 0 &&
+ cnt == ecc->bytes + 4) {
+ tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
+ tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
+ tmp |= NFC_RANDOM_EN;
+ writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
+ }
+
tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ACCESS_DIR |
(1 << 30);
writel(tmp, nfc->regs + NFC_REG_CMD);
@@ -796,6 +1187,9 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
if (ret)
return ret;
+ writel(readl(nfc->regs + NFC_REG_ECC_CTL) & ~NFC_RANDOM_EN,
+ nfc->regs + NFC_REG_ECC_CTL);
+
offset += ecc->bytes + ecc->prepad;
oob += ecc->bytes + ecc->prepad;
}
@@ -804,9 +1198,11 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
cnt = mtd->oobsize - (oob - chip->oob_poi);
if (cnt > 0) {
chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
- chip->write_buf(mtd, oob, cnt);
+ nand_rnd_config(mtd, -1, offset, NAND_RND_WRITE);
+ nand_rnd_write_buf(mtd, oob, cnt);
}
}
+ nand_rnd_config(mtd, -1, -1, NAND_RND_WRITE);
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~NFC_ECC_EN;
@@ -816,6 +1212,128 @@ static int sunxi_nfc_hw_syndrome_ecc_wri
return 0;
}
+static u16 sunxi_nfc_hw_syndrome_ecc_rnd_steps(struct mtd_info *mtd, u16 state,
+ int column, int *left)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct nand_ecc_ctrl *ecc = chip->cur_ecc;
+ struct sunxi_nand_hw_rnd *rnd = chip->cur_rnd->priv;
+ int eccsteps = mtd->writesize / ecc->size;
+ int modsize = ecc->size + ecc->prepad + ecc->bytes;
+ int steps;
+
+ if (column < (eccsteps * modsize)) {
+ steps = column % modsize;
+ *left = modsize - steps;
+ if (steps >= ecc->size) {
+ steps -= ecc->size;
+ state = rnd->subseeds[rnd->page % rnd->nseeds];
+ }
+ } else {
+ steps = column % 4096;
+ *left = mtd->writesize + mtd->oobsize - column;
+ }
+
+ return sunxi_nfc_hwrnd_step(rnd, state, steps);
+}
+
+static u16 default_seeds[] = {0x4a80};
+
+static void sunxi_nand_rnd_ctrl_cleanup(struct nand_rnd_ctrl *rnd)
+{
+ struct sunxi_nand_hw_rnd *hwrnd = rnd->priv;
+
+ if (hwrnd->seeds != default_seeds)
+ kfree(hwrnd->seeds);
+ kfree(hwrnd->subseeds);
+ kfree(rnd->layout);
+ kfree(hwrnd);
+}
+
+static int sunxi_nand_rnd_ctrl_init(struct mtd_info *mtd,
+ struct nand_rnd_ctrl *rnd,
+ struct nand_ecc_ctrl *ecc,
+ struct device_node *np)
+{
+ struct sunxi_nand_hw_rnd *hwrnd;
+ struct nand_rnd_layout *layout = NULL;
+ int ret;
+
+ hwrnd = kzalloc(sizeof(*hwrnd), GFP_KERNEL);
+ if (!hwrnd)
+ return -ENOMEM;
+
+ hwrnd->seeds = default_seeds;
+ hwrnd->nseeds = ARRAY_SIZE(default_seeds);
+
+ if (of_get_property(np, "nand-randomizer-seeds", &ret)) {
+ hwrnd->nseeds = ret / sizeof(*hwrnd->seeds);
+ hwrnd->seeds = kzalloc(hwrnd->nseeds * sizeof(*hwrnd->seeds),
+ GFP_KERNEL);
+ if (!hwrnd->seeds) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ret = of_property_read_u16_array(np, "nand-randomizer-seeds",
+ hwrnd->seeds, hwrnd->nseeds);
+ if (ret)
+ goto err;
+ }
+
+ switch (ecc->mode) {
+ case NAND_ECC_HW_SYNDROME:
+ hwrnd->step = sunxi_nfc_hw_syndrome_ecc_rnd_steps;
+ break;
+
+ case NAND_ECC_HW:
+ hwrnd->step = sunxi_nfc_hw_ecc_rnd_steps;
+
+ default:
+ layout = kzalloc(sizeof(*layout) + sizeof(struct nand_rndfree),
+ GFP_KERNEL);
+ if (!layout) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ layout->nranges = 1;
+ layout->ranges[0].offset = mtd->writesize;
+ layout->ranges[0].length = 2;
+ rnd->layout = layout;
+ break;
+ }
+
+ if (ecc->mode == NAND_ECC_HW_SYNDROME || ecc->mode == NAND_ECC_HW) {
+ int i;
+
+ hwrnd->subseeds = kzalloc(hwrnd->nseeds *
+ sizeof(*hwrnd->subseeds),
+ GFP_KERNEL);
+ if (!hwrnd->subseeds) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < hwrnd->nseeds; i++)
+ hwrnd->subseeds[i] = sunxi_nfc_hwrnd_step(hwrnd,
+ hwrnd->seeds[i],
+ ecc->size);
+ }
+
+ rnd->config = sunxi_nfc_hwrnd_config;
+ rnd->read_buf = sunxi_nfc_hwrnd_read_buf;
+ rnd->write_buf = sunxi_nfc_hwrnd_write_buf;
+ rnd->priv = hwrnd;
+
+ return 0;
+
+err:
+ kfree(hwrnd);
+ kfree(layout);
+
+ return ret;
+}
+
static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip,
const struct nand_sdr_timings *timings)
{
@@ -1076,6 +1594,40 @@ static int sunxi_nand_hw_syndrome_ecc_ct
return 0;
}
+static void sunxi_nand_rnd_cleanup(struct nand_rnd_ctrl *rnd)
+{
+ switch (rnd->mode) {
+ case NAND_RND_HW:
+ sunxi_nand_rnd_ctrl_cleanup(rnd);
+ break;
+ default:
+ break;
+ }
+}
+
+static int sunxi_nand_rnd_init(struct mtd_info *mtd,
+ struct nand_rnd_ctrl *rnd,
+ struct nand_ecc_ctrl *ecc,
+ struct device_node *np)
+{
+ int ret;
+
+ rnd->mode = NAND_RND_NONE;
+
+ ret = of_get_nand_rnd_mode(np);
+ if (ret >= 0)
+ rnd->mode = ret;
+
+ switch (rnd->mode) {
+ case NAND_RND_HW:
+ return sunxi_nand_rnd_ctrl_init(mtd, rnd, ecc, np);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
{
switch (ecc->mode) {
@@ -1167,7 +1719,14 @@ struct nand_part *sunxi_ofnandpart_parse
if (ret)
goto err;
+ ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
+ if (ret) {
+ sunxi_nand_ecc_cleanup(&part->ecc);
+ goto err;
+ }
+
part->part.ecc = &part->ecc;
+ part->part.rnd = &part->rnd;
return &part->part;
@@ -1292,18 +1851,30 @@ static int sunxi_nand_chip_init(struct d
if (ret)
return ret;
+ chip->buffer = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
+ if (!chip->buffer)
+ return -ENOMEM;
+
ret = sunxi_nand_chip_init_timings(chip, np);
if (ret) {
dev_err(dev, "could not configure chip timings: %d\n", ret);
return ret;
}
+ ret = nand_pst_create(mtd);
+ if (ret)
+ return ret;
+
ret = sunxi_nand_ecc_init(mtd, &nand->ecc, np);
if (ret) {
dev_err(dev, "ECC init failed: %d\n", ret);
return ret;
}
+ ret = sunxi_nand_rnd_init(mtd, &nand->rnd, &nand->ecc, np);
+ if (ret)
+ return ret;
+
ret = nand_scan_tail(mtd);
if (ret) {
dev_err(dev, "nand_scan_tail failed: %d\n", ret);
@@ -1360,6 +1931,8 @@ static void sunxi_nand_chips_cleanup(str
nand_release(&chip->mtd);
sunxi_nand_ecc_cleanup(&chip->nand.ecc);
list_del(&chip->node);
+ sunxi_nand_rnd_cleanup(&chip->nand.rnd);
+ kfree(chip->buffer);
}
}

View file

@ -1,65 +0,0 @@
From de994d9c849ca0ca020fccfa1916afcde7f313f2 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Sun, 24 Aug 2014 10:40:44 +0200
Subject: [PATCH] mtd: nand: sunxi: Fallback to chip config when partition
config is not available
Fallback to chip config for partitions where ecc/rnd config are not
specified in the device tree.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/sunxi_nand.c | 27 ++++++++++++++++++---------
1 file changed, 18 insertions(+), 9 deletions(-)
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1709,28 +1709,37 @@ static void sunxi_nand_part_release(stru
struct nand_part *sunxi_ofnandpart_parse(void *priv, struct mtd_info *master,
struct device_node *pp)
{
+ struct nand_chip *chip = master->priv;
struct sunxi_nand_part *part;
int ret;
part = kzalloc(sizeof(*part), GFP_KERNEL);
part->part.release = sunxi_nand_part_release;
- ret = sunxi_nand_ecc_init(master, &part->ecc, pp);
- if (ret)
- goto err;
-
- ret = sunxi_nand_rnd_init(master, &part->rnd, &part->ecc, pp);
- if (ret) {
- sunxi_nand_ecc_cleanup(&part->ecc);
- goto err;
+ if (of_find_property(pp, "nand-ecc-mode", NULL)) {
+ ret = sunxi_nand_ecc_init(master, &part->ecc, pp);
+ if (ret)
+ goto err;
+
+ part->part.ecc = &part->ecc;
}
- part->part.ecc = &part->ecc;
- part->part.rnd = &part->rnd;
+ if (of_find_property(pp, "nand-rnd-mode", NULL)) {
+ ret = sunxi_nand_rnd_init(master, &part->rnd,
+ part->part.ecc ? part->part.ecc : &chip->ecc,
+ pp);
+ if (ret)
+ goto err;
+
+ part->part.rnd = &part->rnd;
+ }
return &part->part;
err:
+ if (part->part.ecc)
+ sunxi_nand_ecc_cleanup(part->part.ecc);
+
kfree(part);
return ERR_PTR(ret);
}

View file

@ -1,34 +0,0 @@
From a5ba30016f4a29f5875112169a92a28a9ba7f5c9 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Mon, 25 May 2015 11:59:03 +0200
Subject: [PATCH] mtd: nand: sunxi: Add NAND_BBT_CREATE_EMPTY to bbt_options
The ftl format used by the Allwinner Android kernels, with which most
Allwinnner devices ship, overrides the factory bad block markers, and
fills the oob data with a pattern which causes a lot of false bad block
positives, so when we first create a bbt table, start with an empty one
to avoid marking a ton of blocks as bad from the start.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/mtd/nand/sunxi_nand.c | 9 +++++++++
1 file changed, 9 insertions(+)
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1851,6 +1851,15 @@ static int sunxi_nand_chip_init(struct d
if (of_get_nand_on_flash_bbt(np))
nand->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+ /*
+ * The ftl format used by the Allwinner Android kernels overrides
+ * the factory bad block markers, and fills the oob data with a
+ * pattern which causes a lot of false bad block positives, so
+ * when we first create a bbt table, start with an empty one
+ * to avoid marking a ton of blocks as bad from the start.
+ */
+ nand->bbt_options |= NAND_BBT_CREATE_EMPTY;
+
mtd = &chip->mtd;
mtd->dev.parent = dev;
mtd->priv = nand;

View file

@ -1,102 +0,0 @@
From 00f9956384e3cf011e0d5ffd211847bf9336ec78 Mon Sep 17 00:00:00 2001
From: Michal Suchanek <hramrach@gmail.com>
Date: Tue, 26 May 2015 17:01:33 +0200
Subject: [PATCH] ARM: dts: sun4i: Add NAND controller pin definitions
Define the NAND controller pin configs.
Signed-off-by: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 80 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -774,6 +774,86 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ nand_pins_a: nand_base0@0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15", "PC16";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs0_pins_a: nand_cs@0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs1_pins_a: nand_cs@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs2_pins_a: nand_cs@2 {
+ allwinner,pins = "PC17";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs3_pins_a: nand_cs@3 {
+ allwinner,pins = "PC18";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs4_pins_a: nand_cs@4 {
+ allwinner,pins = "PC19";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs5_pins_a: nand_cs@5 {
+ allwinner,pins = "PC20";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs6_pins_a: nand_cs@6 {
+ allwinner,pins = "PC21";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs7_pins_a: nand_cs@7 {
+ allwinner,pins = "PC22";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb0_pins_a: nand_rb@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb1_pins_a: nand_rb@1 {
+ allwinner,pins = "PC7";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
timer@01c20c00 {

View file

@ -1,81 +0,0 @@
From a8ad7637cec0c2c2b1322d78b142beea4621dd23 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 26 May 2015 17:18:26 +0200
Subject: [PATCH] ARM: dts: sun5i: Add NAND controller pin definitions
Define the NAND controller pin configs.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun5i-a10s.dtsi | 14 ++++++++++++++
arch/arm/boot/dts/sun5i.dtsi | 38 ++++++++++++++++++++++++++++++++++++++
2 files changed, 52 insertions(+)
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -656,4 +656,18 @@
clocks = <&ahb_gates 28>;
};
};
+
+ nand_cs2_pins_a: nand_cs@2 {
+ allwinner,pins = "PC17";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs3_pins_a: nand_cs@3 {
+ allwinner,pins = "PC18";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -528,6 +528,44 @@
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ nand_pins_a: nand_base0@0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs0_pins_a: nand_cs@0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs1_pins_a: nand_cs@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb0_pins_a: nand_rb@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb1_pins_a: nand_rb@1 {
+ allwinner,pins = "PC7";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
timer@01c20c00 {

View file

@ -1,102 +0,0 @@
From 576701449b01fb0dfaa76bb71f2b94ab5194c1dc Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:08:15 +0200
Subject: [PATCH] ARM: dts: sun7i: Add NAND controller pin definitions
Define the NAND controller pin configs.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 80 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -978,6 +978,86 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ nand_pins_a: nand_base0@0 {
+ allwinner,pins = "PC0", "PC1", "PC2",
+ "PC5", "PC8", "PC9", "PC10",
+ "PC11", "PC12", "PC13", "PC14",
+ "PC15", "PC16";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs0_pins_a: nand_cs@0 {
+ allwinner,pins = "PC4";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs1_pins_a: nand_cs@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs2_pins_a: nand_cs@2 {
+ allwinner,pins = "PC17";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs3_pins_a: nand_cs@3 {
+ allwinner,pins = "PC18";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs4_pins_a: nand_cs@4 {
+ allwinner,pins = "PC19";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs5_pins_a: nand_cs@5 {
+ allwinner,pins = "PC20";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs6_pins_a: nand_cs@6 {
+ allwinner,pins = "PC21";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_cs7_pins_a: nand_cs@7 {
+ allwinner,pins = "PC22";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb0_pins_a: nand_rb@0 {
+ allwinner,pins = "PC6";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ nand_rb1_pins_a: nand_rb@1 {
+ allwinner,pins = "PC7";
+ allwinner,function = "nand0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
timer@01c20c00 {

View file

@ -1,33 +0,0 @@
From 9cc66234a20c6ba1611233a122f04f3b175ad2d3 Mon Sep 17 00:00:00 2001
From: Boris BREZILLON <boris.brezillon@free-electrons.com>
Date: Mon, 28 Jul 2014 14:01:22 +0200
Subject: [PATCH] ARM: dts: sun7i: Add NFC node to Allwinner A20 SoC
Add NAND Flash controller node definition to the A20 SoC.
Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -543,6 +543,17 @@
#dma-cells = <2>;
};
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <0 37 4>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb", "mod";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
spi0: spi@01c05000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c05000 0x1000>;

View file

@ -1,33 +0,0 @@
From a5bbf2ee4ca1479e4488399a45336e003e09647f Mon Sep 17 00:00:00 2001
From: Michal Suchanek <hramrach@gmail.com>
Date: Tue, 26 May 2015 17:03:41 +0200
Subject: [PATCH] ARM: dts: sun4i: Add NFC node to Allwinner A10 SoC
Add NAND Flash controller node definition to the A10 SoC.
Signed-off-by: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -428,6 +428,17 @@
#dma-cells = <2>;
};
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <37>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb", "mod";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
spi0: spi@01c05000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c05000 0x1000>;

View file

@ -1,32 +0,0 @@
From 22ef77b0ba8fa347fe4b8c4c05d0bf0d08f4c141 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 26 May 2015 18:01:50 +0200
Subject: [PATCH] ARM: dts: sun5i: Add NFC node to Allwinner A13/A10s SoC
Add NAND Flash controller node definition to the A13/a10s SoC.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun5i.dtsi | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -365,6 +365,17 @@
#dma-cells = <2>;
};
+ nfc: nand@01c03000 {
+ compatible = "allwinner,sun4i-a10-nand";
+ reg = <0x01c03000 0x1000>;
+ interrupts = <37>;
+ clocks = <&ahb_gates 13>, <&nand_clk>;
+ clock-names = "ahb", "mod";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
spi0: spi@01c05000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c05000 0x1000>;

View file

@ -1,77 +0,0 @@
From f84e215756932c495bc92c50d40d8cd6773822bb Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 26 May 2015 21:06:22 +0200
Subject: [PATCH] ARM: dts: sun5i: Enable NAND on A13 OLinuxIno board
Add a node describing the NAND controller and partitions.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun5i-a13-olinuxino.dts | 59 +++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -201,3 +201,62 @@
status = "okay";
};
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-ecc-strength = <40>;
+ nand-ecc-step-size = <1024>;
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,63 +0,0 @@
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -245,3 +245,60 @@
status = "okay";
};
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a>, <&nand_cs0_pins_a>, <&nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,76 +0,0 @@
From e9f0391c7fccd13dfc07b470775b417d18d7df3b Mon Sep 17 00:00:00 2001
From: Michal Suchanek <hramrach@gmail.com>
Date: Fri, 12 Dec 2014 19:19:12 +0100
Subject: [PATCH] ARM: dts: sun4i: Enable NAND on cubieboard
Add a node describing the NAND controller and partitions.
Signed-off-by: Michal Suchanek <hramrach@gmail.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10-cubieboard.dts | 57 ++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -215,3 +215,60 @@
regulator-max-microvolt = <3000000>;
regulator-name = "avcc";
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,65 +0,0 @@
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -189,3 +189,62 @@
status = "okay";
};
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-ecc-strength = <40>;
+ nand-ecc-step-size = <1024>;
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,65 +0,0 @@
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -194,3 +194,62 @@
status = "okay";
};
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-ecc-strength = <40>;
+ nand-ecc-step-size = <1024>;
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,65 +0,0 @@
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -210,3 +210,62 @@
status = "okay";
};
};
+&nfc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_pins_a &nand_cs0_pins_a &nand_rb0_pins_a>;
+ status = "okay";
+
+ nand@0 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0>;
+ allwinner,rb = <0>;
+
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-ecc-strength = <40>;
+ nand-ecc-step-size = <1024>;
+ nand-on-flash-bbt;
+
+ boot0@0 {
+ label = "boot0";
+ reg = /bits/ 64 <0x0 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ boot0-rescue@200000 {
+ label = "boot0-rescue";
+ reg = /bits/ 64 <0x200000 0x200000>;
+ nand-ecc-mode = "hw_syndrome";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <0x4a80>;
+ };
+
+ main@200000 {
+ label = "main";
+ reg = /bits/ 64 <0x400000 0xffc00000>;
+ nand-ecc-mode = "hw";
+ nand-rnd-mode = "hw";
+ nand-randomizer-seeds = /bits/ 16 <
+ 0x2b75 0x0bd0 0x5ca3 0x62d1 0x1c93 0x07e9 0x2162 0x3a72
+ 0x0d67 0x67f9 0x1be7 0x077d 0x032f 0x0dac 0x2716 0x2436
+ 0x7922 0x1510 0x3860 0x5287 0x480f 0x4252 0x1789 0x5a2d
+ 0x2a49 0x5e10 0x437f 0x4b4e 0x2f45 0x216e 0x5cb7 0x7130
+ 0x2a3f 0x60e4 0x4dc9 0x0ef0 0x0f52 0x1bb9 0x6211 0x7a56
+ 0x226d 0x4ea7 0x6f36 0x3692 0x38bf 0x0c62 0x05eb 0x4c55
+ 0x60f4 0x728c 0x3b6f 0x2037 0x7f69 0x0936 0x651a 0x4ceb
+ 0x6218 0x79f3 0x383f 0x18d9 0x4f05 0x5c82 0x2912 0x6f17
+ 0x6856 0x5938 0x1007 0x61ab 0x3e7f 0x57c2 0x542f 0x4f62
+ 0x7454 0x2eac 0x7739 0x42d4 0x2f90 0x435a 0x2e52 0x2064
+ 0x637c 0x66ad 0x2c90 0x0bad 0x759c 0x0029 0x0986 0x7126
+ 0x1ca7 0x1605 0x386a 0x27f5 0x1380 0x6d75 0x24c3 0x0f8e
+ 0x2b7a 0x1418 0x1fd1 0x7dc1 0x2d8e 0x43af 0x2267 0x7da3
+ 0x4e3d 0x1338 0x50db 0x454d 0x764d 0x40a3 0x42e6 0x262b
+ 0x2d2e 0x1aea 0x2e17 0x173d 0x3a6e 0x71bf 0x25f9 0x0a5d
+ 0x7c57 0x0fbe 0x46ce 0x4939 0x6b17 0x37bb 0x3e91 0x76db>;
+ };
+ };
+};
+

View file

@ -1,182 +0,0 @@
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4249,6 +4249,8 @@ static inline bool is_full_id_nand(struc
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
struct nand_flash_dev *type, const u8 *id_data, int *busw)
{
+ int mode;
+
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
@@ -4259,8 +4261,9 @@ static bool find_full_id_nand(struct mtd
chip->options |= type->options;
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
chip->ecc_step_ds = NAND_ECC_STEP(type);
- chip->onfi_timing_mode_default =
- type->onfi_timing_mode_default;
+
+ mode = type->onfi_timing_mode_default;
+ chip->sdr_timings = onfi_async_timing_mode_to_sdr_timings(mode);
*busw = type->options & NAND_BUSWIDTH_16;
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1425,7 +1425,7 @@ static int sunxi_nand_chip_init_timings(
mode = onfi_get_async_timing_mode(&chip->nand);
if (mode == ONFI_TIMING_MODE_UNKNOWN) {
- mode = chip->nand.onfi_timing_mode_default;
+ timings = chip->nand.sdr_timings;
} else {
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
@@ -1439,9 +1439,10 @@ static int sunxi_nand_chip_init_timings(
feature);
if (ret)
return ret;
+
+ timings = onfi_async_timing_mode_to_sdr_timings(mode);
}
- timings = onfi_async_timing_mode_to_sdr_timings(mode);
if (IS_ERR(timings))
return PTR_ERR(timings);
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -612,6 +612,55 @@ struct nand_buffers {
uint8_t *databuf;
};
+/*
+ * struct nand_sdr_timings - SDR NAND chip timings
+ *
+ * This struct defines the timing requirements of a SDR NAND chip.
+ * These informations can be found in every NAND datasheets and the timings
+ * meaning are described in the ONFI specifications:
+ * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
+ * Parameters)
+ *
+ * All these timings are expressed in picoseconds.
+ */
+
+struct nand_sdr_timings {
+ u32 tALH_min;
+ u32 tADL_min;
+ u32 tALS_min;
+ u32 tAR_min;
+ u32 tCEA_max;
+ u32 tCEH_min;
+ u32 tCH_min;
+ u32 tCHZ_max;
+ u32 tCLH_min;
+ u32 tCLR_min;
+ u32 tCLS_min;
+ u32 tCOH_min;
+ u32 tCS_min;
+ u32 tDH_min;
+ u32 tDS_min;
+ u32 tFEAT_max;
+ u32 tIR_min;
+ u32 tITC_max;
+ u32 tRC_min;
+ u32 tREA_max;
+ u32 tREH_min;
+ u32 tRHOH_min;
+ u32 tRHW_min;
+ u32 tRHZ_max;
+ u32 tRLOH_min;
+ u32 tRP_min;
+ u32 tRR_min;
+ u64 tRST_max;
+ u32 tWB_max;
+ u32 tWC_min;
+ u32 tWH_min;
+ u32 tWHR_min;
+ u32 tWP_min;
+ u32 tWW_min;
+};
+
/**
* struct nand_chip - NAND Private Flash Chip Data
* @IO_ADDR_R: [BOARDSPECIFIC] address to read the 8 I/O lines of the
@@ -676,11 +725,7 @@ struct nand_buffers {
* @ecc_step_ds: [INTERN] ECC step required by the @ecc_strength_ds,
* also from the datasheet. It is the recommended ECC step
* size, if known; if unknown, set to zero.
- * @onfi_timing_mode_default: [INTERN] default ONFI timing mode. This field is
- * either deduced from the datasheet if the NAND
- * chip is not ONFI compliant or set to 0 if it is
- * (an ONFI chip is always configured in mode 0
- * after a NAND reset)
+ * @sdr_timings [INTERN] Pointer to default timings for SDR NAND.
* @numchips: [INTERN] number of physical chips
* @chipsize: [INTERN] the size of one chip for multichip arrays
* @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
@@ -769,7 +814,7 @@ struct nand_chip {
uint8_t bits_per_cell;
uint16_t ecc_strength_ds;
uint16_t ecc_step_ds;
- int onfi_timing_mode_default;
+ const struct nand_sdr_timings *sdr_timings;
int badblockpos;
int badblockbits;
@@ -1156,55 +1201,6 @@ struct ofnandpart_data {
int ofnandpart_parse(struct mtd_info *master,
const struct ofnandpart_data *data);
-/*
- * struct nand_sdr_timings - SDR NAND chip timings
- *
- * This struct defines the timing requirements of a SDR NAND chip.
- * These informations can be found in every NAND datasheets and the timings
- * meaning are described in the ONFI specifications:
- * www.onfi.org/~/media/ONFI/specs/onfi_3_1_spec.pdf (chapter 4.15 Timing
- * Parameters)
- *
- * All these timings are expressed in picoseconds.
- */
-
-struct nand_sdr_timings {
- u32 tALH_min;
- u32 tADL_min;
- u32 tALS_min;
- u32 tAR_min;
- u32 tCEA_max;
- u32 tCEH_min;
- u32 tCH_min;
- u32 tCHZ_max;
- u32 tCLH_min;
- u32 tCLR_min;
- u32 tCLS_min;
- u32 tCOH_min;
- u32 tCS_min;
- u32 tDH_min;
- u32 tDS_min;
- u32 tFEAT_max;
- u32 tIR_min;
- u32 tITC_max;
- u32 tRC_min;
- u32 tREA_max;
- u32 tREH_min;
- u32 tRHOH_min;
- u32 tRHW_min;
- u32 tRHZ_max;
- u32 tRLOH_min;
- u32 tRP_min;
- u32 tRR_min;
- u64 tRST_max;
- u32 tWB_max;
- u32 tWC_min;
- u32 tWH_min;
- u32 tWHR_min;
- u32 tWP_min;
- u32 tWW_min;
-};
-
/* get timing characteristics from ONFI timing mode. */
const struct nand_sdr_timings *onfi_async_timing_mode_to_sdr_timings(int mode);
#endif /* __LINUX_MTD_NAND_H */

View file

@ -1,28 +0,0 @@
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4262,8 +4262,13 @@ static bool find_full_id_nand(struct mtd
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
chip->ecc_step_ds = NAND_ECC_STEP(type);
- mode = type->onfi_timing_mode_default;
- chip->sdr_timings = onfi_async_timing_mode_to_sdr_timings(mode);
+ if (type->custom_sdr_timing) {
+ chip->sdr_timings = type->custom_sdr_timing;
+ } else {
+ mode = type->onfi_timing_mode_default;
+ chip->sdr_timings =
+ onfi_async_timing_mode_to_sdr_timings(mode);
+ }
*busw = type->options & NAND_BUSWIDTH_16;
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -988,6 +988,7 @@ struct nand_flash_dev {
uint16_t step_ds;
} ecc;
int onfi_timing_mode_default;
+ const struct nand_sdr_timings *custom_sdr_timing;
};
/**

View file

@ -1,63 +0,0 @@
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -19,6 +19,49 @@
#define SP_OPTIONS16 (SP_OPTIONS | NAND_BUSWIDTH_16)
/*
+ * Hynix H27UBG8T2BTR timings
+ * This chip has an exceptionally large tADL, which results in only supporting
+ * ONFI timing mode 0. Using these timings, the clock can be raised from
+ * 12.5MHz to 50MHz.
+ */
+const struct nand_sdr_timings hynix_h27ubg8t2btr_sdr_timing = {
+ .tADL_min = 200000,
+ .tALH_min = 5000,
+ .tALS_min = 10000,
+ .tAR_min = 10000,
+ .tCEA_max = 100000,
+ .tCEH_min = 20000,
+ .tCH_min = 5000,
+ .tCHZ_max = 50000,
+ .tCLH_min = 5000,
+ .tCLR_min = 10000,
+ .tCLS_min = 10000,
+ .tCOH_min = 15000,
+ .tCS_min = 20000,
+ .tDH_min = 5000,
+ .tDS_min = 10000,
+ .tFEAT_max = 1000000,
+ .tIR_min = 0,
+ .tITC_max = 1000000,
+ .tRC_min = 20000,
+ .tREA_max = 16000,
+ .tREH_min = 8000,
+ .tRHOH_min = 15000,
+ .tRHW_min = 100000,
+ .tRHZ_max = 100000,
+ .tRLOH_min = 5000,
+ .tRP_min = 10000,
+ .tRST_max = 500000000,
+ .tWB_max = 100000,
+ .tRR_min = 20000,
+ .tWC_min = 20000,
+ .tWH_min = 10000,
+ .tWHR_min = 80000,
+ .tWP_min = 8000,
+ .tWW_min = 100000,
+};
+
+/*
* The chip ID list:
* name, device ID, page size, chip size in MiB, eraseblock size, options
*
@@ -50,6 +93,10 @@ struct nand_flash_dev nand_flash_ids[] =
{ .id = {0xad, 0xde, 0x94, 0xda, 0x74, 0xc4} },
SZ_8K, SZ_8K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
4 },
+ {"H27UBG8T2BTR-BC 64G 3.3V 8-bit",
+ { .id = {0xad, 0xd7, 0x94, 0xda, 0x74, 0xc3} },
+ SZ_8K, SZ_4K, SZ_2M, 0, 6, 640, NAND_ECC_INFO(40, SZ_1K),
+ 0, &hynix_h27ubg8t2btr_sdr_timing },
LEGACY_ID_NAND("NAND 4MiB 5V 8-bit", 0x6B, 4, SZ_8K, SP_OPTIONS),
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),

View file

@ -1,78 +0,0 @@
From b1488f1a55da6a297ac4e8e9140922f35b7583c5 Mon Sep 17 00:00:00 2001
From: Boris Brezillon <boris.brezillon@free-electrons.com>
Date: Mon, 15 Jun 2015 11:09:58 +0200
Subject: [PATCH] nand: sunxi: fix write to USER_DATA reg
The USER_DATA register cannot be updated with readb on A13 SoCs, thus
triggering a bug when using memcpy_toio on this register.
Use writel (plus a temporary variable to old the USER_DATA value) to
address that problem.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/mtd/nand/sunxi_nand.c | 38 +++++++++++++++++++++-----------------
1 file changed, 21 insertions(+), 17 deletions(-)
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -908,7 +908,7 @@ static int sunxi_nfc_hw_ecc_write_page(s
for (i = 0; i < ecc->steps; i++) {
bool rndactiv = false;
- u8 oob_buf[4];
+ u32 user_data;
if (i)
chip->cmdfunc(mtd, NAND_CMD_RNDIN, i * ecc->size, -1);
@@ -919,15 +919,13 @@ static int sunxi_nfc_hw_ecc_write_page(s
offset = layout->eccpos[i * ecc->bytes] - 4 + mtd->writesize;
/* Fill OOB data in */
- if (!oob_required)
- memset(oob_buf, 0xff, 4);
- else
- memcpy(oob_buf,
- chip->oob_poi + layout->oobfree[i].offset,
- 4);
-
-
- memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
+ if (!oob_required) {
+ user_data = 0xffffffff;
+ } else {
+ memcpy(&user_data,
+ chip->oob_poi + layout->oobfree[i].offset, 4);
+ user_data = le32_to_cpu(user_data);
+ }
if (i) {
cnt = ecc->bytes + 4;
@@ -946,12 +944,16 @@ static int sunxi_nfc_hw_ecc_write_page(s
if (rndactiv) {
/* pre randomize to generate FF patterns on the NAND */
if (!i) {
+ u8 oob_tmp[2];
u16 state = rnd->subseeds[rnd->page % rnd->nseeds];
+ oob_tmp[0] = user_data;
+ oob_tmp[1] = user_data >> 8;
state = sunxi_nfc_hwrnd_single_step(state, 15);
- oob_buf[0] ^= state;
+ oob_tmp[0] ^= state;
state = sunxi_nfc_hwrnd_step(rnd, state, 1);
- oob_buf[1] ^= state;
- memcpy_toio(nfc->regs + NFC_REG_USER_DATA_BASE, oob_buf, 4);
+ oob_tmp[1] ^= state;
+ user_data &= ~0xffff;
+ user_data |= oob_tmp[0] | (oob_tmp[1] << 8);
}
tmp = readl(nfc->regs + NFC_REG_ECC_CTL);
tmp &= ~(NFC_RANDOM_DIRECTION | NFC_ECC_EXCEPTION);
@@ -959,6 +961,8 @@ static int sunxi_nfc_hw_ecc_write_page(s
writel(tmp, nfc->regs + NFC_REG_ECC_CTL);
}
+ writel(user_data, nfc->regs + NFC_REG_USER_DATA_BASE);
+
chip->cmdfunc(mtd, NAND_CMD_RNDIN, offset, -1);
ret = sunxi_nfc_wait_cmd_fifo_empty(nfc);

View file

@ -1,86 +0,0 @@
From 8a7013f47196abed7e6a40e93d1de1639cd46228 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 10 Jul 2015 17:03:03 +0200
Subject: [PATCH] mmc: sunxi: Don't start commands while the card is busy
Some sdio wifi modules have not been working reliable with the sunxi-mmc
host code. This turns out to be caused by it starting new commands while
the card signals that it is still busy processing a previous command.
This commit fixes this, thereby fixing the wifi reliability issues on
the Cubietruck and other sunxi boards using sdio wifi.
Reported-by: Eugene K <sigintmailru@gmail.com>
Suggested-by: Eugene K <sigintmailru@gmail.com>
Cc: Eugene K <sigintmailru@gmail.com>
Cc: Arend van Spriel <arend@broadcom.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
Changes in v2:
-Properly accredit Eugene K for coming up with the fix for this
---
drivers/mmc/host/sunxi-mmc.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -289,6 +289,24 @@ static int sunxi_mmc_init_host(struct mm
return 0;
}
+/* Wait for card to report ready before starting a new cmd */
+static int sunxi_mmc_wait_card_ready(struct sunxi_mmc_host *host)
+{
+ unsigned long expire = jiffies + msecs_to_jiffies(500);
+ u32 rval;
+
+ do {
+ rval = mmc_readl(host, REG_STAS);
+ } while (time_before(jiffies, expire) && (rval & SDXC_CARD_DATA_BUSY));
+
+ if (rval & SDXC_CARD_DATA_BUSY) {
+ dev_err(mmc_dev(host->mmc), "Error R1 ready timeout\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
struct mmc_data *data)
{
@@ -383,6 +401,8 @@ static void sunxi_mmc_send_manual_stop(s
u32 arg, cmd_val, ri;
unsigned long expire = jiffies + msecs_to_jiffies(1000);
+ sunxi_mmc_wait_card_ready(host);
+
cmd_val = SDXC_START | SDXC_RESP_EXPIRE |
SDXC_STOP_ABORT_CMD | SDXC_CHECK_RESPONSE_CRC;
@@ -597,6 +617,11 @@ static int sunxi_mmc_oclk_onoff(struct s
{
unsigned long expire = jiffies + msecs_to_jiffies(250);
u32 rval;
+ int ret;
+
+ ret = sunxi_mmc_wait_card_ready(host);
+ if (ret)
+ return ret;
rval = mmc_readl(host, REG_CLKCR);
rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON);
@@ -784,6 +809,13 @@ static void sunxi_mmc_request(struct mmc
mmc_request_done(mmc, mrq);
return;
}
+
+ ret = sunxi_mmc_wait_card_ready(host);
+ if (ret) {
+ mrq->cmd->error = ret;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
if (data) {
ret = sunxi_mmc_map_dma(host, data);

View file

@ -1,46 +0,0 @@
From 14a882df14a5ae859b245bc708ce3fce47a91594 Mon Sep 17 00:00:00 2001
From: Jens Kuske <jenskuske@gmail.com>
Date: Fri, 15 May 2015 18:38:55 +0200
Subject: ARM: sunxi: Introduce Allwinner H3 support
The Allwinner H3 is a quad-core Cortex-A7-based SoC. It is very similar
to other sun8i family SoCs like the A23.
Signed-off-by: Jens Kuske <jenskuske@gmail.com>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
--- a/Documentation/devicetree/bindings/arm/sunxi.txt
+++ b/Documentation/devicetree/bindings/arm/sunxi.txt
@@ -9,4 +9,5 @@ using one of the following compatible st
allwinner,sun6i-a31
allwinner,sun7i-a20
allwinner,sun8i-a23
+ allwinner,sun8i-h3
allwinner,sun9i-a80
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -35,7 +35,7 @@ config MACH_SUN7I
select SUN5I_HSTIMER
config MACH_SUN8I
- bool "Allwinner A23 (sun8i) SoCs support"
+ bool "Allwinner sun8i Family SoCs support"
default ARCH_SUNXI
select ARM_GIC
select MFD_SUN6I_PRCM
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -67,10 +67,12 @@ MACHINE_END
static const char * const sun8i_board_dt_compat[] = {
"allwinner,sun8i-a23",
+ "allwinner,sun8i-h3",
NULL,
};
-DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
+DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i Family")
+ .init_time = sun6i_timer_init,
.dt_compat = sun8i_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END

View file

@ -1,38 +0,0 @@
--- a/Documentation/devicetree/bindings/dma/sun6i-dma.txt
+++ b/Documentation/devicetree/bindings/dma/sun6i-dma.txt
@@ -4,7 +4,10 @@ This driver follows the generic DMA bind
Required properties:
-- compatible: Must be "allwinner,sun6i-a31-dma" or "allwinner,sun8i-a23-dma"
+- compatible: Must be one of
+ "allwinner,sun6i-a31-dma"
+ "allwinner,sun8i-a23-dma"
+ "allwinner,sun8i-h3-dma"
- reg: Should contain the registers base address and length
- interrupts: Should contain a reference to the interrupt used by this device
- clocks: Should contain a reference to the parent AHB clock
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -891,9 +891,21 @@ static struct sun6i_dma_config sun8i_a23
.nr_max_vchans = 37,
};
+/*
+ * The H3 has 12 physical channels, a maximum DRQ port id of 27,
+ * and a total of 34 usable source and destination endpoints.
+ */
+
+static struct sun6i_dma_config sun8i_h3_dma_cfg = {
+ .nr_max_channels = 12,
+ .nr_max_requests = 27,
+ .nr_max_vchans = 34,
+};
+
static const struct of_device_id sun6i_dma_match[] = {
{ .compatible = "allwinner,sun6i-a31-dma", .data = &sun6i_a31_dma_cfg },
{ .compatible = "allwinner,sun8i-a23-dma", .data = &sun8i_a23_dma_cfg },
+ { .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg },
{ /* sentinel */ }
};

View file

@ -1,282 +0,0 @@
From ea6871c5b3a934d0bfe08082e95c3b952f93ef39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:48:35 -0300
Subject: [PATCH] clk: sunxi: PLL2 support for sun4i, sun5i and sun7i
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This patch adds support for PLL2 and derivates on A10 revision B and
higher, as well as on sun5i and sun7i SoCs. As this PLL is only used for
audio and requires good accuracy, we only support two known good rates.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-a10-pll2.c | 249 +++++++++++++++++++++++++++++++++++++++
2 files changed, 250 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-a10-pll2.c
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -4,6 +4,7 @@
obj-y += clk-sunxi.o clk-factors.o
obj-y += clk-a10-hosc.o
+obj-y += clk-a10-pll2.o
obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
obj-y += clk-sun8i-mbus.o
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-pll2.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * 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-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#define SUN4I_PLL2_ENABLE 31
+#define SUN4I_PLL2_POST_DIV 26
+#define SUN4I_PLL2_POST_DIV_MASK 0xF
+#define SUN4I_PLL2_N 8
+#define SUN4I_PLL2_N_MASK 0x7F
+#define SUN4I_PLL2_PRE_DIV 0
+#define SUN4I_PLL2_PRE_DIV_MASK 0x1F
+
+#define SUN4I_PLL2_OUTPUTS 4
+
+struct sun4i_pll2_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+static inline struct sun4i_pll2_clk *to_sun4i_pll2_clk(struct clk_hw *hw)
+{
+ return container_of(hw, struct sun4i_pll2_clk, hw);
+}
+
+static unsigned long sun4i_pll2_1x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
+ int n, prediv, postdiv;
+
+ u32 val = readl(clk->reg);
+ n = (val >> SUN4I_PLL2_N) & SUN4I_PLL2_N_MASK;
+ prediv = (val >> SUN4I_PLL2_PRE_DIV) & SUN4I_PLL2_PRE_DIV_MASK;
+ postdiv = (val >> SUN4I_PLL2_POST_DIV) & SUN4I_PLL2_POST_DIV_MASK;
+
+ /* 0 is a special case and means 1 */
+ if (n == 0)
+ n = 1;
+ if (prediv == 0)
+ prediv = 1;
+ if (postdiv == 0)
+ postdiv = 1;
+
+ return ((parent_rate * n) / prediv) / postdiv;
+}
+
+static unsigned long sun4i_pll2_8x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
+ int n, prediv;
+
+ u32 val = readl(clk->reg);
+ n = (val >> SUN4I_PLL2_N) & SUN4I_PLL2_N_MASK;
+ prediv = (val >> SUN4I_PLL2_PRE_DIV) & SUN4I_PLL2_PRE_DIV_MASK;
+
+ /* 0 is a special case and means 1 */
+ if (n == 0)
+ n = 1;
+ if (prediv == 0)
+ prediv = 1;
+
+ return ((parent_rate * 2 * n) / prediv);
+}
+
+static unsigned long sun4i_pll2_4x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return sun4i_pll2_8x_recalc_rate(hw, parent_rate / 2);
+}
+
+static unsigned long sun4i_pll2_2x_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return sun4i_pll2_8x_recalc_rate(hw, parent_rate / 4);
+}
+
+static long sun4i_pll2_1x_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /*
+ * There is only two interesting rates for the audio PLL, the
+ * rest isn't really usable due to accuracy concerns. Therefore,
+ * we specifically round to those rates here
+ */
+ if (rate < 22579200)
+ return -EINVAL;
+
+ if (rate >= 22579200 && rate < 24576000)
+ return 22579200;
+
+ return 24576000;
+}
+
+static long sun4i_pll2_8x_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /*
+ * We should account for the postdiv that we're undoing on PLL2x8,
+ * which is always 4 in the usable configurations. The division
+ * by two is done because PLL2x8 also doubles the rate
+ */
+ *parent_rate = (rate * 4) / 2;
+
+ return rate;
+}
+
+static long sun4i_pll2_4x_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /* PLL2x4 * 2 = PLL2x8 */
+ return sun4i_pll2_8x_round_rate(hw, rate * 2, parent_rate);
+}
+
+static long sun4i_pll2_2x_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /* PLL2x2 * 4 = PLL2x8 */
+ return sun4i_pll2_8x_round_rate(hw, rate * 4, parent_rate);
+}
+
+static int sun4i_pll2_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun4i_pll2_clk *clk = to_sun4i_pll2_clk(hw);
+ u32 val = readl(clk->reg);
+
+ val &= ~(SUN4I_PLL2_N_MASK << SUN4I_PLL2_N);
+ val &= ~(SUN4I_PLL2_PRE_DIV_MASK << SUN4I_PLL2_PRE_DIV);
+ val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV);
+
+ val |= (21 << SUN4I_PLL2_PRE_DIV) | (4 << SUN4I_PLL2_POST_DIV);
+
+ if (rate == 22579200)
+ val |= (79 << SUN4I_PLL2_N);
+ else if (rate == 24576000)
+ val |= (86 << SUN4I_PLL2_N);
+ else
+ return -EINVAL;
+
+ writel(val, clk->reg);
+
+ return 0;
+}
+
+static struct clk_ops sun4i_pll2_ops_1x = {
+ .recalc_rate = sun4i_pll2_1x_recalc_rate,
+ .round_rate = sun4i_pll2_1x_round_rate,
+ .set_rate = sun4i_pll2_set_rate,
+};
+
+static struct clk_ops sun4i_pll2_ops_2x = {
+ .recalc_rate = sun4i_pll2_2x_recalc_rate,
+ .round_rate = sun4i_pll2_2x_round_rate,
+};
+
+static struct clk_ops sun4i_pll2_ops_4x = {
+ .recalc_rate = sun4i_pll2_4x_recalc_rate,
+ .round_rate = sun4i_pll2_4x_round_rate,
+};
+
+static struct clk_ops sun4i_pll2_ops_8x = {
+ .recalc_rate = sun4i_pll2_8x_recalc_rate,
+ .round_rate = sun4i_pll2_8x_round_rate,
+};
+
+static void __init sun4i_pll2_setup(struct device_node *np)
+{
+ const char *clk_name = np->name, *parent;
+ struct clk_onecell_data *clk_data;
+ struct sun4i_pll2_clk *pll2;
+ struct clk_gate *gate;
+ struct clk **clks;
+ void __iomem *reg;
+
+ pll2 = kzalloc(sizeof(*pll2), GFP_KERNEL);
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+ clks = kcalloc(SUN4I_PLL2_OUTPUTS, sizeof(struct clk *), GFP_KERNEL);
+ if (!pll2 || !gate || !clk_data || !clks)
+ goto free_mem;
+
+ reg = of_iomap(np, 0);
+ parent = of_clk_get_parent_name(np, 0);
+ of_property_read_string_index(np, "clock-output-names", 0, &clk_name);
+
+ pll2->reg = reg;
+ gate->reg = reg;
+ gate->bit_idx = SUN4I_PLL2_ENABLE;
+
+ /* PLL2, also known as PLL2x1 */
+ of_property_read_string_index(np, "clock-output-names", 0, &clk_name);
+ clks[0] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
+ &pll2->hw, &sun4i_pll2_ops_1x,
+ &gate->hw, &clk_gate_ops, 0);
+ WARN_ON(IS_ERR(clks[0]));
+ parent = clk_name;
+
+ /* PLL2x2, 1/4 the rate of PLL2x8 */
+ of_property_read_string_index(np, "clock-output-names", 1, &clk_name);
+ clks[1] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
+ &pll2->hw, &sun4i_pll2_ops_2x,
+ NULL, NULL, CLK_SET_RATE_PARENT);
+ WARN_ON(IS_ERR(clks[1]));
+
+ /* PLL2x4, 1/2 the rate of PLL2x8 */
+ of_property_read_string_index(np, "clock-output-names", 2, &clk_name);
+ clks[2] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
+ &pll2->hw, &sun4i_pll2_ops_4x,
+ NULL, NULL, CLK_SET_RATE_PARENT);
+ WARN_ON(IS_ERR(clks[2]));
+
+ /* PLL2x8, double of PLL2 without the post divisor */
+ of_property_read_string_index(np, "clock-output-names", 3, &clk_name);
+ clks[3] = clk_register_composite(NULL, clk_name, &parent, 1, NULL, NULL,
+ &pll2->hw, &sun4i_pll2_ops_8x,
+ NULL, NULL, CLK_SET_RATE_PARENT);
+ WARN_ON(IS_ERR(clks[3]));
+
+ clk_data->clks = clks;
+ clk_data->clk_num = SUN4I_PLL2_OUTPUTS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+
+ return;
+
+free_mem:
+ kfree(pll2);
+ kfree(gate);
+ kfree(clk_data);
+ kfree(clks);
+}
+CLK_OF_DECLARE(sun4i_pll2, "allwinner,sun4i-a10-b-pll2-clk", sun4i_pll2_setup);

View file

@ -1,73 +0,0 @@
From 9b95732096c11d84bd0082aed0d575d8c09e3ab6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:49:37 -0300
Subject: [PATCH] clk: sunxi: codec clock support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The codec clock on sun4i, sun5i and sun7i is a simple gate with PLL2 as
parent.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-a10-codec.c | 41 +++++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-a10-codec.c
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -3,6 +3,7 @@
#
obj-y += clk-sunxi.o clk-factors.o
+obj-y += clk-a10-codec.o
obj-y += clk-a10-hosc.o
obj-y += clk-a10-pll2.o
obj-y += clk-a20-gmac.o
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-codec.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * 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-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#define SUN4I_CODEC_GATE 31
+
+static void __init sun4i_codec_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name, *parent_name;
+ void __iomem *reg;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ parent_name = of_clk_get_parent_name(node, 0);
+ reg = of_iomap(node, 0);
+
+ clk = clk_register_gate(NULL, clk_name, parent_name,
+ CLK_SET_RATE_PARENT, reg,
+ SUN4I_CODEC_GATE, 0, NULL);
+
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(sun4i_codec, "allwinner,sun4i-a10-codec-clk", sun4i_codec_clk_setup);

View file

@ -1,102 +0,0 @@
From 7fbbca069587b7f467e76f583ad640977de1a4ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:28:02 -0300
Subject: [PATCH] clk: sunxi: mod1 clock support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The module 1 type of clocks consist of a gate and a mux and are used on
the audio blocks to mux and gate the PLL2 outputs for AC97, IIS or
SPDIF. This commit adds support for them on the sunxi clock driver.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk-a10-mod1.c | 69 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+)
create mode 100644 drivers/clk/sunxi/clk-a10-mod1.c
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -5,6 +5,7 @@
obj-y += clk-sunxi.o clk-factors.o
obj-y += clk-a10-codec.o
obj-y += clk-a10-hosc.o
+obj-y += clk-a10-mod1.o
obj-y += clk-a10-pll2.o
obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
--- /dev/null
+++ b/drivers/clk/sunxi/clk-a10-mod1.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013 Emilio López
+ *
+ * Emilio López <emilio@elopez.com.ar>
+ *
+ * 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-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+static DEFINE_SPINLOCK(mod1_lock);
+
+#define SUN4I_MOD1_ENABLE 31
+#define SUN4I_MOD1_MUX 16
+#define SUN4I_MOD1_MUX_WIDTH 2
+#define SUN4I_MOD1_MAX_PARENTS 4
+
+static void __init sun4i_mod1_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct clk_mux *mux;
+ struct clk_gate *gate;
+ const char *parents[4];
+ const char *clk_name = node->name;
+ void __iomem *reg;
+ int i = 0;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!mux || !gate) {
+ kfree(mux);
+ kfree(gate);
+ return;
+ }
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+ reg = of_iomap(node, 0);
+
+ while (i < SUN4I_MOD1_MAX_PARENTS &&
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ gate->reg = reg;
+ gate->bit_idx = SUN4I_MOD1_ENABLE;
+ gate->lock = &mod1_lock;
+ mux->reg = reg;
+ mux->shift = SUN4I_MOD1_MUX;
+ mux->mask = BIT(SUN4I_MOD1_MUX_WIDTH) - 1;
+ mux->lock = &mod1_lock;
+
+ clk = clk_register_composite(NULL, clk_name, parents, i,
+ &mux->hw, &clk_mux_ops,
+ NULL, NULL,
+ &gate->hw, &clk_gate_ops, 0);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(sun4i_mod1, "allwinner,sun4i-a10-mod1-clk", sun4i_mod1_clk_setup);

View file

@ -1,70 +0,0 @@
From 32bb743195e1e48c48fc5cefd7c6ecdce56046a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:58:44 -0300
Subject: [PATCH] ARM: sunxi: Add PLL2 support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This commit adds the PLL2 definition to the sun4i, sun5i and sun7i
device trees. PLL2 is used to clock audio devices.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++
arch/arm/boot/dts/sun5i.dtsi | 8 ++++++++
arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
3 files changed, 24 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -162,6 +162,14 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-b-pll2-clk";
+ reg = <0x01c20008 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2", "pll2x2", "pll2x4", "pll2x8";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-pll1-clk";
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -136,6 +136,14 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-b-pll2-clk";
+ reg = <0x01c20008 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2", "pll2x2", "pll2x4", "pll2x8";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-pll1-clk";
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -203,6 +203,14 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-b-pll2-clk";
+ reg = <0x01c20008 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2", "pll2x2", "pll2x4", "pll2x8";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun7i-a20-pll4-clk";

View file

@ -1,70 +0,0 @@
From b404f3daca1807a74e07180397c6e85046b7a5cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:58:58 -0300
Subject: [PATCH] ARM: sunxi: Add codec clock support
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This commit adds the codec clock definition to the sun4i, sun5i and
sun7i device trees. The codec clock is used in the analog codec block.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++
arch/arm/boot/dts/sun5i.dtsi | 8 ++++++++
arch/arm/boot/dts/sun7i-a20.dtsi | 8 ++++++++
3 files changed, 24 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -420,6 +420,14 @@
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
clock-output-names = "spi3";
};
+
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 0>;
+ clock-output-names = "codec";
+ };
};
soc@01c00000 {
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -350,6 +350,14 @@
clock-output-names = "usb_ohci0", "usb_phy";
};
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 0>;
+ clock-output-names = "codec";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun5i-a13-mbus-clk";
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -464,6 +464,14 @@
clock-output-names = "spi3";
};
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 0>;
+ clock-output-names = "codec";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun5i-a13-mbus-clk";

View file

@ -1,72 +0,0 @@
From e9051f5dbc26e78f91cf23ca79ae4c8471119667 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Fri, 18 Jul 2014 15:26:08 -0300
Subject: [PATCH] ARM: sun7i: Add mod1 clock nodes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This commit adds all the mod1 clocks available on A20 to its device
tree. This list was created by looking at the A20 user manual.
Not-signed-off-by: Emilio López <emilio@elopez.com.ar>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -447,6 +447,29 @@
clock-output-names = "ir1";
};
+ iis0_clk: clk@01c200b8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200b8 0x4>;
+ clocks = <&pll2 0>, <&pll2 1>, <&pll2 2>, <&pll2 3>;
+ clock-output-names = "iis0";
+ };
+
+ ac97_clk: clk@01c200bc {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200bc 0x4>;
+ clocks = <&pll2 3>, <&pll2 2>, <&pll2 1>, <&pll2 0>;
+ clock-output-names = "ac97";
+ };
+
+ spdif_clk: clk@01c200c0 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200c0 0x4>;
+ clocks = <&pll2 0>, <&pll2 1>, <&pll2 2>, <&pll2 3>;
+ clock-output-names = "spdif";
+ };
usb_clk: clk@01c200cc {
#clock-cells = <1>;
#reset-cells = <1>;
@@ -464,6 +487,22 @@
clock-output-names = "spi3";
};
+ iis1_clk: clk@01c200d8 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200d8 0x4>;
+ clocks = <&pll2 0>, <&pll2 1>, <&pll2 2>, <&pll2 3>;
+ clock-output-names = "iis1";
+ };
+
+ iis2_clk: clk@01c200dc {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod1-clk";
+ reg = <0x01c200dc 0x4>;
+ clocks = <&pll2 0>, <&pll2 1>, <&pll2 2>, <&pll2 3>;
+ clock-output-names = "iis2";
+ };
+
codec_clk: clk@01c20140 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-codec-clk";

View file

@ -1,21 +0,0 @@
From ed5c1e047de4e8a849cd0517590d5c1bbf3247fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <elopez93@gmail.com>
Date: Sun, 17 Aug 2014 19:25:53 -0300
Subject: [PATCH] resort pll parents for audio
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -467,7 +467,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod1-clk";
reg = <0x01c200c0 0x4>;
- clocks = <&pll2 0>, <&pll2 1>, <&pll2 2>, <&pll2 3>;
+ clocks = <&pll2 3>, <&pll2 2>, <&pll2 1>, <&pll2 0>;
clock-output-names = "spdif";
};
usb_clk: clk@01c200cc {

View file

@ -1,865 +0,0 @@
From 97dcb50623db12f13c9c9a8b68dca61901b7f030 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <emilio@elopez.com.ar>
Date: Mon, 14 Jul 2014 20:25:23 -0300
Subject: [PATCH] ASoC: sunxi: add support for the on-chip codec on early
Allwinner SoCs
The sun4i, sun5i and sun7i SoC families have a built-in codec, capable
of both audio capture and playback. This memory-mapped device can be fed
with audio data via the Allwinner DMA controller.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
sound/soc/Kconfig | 1 +
sound/soc/Makefile | 1 +
sound/soc/sunxi/Kconfig | 10 +
sound/soc/sunxi/Makefile | 2 +
sound/soc/sunxi/sunxi-codec.c | 802 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 816 insertions(+)
create mode 100644 sound/soc/sunxi/Kconfig
create mode 100644 sound/soc/sunxi/Makefile
create mode 100644 sound/soc/sunxi/sunxi-codec.c
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -53,6 +53,7 @@ source "sound/soc/samsung/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/sirf/Kconfig"
source "sound/soc/spear/Kconfig"
+source "sound/soc/sunxi/Kconfig"
source "sound/soc/tegra/Kconfig"
source "sound/soc/txx9/Kconfig"
source "sound/soc/ux500/Kconfig"
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_SND_SOC) += samsung/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += sirf/
obj-$(CONFIG_SND_SOC) += spear/
+obj-$(CONFIG_SND_SOC) += sunxi/
obj-$(CONFIG_SND_SOC) += tegra/
obj-$(CONFIG_SND_SOC) += txx9/
obj-$(CONFIG_SND_SOC) += ux500/
--- /dev/null
+++ b/sound/soc/sunxi/Kconfig
@@ -0,0 +1,10 @@
+menu "SoC Audio support for Allwinner SoCs"
+ depends on ARCH_SUNXI
+
+config SND_SUNXI_SOC_CODEC
+ tristate "APB on-chip sun4i/sun5i/sun7i CODEC"
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ select REGMAP_MMIO
+ default y
+
+endmenu
--- /dev/null
+++ b/sound/soc/sunxi/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_SND_SUNXI_SOC_CODEC) += sunxi-codec.o
+
--- /dev/null
+++ b/sound/soc/sunxi/sunxi-codec.c
@@ -0,0 +1,802 @@
+/*
+ * Copyright 2014 Emilio López <emilio@elopez.com.ar>
+ * Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * Based on the Allwinner SDK driver, released under the GPL.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/dmaengine_pcm.h>
+
+/* Codec DAC register offsets and bit fields */
+#define SUNXI_DAC_DPC (0x00)
+#define SUNXI_DAC_DPC_EN_DA (31)
+#define SUNXI_DAC_DPC_DVOL (12)
+#define SUNXI_DAC_FIFOC (0x04)
+#define SUNXI_DAC_FIFOC_DAC_FS (29)
+#define SUNXI_DAC_FIFOC_FIR_VERSION (28)
+#define SUNXI_DAC_FIFOC_SEND_LASAT (26)
+#define SUNXI_DAC_FIFOC_TX_FIFO_MODE (24)
+#define SUNXI_DAC_FIFOC_DRQ_CLR_CNT (21)
+#define SUNXI_DAC_FIFOC_TX_TRIG_LEVEL (8)
+#define SUNXI_DAC_FIFOC_MONO_EN (6)
+#define SUNXI_DAC_FIFOC_TX_SAMPLE_BITS (5)
+#define SUNXI_DAC_FIFOC_DAC_DRQ_EN (4)
+#define SUNXI_DAC_FIFOC_FIFO_FLUSH (0)
+#define SUNXI_DAC_FIFOS (0x08)
+#define SUNXI_DAC_TXDATA (0x0c)
+#define SUNXI_DAC_ACTL (0x10)
+#define SUNXI_DAC_ACTL_DACAENR (31)
+#define SUNXI_DAC_ACTL_DACAENL (30)
+#define SUNXI_DAC_ACTL_MIXEN (29)
+#define SUNXI_DAC_ACTL_LDACLMIXS (15)
+#define SUNXI_DAC_ACTL_RDACRMIXS (14)
+#define SUNXI_DAC_ACTL_LDACRMIXS (13)
+#define SUNXI_DAC_ACTL_DACPAS (8)
+#define SUNXI_DAC_ACTL_MIXPAS (7)
+#define SUNXI_DAC_ACTL_PA_MUTE (6)
+#define SUNXI_DAC_ACTL_PA_VOL (0)
+#define SUNXI_DAC_TUNE (0x14)
+#define SUNXI_DAC_DEBUG (0x18)
+
+/* Codec ADC register offsets and bit fields */
+#define SUNXI_ADC_FIFOC (0x1c)
+#define SUNXI_ADC_FIFOC_EN_AD (28)
+#define SUNXI_ADC_FIFOC_RX_FIFO_MODE (24)
+#define SUNXI_ADC_FIFOC_RX_TRIG_LEVEL (8)
+#define SUNXI_ADC_FIFOC_MONO_EN (7)
+#define SUNXI_ADC_FIFOC_RX_SAMPLE_BITS (6)
+#define SUNXI_ADC_FIFOC_ADC_DRQ_EN (4)
+#define SUNXI_ADC_FIFOC_FIFO_FLUSH (0)
+#define SUNXI_ADC_FIFOS (0x20)
+#define SUNXI_ADC_RXDATA (0x24)
+#define SUNXI_ADC_ACTL (0x28)
+#define SUNXI_ADC_ACTL_ADCREN (31)
+#define SUNXI_ADC_ACTL_ADCLEN (30)
+#define SUNXI_ADC_ACTL_PREG1EN (29)
+#define SUNXI_ADC_ACTL_PREG2EN (28)
+#define SUNXI_ADC_ACTL_VMICEN (27)
+#define SUNXI_ADC_ACTL_VADCG (20)
+#define SUNXI_ADC_ACTL_ADCIS (17)
+#define SUNXI_ADC_ACTL_PA_EN (4)
+#define SUNXI_ADC_ACTL_DDE (3)
+#define SUNXI_ADC_DEBUG (0x2c)
+
+/* Other various ADC registers */
+#define SUNXI_DAC_TXCNT (0x30)
+#define SUNXI_ADC_RXCNT (0x34)
+#define SUNXI_AC_SYS_VERI (0x38)
+#define SUNXI_AC_MIC_PHONE_CAL (0x3c)
+
+/* Supported SoC families - used for quirks */
+enum sunxi_soc_family {
+ SUN4IA, /* A10 SoC - revision A */
+ SUN4I, /* A10 SoC - later revisions */
+ SUN5I, /* A10S/A13 SoCs */
+ SUN7I, /* A20 SoC */
+};
+
+struct sunxi_priv {
+ struct regmap *regmap;
+ struct clk *clk_apb, *clk_module;
+
+ enum sunxi_soc_family revision;
+
+ struct snd_dmaengine_dai_dma_data playback_dma_data;
+ struct snd_dmaengine_dai_dma_data capture_dma_data;
+};
+
+static void sunxi_codec_play_start(struct sunxi_priv *priv)
+{
+ /* TODO: see if we need to drive PA GPIO high */
+
+ /* flush TX FIFO */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_FIFO_FLUSH, 0x1 << SUNXI_DAC_FIFOC_FIFO_FLUSH);
+
+ /* enable DAC DRQ */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_DAC_DRQ_EN, 0x1 << SUNXI_DAC_FIFOC_DAC_DRQ_EN);
+}
+
+static void sunxi_codec_play_stop(struct sunxi_priv *priv)
+{
+ /* TODO: see if we need to drive PA GPIO low */
+
+ /* disable DAC DRQ */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_DAC_DRQ_EN, 0x0 << SUNXI_DAC_FIFOC_DAC_DRQ_EN);
+}
+
+static void sunxi_codec_capture_start(struct sunxi_priv *priv)
+{
+ /* TODO: see if we need to drive PA GPIO high */
+
+ /* enable ADC DRQ */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_ADC_DRQ_EN, 0x1 << SUNXI_ADC_FIFOC_ADC_DRQ_EN);
+}
+
+static void sunxi_codec_capture_stop(struct sunxi_priv *priv)
+{
+ /* disable ADC DRQ */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_ADC_DRQ_EN, 0x0 << SUNXI_ADC_FIFOC_ADC_DRQ_EN);
+
+ /* enable mic1 PA */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << SUNXI_ADC_ACTL_PREG1EN, 0x0 << SUNXI_ADC_ACTL_PREG1EN);
+
+ /* enable VMIC */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << SUNXI_ADC_ACTL_VMICEN, 0x0 << SUNXI_ADC_ACTL_VMICEN);
+ if (priv->revision == SUN7I) {
+ /* TODO: undocumented */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_TUNE, 0x3 << 8, 0x0 << 8);
+ }
+
+ /* enable ADC digital */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_EN_AD, 0x0 << SUNXI_ADC_FIFOC_EN_AD);
+
+ /* set RX FIFO mode */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_RX_FIFO_MODE, 0x0 << SUNXI_ADC_FIFOC_RX_FIFO_MODE);
+
+ /* flush RX FIFO */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_FIFO_FLUSH, 0x0 << SUNXI_ADC_FIFOC_FIFO_FLUSH);
+
+ /* enable adc1 analog */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << SUNXI_ADC_ACTL_ADCLEN, 0x0 << SUNXI_ADC_ACTL_ADCLEN);
+}
+
+static int sunxi_codec_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ sunxi_codec_capture_start(priv);
+ else
+ sunxi_codec_play_start(priv);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ sunxi_codec_capture_stop(priv);
+ else
+ sunxi_codec_play_stop(priv);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sunxi_codec_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_FIFO_FLUSH, 0x1 << SUNXI_DAC_FIFOC_FIFO_FLUSH);
+
+ /* set TX FIFO send DRQ level */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x3f << SUNXI_DAC_FIFOC_TX_TRIG_LEVEL, 0xf << SUNXI_DAC_FIFOC_TX_TRIG_LEVEL);
+ if (substream->runtime->rate > 32000) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_FIR_VERSION, 0x0 << SUNXI_DAC_FIFOC_FIR_VERSION);
+ } else {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_FIR_VERSION, 0x1 << SUNXI_DAC_FIFOC_FIR_VERSION);
+ }
+
+ /* set TX FIFO MODE - 0 works for both 16 and 24 bits */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_TX_FIFO_MODE, 0x0 << SUNXI_DAC_FIFOC_TX_FIFO_MODE);
+
+ /* send last sample when DAC FIFO under run */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_SEND_LASAT, 0x0 << SUNXI_DAC_FIFOC_SEND_LASAT);
+ } else {
+ /* enable mic1 PA */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << SUNXI_ADC_ACTL_PREG1EN, 0x1 << SUNXI_ADC_ACTL_PREG1EN);
+
+ /* mic1 gain 32dB */ /* FIXME - makes no sense */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << 25, 0x1 << 25);
+
+ /* enable VMIC */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x1 << SUNXI_ADC_ACTL_VMICEN, 0x1 << SUNXI_ADC_ACTL_VMICEN);
+
+ if (priv->revision == SUN7I) {
+ /* boost up record effect */
+ regmap_update_bits(priv->regmap, SUNXI_DAC_TUNE, 0x3 << 8, 0x1 << 8);
+ }
+
+ /* enable ADC digital */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_EN_AD, 0x1 << SUNXI_ADC_FIFOC_EN_AD);
+
+ /* set RX FIFO mode */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_RX_FIFO_MODE, 0x1 << SUNXI_ADC_FIFOC_RX_FIFO_MODE);
+
+ /* flush RX FIFO */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0x1 << SUNXI_ADC_FIFOC_FIFO_FLUSH, 0x1 << SUNXI_ADC_FIFOC_FIFO_FLUSH);
+
+ /* set RX FIFO rec drq level */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 0xf << SUNXI_ADC_FIFOC_RX_TRIG_LEVEL, 0x7 << SUNXI_ADC_FIFOC_RX_TRIG_LEVEL);
+
+ /* enable adc1 analog */
+ regmap_update_bits(priv->regmap, SUNXI_ADC_ACTL, 0x3 << SUNXI_ADC_ACTL_ADCLEN, 0x3 << SUNXI_ADC_ACTL_ADCLEN);
+ }
+
+ return 0;
+}
+
+static int sunxi_codec_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+ int is_mono = !!(params_channels(params) == 1);
+ int is_24bit = !!(hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)->min == 32);
+ unsigned int rate = params_rate(params);
+ unsigned int hwrate;
+
+ switch (rate) {
+ case 176400:
+ case 88200:
+ case 44100:
+ case 33075:
+ case 22050:
+ case 14700:
+ case 11025:
+ case 7350:
+ default:
+ clk_set_rate(priv->clk_module, 22579200);
+ break;
+ case 192000:
+ case 96000:
+ case 48000:
+ case 32000:
+ case 24000:
+ case 16000:
+ case 12000:
+ case 8000:
+ clk_set_rate(priv->clk_module, 24576000);
+ break;
+ }
+
+ switch (rate) {
+ case 192000:
+ case 176400:
+ hwrate = 6;
+ break;
+ case 96000:
+ case 88200:
+ hwrate = 7;
+ break;
+ default:
+ case 48000:
+ case 44100:
+ hwrate = 0;
+ break;
+ case 32000:
+ case 33075:
+ hwrate = 1;
+ break;
+ case 24000:
+ case 22050:
+ hwrate = 2;
+ break;
+ case 16000:
+ case 14700:
+ hwrate = 3;
+ break;
+ case 12000:
+ case 11025:
+ hwrate = 4;
+ break;
+ case 8000:
+ case 7350:
+ hwrate = 5;
+ break;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 7 << SUNXI_DAC_FIFOC_DAC_FS, hwrate << SUNXI_DAC_FIFOC_DAC_FS);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_MONO_EN, is_mono << SUNXI_DAC_FIFOC_MONO_EN);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_TX_SAMPLE_BITS, is_24bit << SUNXI_DAC_FIFOC_TX_SAMPLE_BITS);
+ if (is_24bit)
+ priv->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ else
+ priv->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ } else {
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 7 << SUNXI_DAC_FIFOC_DAC_FS, hwrate << SUNXI_DAC_FIFOC_DAC_FS);
+ regmap_update_bits(priv->regmap, SUNXI_ADC_FIFOC, 1 << SUNXI_ADC_FIFOC_MONO_EN, is_mono << SUNXI_ADC_FIFOC_MONO_EN);
+ }
+
+ return 0;
+}
+
+static const struct snd_kcontrol_new sun7i_dac_ctls[] = {
+ /*SUNXI_DAC_ACTL = 0x10,PAVOL*/
+ SOC_SINGLE("Master Playback Volume", SUNXI_DAC_ACTL, 0, 0x3f, 0),
+ SOC_SINGLE("Playback Switch", SUNXI_DAC_ACTL, 6, 1, 0), /* Global output switch */
+ SOC_SINGLE("FmL Switch", SUNXI_DAC_ACTL, 17, 1, 0), /* FM left switch */
+ SOC_SINGLE("FmR Switch", SUNXI_DAC_ACTL, 16, 1, 0), /* FM right switch */
+ SOC_SINGLE("LineL Switch", SUNXI_DAC_ACTL, 19, 1, 0), /* Line left switch */
+ SOC_SINGLE("LineR Switch", SUNXI_DAC_ACTL, 18, 1, 0), /* Line right switch */
+ SOC_SINGLE("Ldac Left Mixer", SUNXI_DAC_ACTL, 15, 1, 0),
+ SOC_SINGLE("Rdac Right Mixer", SUNXI_DAC_ACTL, 14, 1, 0),
+ SOC_SINGLE("Ldac Right Mixer", SUNXI_DAC_ACTL, 13, 1, 0),
+ SOC_SINGLE("Mic Input Mux", SUNXI_DAC_ACTL, 9, 15, 0), /* from bit 9 to bit 12. Microphone input mute */
+ SOC_SINGLE("MIC output volume", SUNXI_DAC_ACTL, 20, 7, 0),
+ /* FM Input to output mixer Gain Control
+ * From -4.5db to 6db,1.5db/step,default is 0db
+ * -4.5db:0x0,-3.0db:0x1,-1.5db:0x2,0db:0x3
+ * 1.5db:0x4,3.0db:0x5,4.5db:0x6,6db:0x7
+ */
+ SOC_SINGLE("Fm output Volume", SUNXI_DAC_ACTL, 23, 7, 0),
+ /* Line-in gain stage to output mixer Gain Control
+ * 0:-1.5db,1:0db
+ */
+ SOC_SINGLE("Line output Volume", SUNXI_DAC_ACTL, 26, 1, 0),
+
+ SOC_SINGLE("Master Capture Mute", SUNXI_ADC_ACTL, 4, 1, 0),
+ SOC_SINGLE("Right Capture Mute", SUNXI_ADC_ACTL, 31, 1, 0),
+ SOC_SINGLE("Left Capture Mute", SUNXI_ADC_ACTL, 30, 1, 0),
+ SOC_SINGLE("Linein Pre-AMP", SUNXI_ADC_ACTL, 13, 7, 0),
+ SOC_SINGLE("LINEIN APM Volume", SUNXI_AC_MIC_PHONE_CAL, 13, 0x7, 0),
+ /* ADC Input Gain Control, capture volume
+ * 000:-4.5db,001:-3db,010:-1.5db,011:0db,100:1.5db,101:3db,110:4.5db,111:6db
+ */
+ SOC_SINGLE("Capture Volume", SUNXI_ADC_ACTL, 20, 7, 0),
+ /*
+ * MIC2 pre-amplifier Gain Control
+ * 00:0db,01:35db,10:38db,11:41db
+ */
+ SOC_SINGLE("MicL Volume", SUNXI_ADC_ACTL, 25, 3, 0), /* Microphone left volume */
+ SOC_SINGLE("MicR Volume", SUNXI_ADC_ACTL, 23, 3, 0), /* Microphone right volume */
+ SOC_SINGLE("Mic2 Boost", SUNXI_ADC_ACTL, 29, 1, 0),
+ SOC_SINGLE("Mic1 Boost", SUNXI_ADC_ACTL, 28, 1, 0),
+ SOC_SINGLE("Mic Power", SUNXI_ADC_ACTL, 27, 1, 0),
+ SOC_SINGLE("ADC Input Mux", SUNXI_ADC_ACTL, 17, 7, 0), /* ADC input mute */
+ SOC_SINGLE("Mic2 gain Volume", SUNXI_AC_MIC_PHONE_CAL, 26, 7, 0),
+ /*
+ * MIC1 pre-amplifier Gain Control
+ * 00:0db,01:35db,10:38db,11:41db
+ */
+ SOC_SINGLE("Mic1 gain Volume", SUNXI_AC_MIC_PHONE_CAL, 29, 3, 0),
+};
+
+static int sunxi_codec_dai_probe(struct snd_soc_dai *dai)
+{
+ struct snd_soc_card *card = snd_soc_dai_get_drvdata(dai);
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(card);
+
+ snd_soc_dai_init_dma_data(dai, &priv->playback_dma_data, &priv->capture_dma_data);
+
+ return 0;
+}
+
+static void sunxi_codec_init(struct sunxi_priv *priv)
+{
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_FIR_VERSION, 1 << SUNXI_DAC_FIFOC_FIR_VERSION);
+
+ /* set digital volume to maximum */
+ if (priv->revision == SUN4IA)
+ regmap_update_bits(priv->regmap, SUNXI_DAC_DPC, 0x3F << SUNXI_DAC_DPC_DVOL, 0 << SUNXI_DAC_DPC_DVOL);
+
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 3 << SUNXI_DAC_FIFOC_DRQ_CLR_CNT, 3 << SUNXI_DAC_FIFOC_DRQ_CLR_CNT);
+
+ /* set volume */ /* TODO: is A10A inverted? */
+ if (priv->revision == SUN4IA)
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x3f << SUNXI_DAC_ACTL_PA_VOL, 1 << SUNXI_DAC_ACTL_PA_VOL);
+ else
+ regmap_update_bits(priv->regmap, SUNXI_DAC_ACTL, 0x3f << SUNXI_DAC_ACTL_PA_VOL, 0x3b << SUNXI_DAC_ACTL_PA_VOL);
+}
+
+static int sunxi_codec_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+
+ sunxi_codec_init(priv);
+
+ return clk_prepare_enable(priv->clk_module);
+}
+
+static void sunxi_codec_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct sunxi_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+
+ clk_disable_unprepare(priv->clk_module);
+}
+
+/*** Codec DAI ***/
+
+static const struct snd_soc_dai_ops sunxi_codec_dai_ops = {
+ .startup = sunxi_codec_startup,
+ .shutdown = sunxi_codec_shutdown,
+ .trigger = sunxi_codec_trigger,
+ .hw_params = sunxi_codec_hw_params,
+ .prepare = sunxi_codec_prepare,
+};
+
+static struct snd_soc_dai_driver sunxi_codec_dai = {
+ .name = "Codec",
+ .playback = {
+ .stream_name = "Codec Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_22050| SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 |SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
+ .sig_bits = 24,
+ },
+ .capture = {
+ .stream_name = "Codec Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 192000,
+ .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_11025 |\
+ SNDRV_PCM_RATE_22050| SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000 |SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
+ SNDRV_PCM_RATE_KNOT),
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE),
+ .sig_bits = 24,
+ },
+ .ops = &sunxi_codec_dai_ops,
+};
+
+/*** Codec ***/
+
+static const struct snd_kcontrol_new sunxi_pa =
+ SOC_DAPM_SINGLE("PA Switch", SUNXI_ADC_ACTL, SUNXI_ADC_ACTL_PA_EN, 1, 0);
+
+static const struct snd_kcontrol_new sunxi_pa_mute =
+ SOC_DAPM_SINGLE("PA Mute Switch", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_PA_MUTE, 1, 0);
+
+static DECLARE_TLV_DB_SCALE(sunxi_pa_volume_scale, -6300, 100, 1);
+
+static const struct snd_kcontrol_new sunxi_codec_widgets[] = {
+ SOC_SINGLE_TLV("PA Volume", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_PA_VOL,
+ 0x3F, 0, sunxi_pa_volume_scale),
+};
+
+static const char *right_output_mixer_text[] = { "Disabled", "Left", "Right" };
+static const unsigned int right_output_mixer_values[] = { 0x0, 0x1, 0x2 };
+static SOC_VALUE_ENUM_SINGLE_DECL(right_output_mixer, SUNXI_DAC_ACTL,
+ SUNXI_DAC_ACTL_LDACRMIXS, 0x3,
+ right_output_mixer_text,
+ right_output_mixer_values);
+
+static const char *left_output_mixer_text[] = { "Disabled", "Left" };
+static const unsigned int left_output_mixer_values[] = { 0x0, 0x1 };
+static SOC_VALUE_ENUM_SINGLE_DECL(left_output_mixer, SUNXI_DAC_ACTL,
+ SUNXI_DAC_ACTL_LDACLMIXS, 0x1,
+ left_output_mixer_text,
+ left_output_mixer_values);
+
+static const struct snd_kcontrol_new right_mixer =
+ SOC_DAPM_ENUM("Right Mixer", right_output_mixer);
+
+static const struct snd_kcontrol_new left_mixer =
+ SOC_DAPM_ENUM("Left Mixer", left_output_mixer);
+
+static const struct snd_kcontrol_new sunxi_mixer =
+ SOC_DAPM_SINGLE("Mixer Switch", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_MIXEN, 1, 0);
+
+static const char *sunxi_dac_output_text[] = { "Muted", "Mixed", "Direct" };
+static const unsigned int sunxi_dac_output_values[] = { 0x0, 0x1, 0x2 };
+static SOC_VALUE_ENUM_SINGLE_DECL(dac_output_mux, SUNXI_DAC_ACTL,
+ SUNXI_DAC_ACTL_MIXPAS, 0x3,
+ sunxi_dac_output_text,
+ sunxi_dac_output_values);
+
+static const struct snd_kcontrol_new sunxi_dac_output =
+ SOC_DAPM_ENUM("DAC Output", dac_output_mux);
+
+static const struct snd_soc_dapm_widget codec_dapm_widgets[] = {
+ /* Digital parts of the DACs */
+ SND_SOC_DAPM_SUPPLY("DAC", SUNXI_DAC_DPC, SUNXI_DAC_DPC_EN_DA, 0, NULL, 0),
+
+ /* Analog parts of the DACs */
+ SND_SOC_DAPM_DAC("Left DAC", NULL, SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_DACAENL, 0),
+ SND_SOC_DAPM_DAC("Right DAC", NULL, SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_DACAENR, 0),
+
+ SND_SOC_DAPM_SWITCH("PA", SUNXI_ADC_ACTL, SUNXI_ADC_ACTL_PA_EN, 0, &sunxi_pa),
+ SND_SOC_DAPM_SWITCH("PA Mute", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_PA_MUTE, 0, &sunxi_pa_mute),
+
+ SND_SOC_DAPM_MUX("Right Mixer", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_LDACRMIXS, 0, &right_mixer),
+ SND_SOC_DAPM_MUX("Left Mixer", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_LDACLMIXS, 0, &left_mixer),
+ SND_SOC_DAPM_SWITCH("Mixer", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_MIXEN, 0, &sunxi_mixer),
+
+ SND_SOC_DAPM_MUX("DAC Output", SUNXI_DAC_ACTL, SUNXI_DAC_ACTL_MIXPAS, 0, &sunxi_dac_output),
+
+ SND_SOC_DAPM_OUTPUT("Mic Bias"),
+ SND_SOC_DAPM_OUTPUT("HP Right"),
+ SND_SOC_DAPM_OUTPUT("HP Left"),
+ SND_SOC_DAPM_INPUT("MIC_IN"),
+ SND_SOC_DAPM_INPUT("LINE_IN"),
+};
+
+static const struct snd_soc_dapm_route codec_dapm_routes[] = {
+ /* DAC block */
+ { "Left DAC", NULL, "Codec Playback" },
+ { "Right DAC", NULL, "Codec Playback" },
+ { "Left DAC", NULL, "DAC" },
+ { "Right DAC", NULL, "DAC" },
+
+ /* DAC -> PA path */
+ { "DAC Output", "Direct", "Left DAC" },
+ { "DAC Output", "Direct", "Right DAC" },
+ { "PA", NULL, "DAC Output"},
+
+ /* DAC -> MIX -> PA path */
+ { "Left Mixer", "Left", "Left DAC" },
+ { "Right Mixer", "Right", "Right DAC" },
+ { "Mixer", NULL, "Left Mixer" },
+ { "Mixer", NULL, "Right Mixer" },
+ { "DAC Output", "Mixed", "Mixer" },
+ { "PA", NULL, "DAC Output" },
+
+ /* PA -> HP path */
+ { "PA Mute", NULL, "PA" },
+ { "HP Right", NULL, "PA Mute" },
+ { "HP Left", NULL, "PA Mute" },
+};
+
+static struct snd_soc_codec_driver sunxi_codec = {
+ .controls = sunxi_codec_widgets,
+ .num_controls = ARRAY_SIZE(sunxi_codec_widgets),
+ .dapm_widgets = codec_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(codec_dapm_widgets),
+ .dapm_routes = codec_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(codec_dapm_routes),
+};
+
+/*** Board routing ***/
+/* TODO: do this with DT */
+
+static const struct snd_soc_dapm_widget sunxi_board_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route sunxi_board_routing[] = {
+ { "Headphone Jack", NULL, "HP Right" },
+ { "Headphone Jack", NULL, "HP Left" },
+};
+
+/*** Card and DAI Link ***/
+
+static struct snd_soc_dai_link cdc_dai = {
+ .name = "cdc",
+
+ .stream_name = "CDC PCM",
+ .codec_dai_name = "Codec",
+ .cpu_dai_name = "1c22c00.codec",
+ .codec_name = "1c22c00.codec",
+ .platform_name = "1c22c00.codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S,
+};
+
+static struct snd_soc_card snd_soc_sunxi_codec = {
+ .name = "sunxi-codec",
+ .owner = THIS_MODULE,
+ .dai_link = &cdc_dai,
+ .num_links = 1,
+ .dapm_widgets = sunxi_board_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(sunxi_board_dapm_widgets),
+ .dapm_routes = sunxi_board_routing,
+ .num_dapm_routes = ARRAY_SIZE(sunxi_board_routing),
+};
+
+/*** CPU DAI ***/
+
+static const struct snd_soc_component_driver sunxi_codec_component = {
+ .name = "sunxi-codec",
+};
+
+#define SUNXI_RATES SNDRV_PCM_RATE_8000_192000
+#define SUNXI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver dummy_cpu_dai = {
+ .name = "sunxi-cpu-dai",
+ .probe = sunxi_codec_dai_probe,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SUNXI_RATES,
+ .formats = SUNXI_FORMATS,
+ .sig_bits = 24,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SUNXI_RATES,
+ .formats = SUNXI_FORMATS,
+ .sig_bits = 24,
+ },
+};
+
+static const struct regmap_config sunxi_codec_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = SUNXI_AC_MIC_PHONE_CAL,
+};
+
+static const struct of_device_id sunxi_codec_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10a-codec", .data = (void *)SUN4IA},
+ { .compatible = "allwinner,sun4i-a10-codec", .data = (void *)SUN4I},
+ { .compatible = "allwinner,sun5i-a13-codec", .data = (void *)SUN5I},
+ { .compatible = "allwinner,sun7i-a20-codec", .data = (void *)SUN7I},
+ {}
+};
+MODULE_DEVICE_TABLE(of, sunxi_codec_of_match);
+
+static int sunxi_codec_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &snd_soc_sunxi_codec;
+ const struct of_device_id *of_id;
+ struct device *dev = &pdev->dev;
+ struct sunxi_priv *priv;
+ struct resource *res;
+ void __iomem *base;
+ int ret;
+
+ if (!of_device_is_available(np))
+ return -ENODEV;
+
+ of_id = of_match_device(sunxi_codec_of_match, dev);
+ if (!of_id)
+ return -EINVAL;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ card->dev = &pdev->dev;
+ platform_set_drvdata(pdev, card);
+ snd_soc_card_set_drvdata(card, priv);
+
+ priv->revision = (enum sunxi_soc_family)of_id->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &sunxi_codec_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ /* Get the clocks from the DT */
+ priv->clk_apb = devm_clk_get(dev, "apb");
+ if (IS_ERR(priv->clk_apb)) {
+ dev_err(dev, "failed to get apb clock\n");
+ return PTR_ERR(priv->clk_apb);
+ }
+ priv->clk_module = devm_clk_get(dev, "codec");
+ if (IS_ERR(priv->clk_module)) {
+ dev_err(dev, "failed to get codec clock\n");
+ return PTR_ERR(priv->clk_module);
+ }
+
+ /* Enable the clock on a basic rate */
+ ret = clk_set_rate(priv->clk_module, 24576000);
+ if (ret) {
+ dev_err(dev, "failed to set codec base clock rate\n");
+ return ret;
+ }
+
+ /* Enable the bus clock */
+ if (clk_prepare_enable(priv->clk_apb)) {
+ dev_err(dev, "failed to enable apb clock\n");
+ clk_disable_unprepare(priv->clk_module);
+ return -EINVAL;
+ }
+
+ /* DMA configuration for TX FIFO */
+ priv->playback_dma_data.addr = res->start + SUNXI_DAC_TXDATA;
+ priv->playback_dma_data.maxburst = 4;
+ priv->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ /* DMA configuration for RX FIFO */
+ priv->capture_dma_data.addr = res->start + SUNXI_ADC_RXDATA;
+ priv->capture_dma_data.maxburst = 4;
+ priv->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ ret = snd_soc_register_codec(&pdev->dev, &sunxi_codec, &sunxi_codec_dai, 1);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &sunxi_codec_component, &dummy_cpu_dai, 1);
+ if (ret)
+ goto err_clk_disable;
+
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
+ if (ret)
+ goto err_clk_disable;
+
+ sunxi_codec_init(priv);
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+ goto err_fini_utils;
+ }
+
+ ret = snd_soc_of_parse_audio_routing(card, "routing");
+ if (ret)
+ goto err;
+
+ return 0;
+
+err_fini_utils:
+err:
+err_clk_disable:
+ clk_disable_unprepare(priv->clk_apb);
+ return ret;
+}
+
+static int sunxi_codec_remove(struct platform_device *pdev)
+{
+ struct sunxi_priv *priv = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(priv->clk_apb);
+ clk_disable_unprepare(priv->clk_module);
+
+ return 0;
+}
+
+static struct platform_driver sunxi_codec_driver = {
+ .driver = {
+ .name = "sunxi-codec",
+ .owner = THIS_MODULE,
+ .of_match_table = sunxi_codec_of_match,
+ },
+ .probe = sunxi_codec_probe,
+ .remove = sunxi_codec_remove,
+};
+module_platform_driver(sunxi_codec_driver);
+
+MODULE_DESCRIPTION("sunxi codec ASoC driver");
+MODULE_AUTHOR("Emilio López <emilio@elopez.com.ar>");
+MODULE_AUTHOR("Jon Smirl <jonsmirl@gmail.com>");
+MODULE_LICENSE("GPL");

View file

@ -1,33 +0,0 @@
From f8517e7d836269f5fa1e1049394104417d3a7357 Mon Sep 17 00:00:00 2001
From: "B.R. Oake" <broake@openmailbox.org>
Date: Sat, 6 Sep 2014 14:58:50 +0000
Subject: [PATCH] ASoC: sunxi-codec: Fix distortion on 16-bit mono
Patch to remove distortion on 16-bit mono, based on the linux-sunxi-3.4
code.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
sound/soc/sunxi/sunxi-codec.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
--- a/sound/soc/sunxi/sunxi-codec.c
+++ b/sound/soc/sunxi/sunxi-codec.c
@@ -215,9 +215,6 @@ static int sunxi_codec_prepare(struct sn
regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_FIR_VERSION, 0x1 << SUNXI_DAC_FIFOC_FIR_VERSION);
}
- /* set TX FIFO MODE - 0 works for both 16 and 24 bits */
- regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_TX_FIFO_MODE, 0x0 << SUNXI_DAC_FIFOC_TX_FIFO_MODE);
-
/* send last sample when DAC FIFO under run */
regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 0x1 << SUNXI_DAC_FIFOC_SEND_LASAT, 0x0 << SUNXI_DAC_FIFOC_SEND_LASAT);
} else {
@@ -329,6 +326,7 @@ static int sunxi_codec_hw_params(struct
regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 7 << SUNXI_DAC_FIFOC_DAC_FS, hwrate << SUNXI_DAC_FIFOC_DAC_FS);
regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_MONO_EN, is_mono << SUNXI_DAC_FIFOC_MONO_EN);
regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_TX_SAMPLE_BITS, is_24bit << SUNXI_DAC_FIFOC_TX_SAMPLE_BITS);
+ regmap_update_bits(priv->regmap, SUNXI_DAC_FIFOC, 1 << SUNXI_DAC_FIFOC_TX_FIFO_MODE, !is_24bit << SUNXI_DAC_FIFOC_TX_FIFO_MODE);
if (is_24bit)
priv->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
else

View file

@ -1,34 +0,0 @@
From ca3f125c08bab943572a15ac3a52f33f132cf77f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <elopez93@gmail.com>
Date: Mon, 18 Aug 2014 01:07:55 -0300
Subject: [PATCH] ARM: sun7i: dt: Add sunxi codec device node
The A20 SoC includes the Allwinner audio codec, capable of both 24-bit
playback and capture. This commit adds a device node for it.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -1182,6 +1182,18 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun7i-a20-codec";
+ reg = <0x01c22c00 0x40>;
+ interrupts = <0 30 4>;
+ clocks = <&apb0_gates 0>, <&codec_clk>;
+ clock-names = "apb", "codec";
+ dmas = <&dma 0 19>, <&dma 0 19>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun7i-a20-sid";
reg = <0x01c23800 0x200>;

View file

@ -1,13 +0,0 @@
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -302,3 +302,10 @@
};
};
+
+&codec {
+ routing =
+ "Headphone Jack", "HP Left",
+ "Headphone Jack", "HP Right";
+ status = "okay";
+};

View file

@ -1,26 +0,0 @@
From f9681320a1c1caed9c899acfefcb308ac7c911d1 Mon Sep 17 00:00:00 2001
From: Maxime Ripard <maxime.ripard@free-electrons.com>
Date: Fri, 1 May 2015 22:39:45 +0200
Subject: [PATCH] Add cubieboard2 audio codec
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -180,6 +180,13 @@
#include "axp209.dtsi"
+&codec {
+ routing =
+ "Headphone Jack", "HP Left",
+ "Headphone Jack", "HP Right";
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};

View file

@ -1,29 +0,0 @@
From 42ac277ad129cf69d5540938c943f6291a7a9898 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <elopez93@gmail.com>
Date: Mon, 18 Aug 2014 01:10:05 -0300
Subject: [PATCH] ARM: sun7i: dt: enable audio codec on Cubietruck
This commit enables the on-chip audio codec present on the A20 SoC
and outlines the SoC to connector routes for the Cubietruck.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -257,6 +257,13 @@
#include "axp209.dtsi"
+&codec {
+ routing =
+ "Headphone Jack", "HP Left",
+ "Headphone Jack", "HP Right";
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};

View file

@ -1,810 +0,0 @@
From 744543c599c420bcddca08cd2e2713b82a008328 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 8 Jul 2015 16:41:38 +0200
Subject: [PATCH] usb: musb: sunxi: Add support for the Allwinner sunxi musb
controller
This is based on initial code to get the Allwinner sunxi musb controller
supported by Chen-Yu Tsai and Roman Byshko.
This adds support for the Allwinner sunxi musb controller in both host only
and otg mode. Peripheral only mode is not supported, as no boards use that.
This has been tested on a cubietruck (A20 SoC) and an UTOO P66 tablet
(A13 SoC) with a variety of devices in host mode and with the g_serial gadget
driver in peripheral mode, plugging otg / host cables in/out a lot of times
in all possible imaginable plug orders.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
.../bindings/usb/allwinner,sun4i-a10-musb.txt | 27 +
drivers/usb/musb/Kconfig | 13 +-
drivers/usb/musb/Makefile | 1 +
drivers/usb/musb/sunxi.c | 703 +++++++++++++++++++++
4 files changed, 743 insertions(+), 1 deletion(-)
create mode 100644 Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
create mode 100644 drivers/usb/musb/sunxi.c
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
@@ -0,0 +1,27 @@
+Allwinner sun4i A10 musb DRC/OTG controller
+-------------------------------------------
+
+Required properties:
+ - compatible : "allwinner,sun4i-a10-musb"
+ - reg : mmio address range of the musb controller
+ - clocks : clock specifier for the musb controller ahb gate clock
+ - interrupts : interrupt to which the musb controller is connected
+ - interrupt-names : must be "mc"
+ - phys : phy specifier for the otg phy
+ - phy-names : must be "usb"
+ - dr_mode : Dual-Role mode must be "host" or "otg"
+ - extcon : extcon specifier for the otg phy
+
+Example:
+
+ usb_otg: usb@01c13000 {
+ compatible = "allwinner,sun4i-a10-musb";
+ reg = <0x01c13000 0x0400>;
+ clocks = <&ahb_gates 0>;
+ interrupts = <38>;
+ interrupt-names = "mc";
+ phys = <&usbphy 0>;
+ phy-names = "usb";
+ extcon = <&usbphy 0>;
+ status = "disabled";
+ };
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -5,7 +5,7 @@
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
- tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
+ tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)'
depends on (USB || USB_GADGET)
help
Say Y here if your system has a dual role high speed USB
@@ -20,6 +20,8 @@ config USB_MUSB_HDRC
Analog Devices parts using this IP include Blackfin BF54x,
BF525 and BF527.
+ Allwinner SoCs using this IP include A10, A13, A20, ...
+
If you do not know what this is, please say N.
To compile this driver as a module, choose M here; the
@@ -60,6 +62,15 @@ endchoice
comment "Platform Glue Layer"
+config USB_MUSB_SUNXI
+ tristate "Allwinner (sunxi)"
+ depends on ARCH_SUNXI
+ depends on NOP_USB_XCEIV
+ depends on PHY_SUN4I_USB
+ depends on EXTCON
+ depends on GENERIC_PHY
+ select SUNXI_SRAM
+
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
obj-$(CONFIG_USB_MUSB_JZ4740) += jz4740.o
+obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
obj-$(CONFIG_USB_MUSB_AM335X_CHILD) += musb_am335x.o
--- /dev/null
+++ b/drivers/usb/musb/sunxi.c
@@ -0,0 +1,703 @@
+/*
+ * Allwinner sun4i MUSB Glue Layer
+ *
+ * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on code from
+ * Allwinner Technology Co., Ltd. <www.allwinnertech.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/err.h>
+#include <linux/extcon.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy-sun4i-usb.h>
+#include <linux/platform_device.h>
+#include <linux/soc/sunxi/sunxi_sram.h>
+#include <linux/usb/musb.h>
+#include <linux/usb/of.h>
+#include <linux/usb/usb_phy_generic.h>
+#include <linux/workqueue.h>
+#include "musb_core.h"
+
+/*
+ * Register offsets, note sunxi musb has a different layout then most
+ * musb implementations, we translate the layout in musb_readb & friends.
+ */
+#define SUNXI_MUSB_POWER 0x0040
+#define SUNXI_MUSB_DEVCTL 0x0041
+#define SUNXI_MUSB_INDEX 0x0042
+#define SUNXI_MUSB_VEND0 0x0043
+#define SUNXI_MUSB_INTRTX 0x0044
+#define SUNXI_MUSB_INTRRX 0x0046
+#define SUNXI_MUSB_INTRTXE 0x0048
+#define SUNXI_MUSB_INTRRXE 0x004a
+#define SUNXI_MUSB_INTRUSB 0x004c
+#define SUNXI_MUSB_INTRUSBE 0x0050
+#define SUNXI_MUSB_FRAME 0x0054
+#define SUNXI_MUSB_TXFIFOSZ 0x0090
+#define SUNXI_MUSB_TXFIFOADD 0x0092
+#define SUNXI_MUSB_RXFIFOSZ 0x0094
+#define SUNXI_MUSB_RXFIFOADD 0x0096
+#define SUNXI_MUSB_FADDR 0x0098
+#define SUNXI_MUSB_TXFUNCADDR 0x0098
+#define SUNXI_MUSB_TXHUBADDR 0x009a
+#define SUNXI_MUSB_TXHUBPORT 0x009b
+#define SUNXI_MUSB_RXFUNCADDR 0x009c
+#define SUNXI_MUSB_RXHUBADDR 0x009e
+#define SUNXI_MUSB_RXHUBPORT 0x009f
+#define SUNXI_MUSB_CONFIGDATA 0x00c0
+
+/* VEND0 bits */
+#define SUNXI_MUSB_VEND0_PIO_MODE 0
+
+/* flags */
+#define SUNXI_MUSB_FL_ENABLED 0
+#define SUNXI_MUSB_FL_HOSTMODE 1
+#define SUNXI_MUSB_FL_HOSTMODE_PEND 2
+#define SUNXI_MUSB_FL_VBUS_ON 3
+#define SUNXI_MUSB_FL_PHY_ON 4
+
+/* Our read/write methods need access and do not get passed in a musb ref :| */
+static struct musb *sunxi_musb;
+
+struct sunxi_glue {
+ struct device *dev;
+ struct platform_device *musb;
+ struct clk *clk;
+ struct phy *phy;
+ struct platform_device *usb_phy;
+ struct usb_phy *xceiv;
+ unsigned long flags;
+ struct work_struct work;
+ struct extcon_dev *extcon;
+ struct notifier_block host_nb;
+};
+
+/* phy_power_on / off may sleep, so we use a workqueue */
+static void sunxi_musb_work(struct work_struct *work)
+{
+ struct sunxi_glue *glue = container_of(work, struct sunxi_glue, work);
+ bool vbus_on, phy_on;
+
+ if (!test_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
+ return;
+
+ if (test_and_clear_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags)) {
+ struct musb *musb = platform_get_drvdata(glue->musb);
+ unsigned long flags;
+ u8 devctl;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ devctl = readb(musb->mregs + SUNXI_MUSB_DEVCTL);
+ if (test_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags)) {
+ set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->otg->state = OTG_STATE_A_IDLE;
+ MUSB_HST_MODE(musb);
+ devctl |= MUSB_DEVCTL_SESSION;
+ } else {
+ clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+ musb->xceiv->otg->default_a = 0;
+ musb->xceiv->otg->state = OTG_STATE_B_IDLE;
+ MUSB_DEV_MODE(musb);
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ }
+ writeb(devctl, musb->mregs + SUNXI_MUSB_DEVCTL);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+ }
+
+ vbus_on = test_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+ phy_on = test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+
+ if (phy_on != vbus_on) {
+ if (vbus_on) {
+ phy_power_on(glue->phy);
+ set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+ } else {
+ phy_power_off(glue->phy);
+ clear_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+ }
+ }
+}
+
+static void sunxi_musb_set_vbus(struct musb *musb, int is_on)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ if (is_on)
+ set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+ else
+ clear_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+
+ schedule_work(&glue->work);
+}
+
+static void sunxi_musb_pre_root_reset_end(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ sun4i_usb_phy_set_squelch_detect(glue->phy, false);
+}
+
+static void sunxi_musb_post_root_reset_end(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ sun4i_usb_phy_set_squelch_detect(glue->phy, true);
+}
+
+static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
+{
+ struct musb *musb = __hci;
+ unsigned long flags;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ musb->int_usb = readb(musb->mregs + SUNXI_MUSB_INTRUSB);
+ if (musb->int_usb)
+ writeb(musb->int_usb, musb->mregs + SUNXI_MUSB_INTRUSB);
+
+ /*
+ * sunxi musb often signals babble on low / full speed device
+ * disconnect, without ever raising MUSB_INTR_DISCONNECT, since
+ * normally babble never happens treat it as disconnect.
+ */
+ if ((musb->int_usb & MUSB_INTR_BABBLE) && is_host_active(musb)) {
+ musb->int_usb &= ~MUSB_INTR_BABBLE;
+ musb->int_usb |= MUSB_INTR_DISCONNECT;
+ }
+
+ if ((musb->int_usb & MUSB_INTR_RESET) && !is_host_active(musb)) {
+ /* ep0 FADDR must be 0 when (re)entering peripheral mode */
+ musb_ep_select(musb->mregs, 0);
+ musb_writeb(musb->mregs, MUSB_FADDR, 0);
+ }
+
+ musb->int_tx = readw(musb->mregs + SUNXI_MUSB_INTRTX);
+ if (musb->int_tx)
+ writew(musb->int_tx, musb->mregs + SUNXI_MUSB_INTRTX);
+
+ musb->int_rx = readw(musb->mregs + SUNXI_MUSB_INTRRX);
+ if (musb->int_rx)
+ writew(musb->int_rx, musb->mregs + SUNXI_MUSB_INTRRX);
+
+ musb_interrupt(musb);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int sunxi_musb_host_notifier(struct notifier_block *nb,
+ unsigned long event, void *ptr)
+{
+ struct sunxi_glue *glue = container_of(nb, struct sunxi_glue, host_nb);
+
+ if (event)
+ set_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
+ else
+ clear_bit(SUNXI_MUSB_FL_HOSTMODE, &glue->flags);
+
+ set_bit(SUNXI_MUSB_FL_HOSTMODE_PEND, &glue->flags);
+ schedule_work(&glue->work);
+
+ return NOTIFY_DONE;
+}
+
+static int sunxi_musb_init(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+ int ret;
+
+ sunxi_musb = musb;
+ musb->phy = glue->phy;
+ musb->xceiv = glue->xceiv;
+
+ ret = sunxi_sram_claim(musb->controller->parent);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(glue->clk);
+ if (ret)
+ goto error_sram_release;
+
+ writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
+
+ /* Register notifier before calling phy_init() */
+ if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) {
+ ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
+ &glue->host_nb);
+ if (ret)
+ goto error_clk_disable;
+ }
+
+ ret = phy_init(glue->phy);
+ if (ret)
+ goto error_unregister_notifier;
+
+ if (musb->port_mode == MUSB_PORT_MODE_HOST) {
+ ret = phy_power_on(glue->phy);
+ if (ret)
+ goto error_phy_exit;
+ set_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags);
+ /* Stop musb work from turning vbus off again */
+ set_bit(SUNXI_MUSB_FL_VBUS_ON, &glue->flags);
+ }
+
+ musb->isr = sunxi_musb_interrupt;
+
+ /* Stop the musb-core from doing runtime pm (not supported on sunxi) */
+ pm_runtime_get(musb->controller);
+
+ return 0;
+
+error_phy_exit:
+ phy_exit(glue->phy);
+error_unregister_notifier:
+ if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+ extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
+ &glue->host_nb);
+error_clk_disable:
+ clk_disable_unprepare(glue->clk);
+error_sram_release:
+ sunxi_sram_release(musb->controller->parent);
+ return ret;
+}
+
+static int sunxi_musb_exit(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ pm_runtime_put(musb->controller);
+
+ cancel_work_sync(&glue->work);
+ if (test_bit(SUNXI_MUSB_FL_PHY_ON, &glue->flags))
+ phy_power_off(glue->phy);
+
+ phy_exit(glue->phy);
+
+ if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
+ extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
+ &glue->host_nb);
+
+ clk_disable_unprepare(glue->clk);
+ sunxi_sram_release(musb->controller->parent);
+
+ return 0;
+}
+
+static void sunxi_musb_enable(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ /* musb_core does not call us in a balanced manner */
+ if (test_and_set_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags))
+ return;
+
+ schedule_work(&glue->work);
+}
+
+static void sunxi_musb_disable(struct musb *musb)
+{
+ struct sunxi_glue *glue = dev_get_drvdata(musb->controller->parent);
+
+ clear_bit(SUNXI_MUSB_FL_ENABLED, &glue->flags);
+}
+
+/*
+ * sunxi musb register layout
+ * 0x00 - 0x17 fifo regs, 1 long per fifo
+ * 0x40 - 0x57 generic control regs (power - frame)
+ * 0x80 - 0x8f ep control regs (addressed through hw_ep->regs, indexed)
+ * 0x90 - 0x97 fifo control regs (indexed)
+ * 0x98 - 0x9f multipoint / busctl regs (indexed)
+ * 0xc0 configdata reg
+ */
+
+static u32 sunxi_musb_fifo_offset(u8 epnum)
+{
+ return (epnum * 4);
+}
+
+static u32 sunxi_musb_ep_offset(u8 epnum, u16 offset)
+{
+ WARN_ONCE(offset != 0,
+ "sunxi_musb_ep_offset called with non 0 offset\n");
+
+ return 0x80; /* indexed, so ignore epnum */
+}
+
+static u32 sunxi_musb_busctl_offset(u8 epnum, u16 offset)
+{
+ return SUNXI_MUSB_TXFUNCADDR + offset;
+}
+
+static u8 sunxi_musb_readb(const void __iomem *addr, unsigned offset)
+{
+ if (addr == sunxi_musb->mregs) {
+ /* generic control or fifo control reg access */
+ switch (offset) {
+ case MUSB_FADDR:
+ return readb(addr + SUNXI_MUSB_FADDR);
+ case MUSB_POWER:
+ return readb(addr + SUNXI_MUSB_POWER);
+ case MUSB_INTRUSB:
+ return readb(addr + SUNXI_MUSB_INTRUSB);
+ case MUSB_INTRUSBE:
+ return readb(addr + SUNXI_MUSB_INTRUSBE);
+ case MUSB_INDEX:
+ return readb(addr + SUNXI_MUSB_INDEX);
+ case MUSB_TESTMODE:
+ return 0; /* No testmode on sunxi */
+ case MUSB_DEVCTL:
+ return readb(addr + SUNXI_MUSB_DEVCTL);
+ case MUSB_TXFIFOSZ:
+ return readb(addr + SUNXI_MUSB_TXFIFOSZ);
+ case MUSB_RXFIFOSZ:
+ return readb(addr + SUNXI_MUSB_RXFIFOSZ);
+ case MUSB_CONFIGDATA + 0x10: /* See musb_read_configdata() */
+ return readb(addr + SUNXI_MUSB_CONFIGDATA);
+ /* Offset for these is fixed by sunxi_musb_busctl_offset() */
+ case SUNXI_MUSB_TXFUNCADDR:
+ case SUNXI_MUSB_TXHUBADDR:
+ case SUNXI_MUSB_TXHUBPORT:
+ case SUNXI_MUSB_RXFUNCADDR:
+ case SUNXI_MUSB_RXHUBADDR:
+ case SUNXI_MUSB_RXHUBPORT:
+ /* multipoint / busctl reg access */
+ return readb(addr + offset);
+ default:
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown readb offset %u\n", offset);
+ return 0;
+ }
+ } else if (addr == (sunxi_musb->mregs + 0x80)) {
+ /* ep control reg access */
+ /* sunxi has a 2 byte hole before the txtype register */
+ if (offset >= MUSB_TXTYPE)
+ offset += 2;
+ return readb(addr + offset);
+ }
+
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown readb at 0x%x bytes offset\n",
+ (int)(addr - sunxi_musb->mregs));
+ return 0;
+}
+
+static void sunxi_musb_writeb(void __iomem *addr, unsigned offset, u8 data)
+{
+ if (addr == sunxi_musb->mregs) {
+ /* generic control or fifo control reg access */
+ switch (offset) {
+ case MUSB_FADDR:
+ return writeb(data, addr + SUNXI_MUSB_FADDR);
+ case MUSB_POWER:
+ return writeb(data, addr + SUNXI_MUSB_POWER);
+ case MUSB_INTRUSB:
+ return writeb(data, addr + SUNXI_MUSB_INTRUSB);
+ case MUSB_INTRUSBE:
+ return writeb(data, addr + SUNXI_MUSB_INTRUSBE);
+ case MUSB_INDEX:
+ return writeb(data, addr + SUNXI_MUSB_INDEX);
+ case MUSB_TESTMODE:
+ if (data)
+ dev_warn(sunxi_musb->controller->parent,
+ "sunxi-musb does not have testmode\n");
+ return;
+ case MUSB_DEVCTL:
+ return writeb(data, addr + SUNXI_MUSB_DEVCTL);
+ case MUSB_TXFIFOSZ:
+ return writeb(data, addr + SUNXI_MUSB_TXFIFOSZ);
+ case MUSB_RXFIFOSZ:
+ return writeb(data, addr + SUNXI_MUSB_RXFIFOSZ);
+ /* Offset for these is fixed by sunxi_musb_busctl_offset() */
+ case SUNXI_MUSB_TXFUNCADDR:
+ case SUNXI_MUSB_TXHUBADDR:
+ case SUNXI_MUSB_TXHUBPORT:
+ case SUNXI_MUSB_RXFUNCADDR:
+ case SUNXI_MUSB_RXHUBADDR:
+ case SUNXI_MUSB_RXHUBPORT:
+ /* multipoint / busctl reg access */
+ return writeb(data, addr + offset);
+ default:
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown writeb offset %u\n", offset);
+ return;
+ }
+ } else if (addr == (sunxi_musb->mregs + 0x80)) {
+ /* ep control reg access */
+ if (offset >= MUSB_TXTYPE)
+ offset += 2;
+ return writeb(data, addr + offset);
+ }
+
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown writeb at 0x%x bytes offset\n",
+ (int)(addr - sunxi_musb->mregs));
+}
+
+static u16 sunxi_musb_readw(const void __iomem *addr, unsigned offset)
+{
+ if (addr == sunxi_musb->mregs) {
+ /* generic control or fifo control reg access */
+ switch (offset) {
+ case MUSB_INTRTX:
+ return readw(addr + SUNXI_MUSB_INTRTX);
+ case MUSB_INTRRX:
+ return readw(addr + SUNXI_MUSB_INTRRX);
+ case MUSB_INTRTXE:
+ return readw(addr + SUNXI_MUSB_INTRTXE);
+ case MUSB_INTRRXE:
+ return readw(addr + SUNXI_MUSB_INTRRXE);
+ case MUSB_FRAME:
+ return readw(addr + SUNXI_MUSB_FRAME);
+ case MUSB_TXFIFOADD:
+ return readw(addr + SUNXI_MUSB_TXFIFOADD);
+ case MUSB_RXFIFOADD:
+ return readw(addr + SUNXI_MUSB_RXFIFOADD);
+ case MUSB_HWVERS:
+ return 0; /* sunxi musb version is not known */
+ default:
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown readw offset %u\n", offset);
+ return 0;
+ }
+ } else if (addr == (sunxi_musb->mregs + 0x80)) {
+ /* ep control reg access */
+ return readw(addr + offset);
+ }
+
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown readw at 0x%x bytes offset\n",
+ (int)(addr - sunxi_musb->mregs));
+ return 0;
+}
+
+static void sunxi_musb_writew(void __iomem *addr, unsigned offset, u16 data)
+{
+ if (addr == sunxi_musb->mregs) {
+ /* generic control or fifo control reg access */
+ switch (offset) {
+ case MUSB_INTRTX:
+ return writew(data, addr + SUNXI_MUSB_INTRTX);
+ case MUSB_INTRRX:
+ return writew(data, addr + SUNXI_MUSB_INTRRX);
+ case MUSB_INTRTXE:
+ return writew(data, addr + SUNXI_MUSB_INTRTXE);
+ case MUSB_INTRRXE:
+ return writew(data, addr + SUNXI_MUSB_INTRRXE);
+ case MUSB_FRAME:
+ return writew(data, addr + SUNXI_MUSB_FRAME);
+ case MUSB_TXFIFOADD:
+ return writew(data, addr + SUNXI_MUSB_TXFIFOADD);
+ case MUSB_RXFIFOADD:
+ return writew(data, addr + SUNXI_MUSB_RXFIFOADD);
+ default:
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown writew offset %u\n", offset);
+ return;
+ }
+ } else if (addr == (sunxi_musb->mregs + 0x80)) {
+ /* ep control reg access */
+ return writew(data, addr + offset);
+ }
+
+ dev_err(sunxi_musb->controller->parent,
+ "Error unknown writew at 0x%x bytes offset\n",
+ (int)(addr - sunxi_musb->mregs));
+}
+
+static const struct musb_platform_ops sunxi_musb_ops = {
+ .quirks = MUSB_INDEXED_EP,
+ .init = sunxi_musb_init,
+ .exit = sunxi_musb_exit,
+ .enable = sunxi_musb_enable,
+ .disable = sunxi_musb_disable,
+ .fifo_offset = sunxi_musb_fifo_offset,
+ .ep_offset = sunxi_musb_ep_offset,
+ .busctl_offset = sunxi_musb_busctl_offset,
+ .readb = sunxi_musb_readb,
+ .writeb = sunxi_musb_writeb,
+ .readw = sunxi_musb_readw,
+ .writew = sunxi_musb_writew,
+ .set_vbus = sunxi_musb_set_vbus,
+ .pre_root_reset_end = sunxi_musb_pre_root_reset_end,
+ .post_root_reset_end = sunxi_musb_post_root_reset_end,
+};
+
+/* Allwinner OTG supports up to 5 endpoints */
+#define SUNXI_MUSB_MAX_EP_NUM 6
+#define SUNXI_MUSB_RAM_BITS 11
+
+static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = {
+ MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512),
+ MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512),
+ MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512),
+ MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512),
+ MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512),
+ MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512),
+ MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512),
+ MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512),
+ MUSB_EP_FIFO_SINGLE(5, FIFO_TX, 512),
+ MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512),
+};
+
+static struct musb_hdrc_config sunxi_musb_hdrc_config = {
+ .fifo_cfg = sunxi_musb_mode_cfg,
+ .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg),
+ .multipoint = true,
+ .dyn_fifo = true,
+ .soft_con = true,
+ .num_eps = SUNXI_MUSB_MAX_EP_NUM,
+ .ram_bits = SUNXI_MUSB_RAM_BITS,
+ .dma = 0,
+};
+
+static int sunxi_musb_probe(struct platform_device *pdev)
+{
+ struct musb_hdrc_platform_data pdata;
+ struct platform_device_info pinfo;
+ struct sunxi_glue *glue;
+ struct device_node *np = pdev->dev.of_node;
+ int ret;
+
+ if (!np) {
+ dev_err(&pdev->dev, "Error no device tree node found\n");
+ return -EINVAL;
+ }
+
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
+ if (!glue)
+ return -ENOMEM;
+
+ memset(&pdata, 0, sizeof(pdata));
+ switch (of_usb_get_dr_mode(np)) {
+#if defined CONFIG_USB_MUSB_DUAL_ROLE || defined CONFIG_USB_MUSB_HOST
+ case USB_DR_MODE_HOST:
+ pdata.mode = MUSB_PORT_MODE_HOST;
+ break;
+#endif
+#ifdef CONFIG_USB_MUSB_DUAL_ROLE
+ case USB_DR_MODE_OTG:
+ glue->extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
+ if (IS_ERR(glue->extcon)) {
+ if (PTR_ERR(glue->extcon) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_err(&pdev->dev, "Invalid or missing extcon\n");
+ return PTR_ERR(glue->extcon);
+ }
+ pdata.mode = MUSB_PORT_MODE_DUAL_ROLE;
+ break;
+#endif
+ default:
+ dev_err(&pdev->dev, "Invalid or missing 'dr_mode' property\n");
+ return -EINVAL;
+ }
+ pdata.platform_ops = &sunxi_musb_ops;
+ pdata.config = &sunxi_musb_hdrc_config;
+
+ glue->dev = &pdev->dev;
+ INIT_WORK(&glue->work, sunxi_musb_work);
+ glue->host_nb.notifier_call = sunxi_musb_host_notifier;
+
+ glue->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(glue->clk)) {
+ dev_err(&pdev->dev, "Error getting clock: %ld\n",
+ PTR_ERR(glue->clk));
+ return PTR_ERR(glue->clk);
+ }
+
+ glue->phy = devm_phy_get(&pdev->dev, "usb");
+ if (IS_ERR(glue->phy)) {
+ if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_err(&pdev->dev, "Error getting phy %ld\n",
+ PTR_ERR(glue->phy));
+ return PTR_ERR(glue->phy);
+ }
+
+ glue->usb_phy = usb_phy_generic_register();
+ if (IS_ERR(glue->usb_phy)) {
+ dev_err(&pdev->dev, "Error registering usb-phy %ld\n",
+ PTR_ERR(glue->usb_phy));
+ return PTR_ERR(glue->usb_phy);
+ }
+
+ glue->xceiv = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
+ if (IS_ERR(glue->xceiv)) {
+ ret = PTR_ERR(glue->xceiv);
+ dev_err(&pdev->dev, "Error getting usb-phy %d\n", ret);
+ goto err_unregister_usb_phy;
+ }
+
+ platform_set_drvdata(pdev, glue);
+
+ memset(&pinfo, 0, sizeof(pinfo));
+ pinfo.name = "musb-hdrc";
+ pinfo.id = PLATFORM_DEVID_AUTO;
+ pinfo.parent = &pdev->dev;
+ pinfo.res = pdev->resource;
+ pinfo.num_res = pdev->num_resources;
+ pinfo.data = &pdata;
+ pinfo.size_data = sizeof(pdata);
+
+ glue->musb = platform_device_register_full(&pinfo);
+ if (IS_ERR(glue->musb)) {
+ ret = PTR_ERR(glue->musb);
+ dev_err(&pdev->dev, "Error registering musb dev: %d\n", ret);
+ goto err_unregister_usb_phy;
+ }
+
+ return 0;
+
+err_unregister_usb_phy:
+ usb_phy_generic_unregister(glue->usb_phy);
+ return ret;
+}
+
+static int sunxi_musb_remove(struct platform_device *pdev)
+{
+ struct sunxi_glue *glue = platform_get_drvdata(pdev);
+ struct platform_device *usb_phy = glue->usb_phy;
+
+ platform_device_unregister(glue->musb); /* Frees glue ! */
+ usb_phy_generic_unregister(usb_phy);
+
+ return 0;
+}
+
+static const struct of_device_id sunxi_musb_match[] = {
+ { .compatible = "allwinner,sun4i-a10-musb", },
+ {}
+};
+
+static struct platform_driver sunxi_musb_driver = {
+ .probe = sunxi_musb_probe,
+ .remove = sunxi_musb_remove,
+ .driver = {
+ .name = "musb-sunxi",
+ .of_match_table = sunxi_musb_match,
+ },
+};
+module_platform_driver(sunxi_musb_driver);
+
+MODULE_DESCRIPTION("Allwinner sunxi MUSB Glue Layer");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL v2");

View file

@ -1,162 +0,0 @@
From 132e23775779cc895c37f7883c33a60a1a8a7cdd Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Wed, 8 Jul 2015 16:41:39 +0200
Subject: [PATCH] usb: musb: sunxi: Add support for musb controller in A31 SoC
The A31 SoC uses the same musb controller as found in earlier SoCs, but it
is hooked up slightly different. Its SRAM is private and no longer controlled
through the SRAM controller, and its reset is controlled via a separate
reset controller. This commit adds support for this setup.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
---
.../bindings/usb/allwinner,sun4i-a10-musb.txt | 3 +-
drivers/usb/musb/sunxi.c | 50 +++++++++++++++++++---
2 files changed, 46 insertions(+), 7 deletions(-)
--- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
+++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
@@ -2,9 +2,10 @@ Allwinner sun4i A10 musb DRC/OTG control
-------------------------------------------
Required properties:
- - compatible : "allwinner,sun4i-a10-musb"
+ - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb"
- reg : mmio address range of the musb controller
- clocks : clock specifier for the musb controller ahb gate clock
+ - reset : reset specifier for the ahb reset (A31 and newer only)
- interrupts : interrupt to which the musb controller is connected
- interrupt-names : must be "mc"
- phys : phy specifier for the otg phy
--- a/drivers/usb/musb/sunxi.c
+++ b/drivers/usb/musb/sunxi.c
@@ -26,6 +26,7 @@
#include <linux/of.h>
#include <linux/phy/phy-sun4i-usb.h>
#include <linux/platform_device.h>
+#include <linux/reset.h>
#include <linux/soc/sunxi/sunxi_sram.h>
#include <linux/usb/musb.h>
#include <linux/usb/of.h>
@@ -70,6 +71,8 @@
#define SUNXI_MUSB_FL_HOSTMODE_PEND 2
#define SUNXI_MUSB_FL_VBUS_ON 3
#define SUNXI_MUSB_FL_PHY_ON 4
+#define SUNXI_MUSB_FL_HAS_SRAM 5
+#define SUNXI_MUSB_FL_HAS_RESET 6
/* Our read/write methods need access and do not get passed in a musb ref :| */
static struct musb *sunxi_musb;
@@ -78,6 +81,7 @@ struct sunxi_glue {
struct device *dev;
struct platform_device *musb;
struct clk *clk;
+ struct reset_control *rst;
struct phy *phy;
struct platform_device *usb_phy;
struct usb_phy *xceiv;
@@ -229,14 +233,22 @@ static int sunxi_musb_init(struct musb *
musb->phy = glue->phy;
musb->xceiv = glue->xceiv;
- ret = sunxi_sram_claim(musb->controller->parent);
- if (ret)
- return ret;
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) {
+ ret = sunxi_sram_claim(musb->controller->parent);
+ if (ret)
+ return ret;
+ }
ret = clk_prepare_enable(glue->clk);
if (ret)
goto error_sram_release;
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
+ ret = reset_control_deassert(glue->rst);
+ if (ret)
+ goto error_clk_disable;
+ }
+
writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
/* Register notifier before calling phy_init() */
@@ -244,7 +256,7 @@ static int sunxi_musb_init(struct musb *
ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
if (ret)
- goto error_clk_disable;
+ goto error_reset_assert;
}
ret = phy_init(glue->phy);
@@ -273,10 +285,14 @@ error_unregister_notifier:
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
+error_reset_assert:
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
+ reset_control_assert(glue->rst);
error_clk_disable:
clk_disable_unprepare(glue->clk);
error_sram_release:
- sunxi_sram_release(musb->controller->parent);
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
+ sunxi_sram_release(musb->controller->parent);
return ret;
}
@@ -296,8 +312,12 @@ static int sunxi_musb_exit(struct musb *
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
&glue->host_nb);
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
+ reset_control_assert(glue->rst);
+
clk_disable_unprepare(glue->clk);
- sunxi_sram_release(musb->controller->parent);
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
+ sunxi_sram_release(musb->controller->parent);
return 0;
}
@@ -617,6 +637,12 @@ static int sunxi_musb_probe(struct platf
INIT_WORK(&glue->work, sunxi_musb_work);
glue->host_nb.notifier_call = sunxi_musb_host_notifier;
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
+ set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
+
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
+ set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
+
glue->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(glue->clk)) {
dev_err(&pdev->dev, "Error getting clock: %ld\n",
@@ -624,6 +650,17 @@ static int sunxi_musb_probe(struct platf
return PTR_ERR(glue->clk);
}
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
+ glue->rst = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(glue->rst)) {
+ if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_err(&pdev->dev, "Error getting reset %ld\n",
+ PTR_ERR(glue->rst));
+ return PTR_ERR(glue->rst);
+ }
+ }
+
glue->phy = devm_phy_get(&pdev->dev, "usb");
if (IS_ERR(glue->phy)) {
if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
@@ -685,6 +722,7 @@ static int sunxi_musb_remove(struct plat
static const struct of_device_id sunxi_musb_match[] = {
{ .compatible = "allwinner,sun4i-a10-musb", },
+ { .compatible = "allwinner,sun6i-a31-musb", },
{}
};

View file

@ -1,17 +0,0 @@
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -745,6 +745,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>;

View file

@ -1,34 +0,0 @@
From 56ba8c5814a859dd94667643a3bc22984efd1521 Mon Sep 17 00:00:00 2001
From: LABBE Corentin <clabbe.montjoie@gmail.com>
Date: Fri, 17 Jul 2015 16:39:38 +0200
Subject: [PATCH] ARM: sun4i: dt: Add Security System to A10 SoC DTS
The Security System is a hardware cryptographic accelerator that support
AES/MD5/SHA1/DES/3DES/PRNG algorithms.
It could be found on many Allwinner SoC.
This patch enable the Security System on the Allwinner A10 SoC Device-tree.
Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
arch/arm/boot/dts/sun4i-a10.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -591,6 +591,14 @@
status = "disabled";
};
+ crypto: crypto-engine@01c15000 {
+ compatible = "allwinner,sun4i-a10-crypto";
+ reg = <0x01c15000 0x1000>;
+ interrupts = <86>;
+ clocks = <&ahb_gates 5>, <&ss_clk>;
+ clock-names = "ahb", "mod";
+ };
+
spi2: spi@01c17000 {
compatible = "allwinner,sun4i-a10-spi";
reg = <0x01c17000 0x1000>;

File diff suppressed because it is too large Load diff

View file

@ -1,64 +0,0 @@
From e4127db9b980a5684c537d9010ed2aaa05a1e79a Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Sat, 24 May 2014 20:53:49 +0200
Subject: [PATCH] ARM: dts: sun7i: Add OOB irq support to boards with broadcom
sdio wifi
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
arch/arm/boot/dts/sun7i-a20-cubietruck.dts | 11 +++++++++++
arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts | 11 +++++++++++
2 files changed, 22 insertions(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -71,12 +71,23 @@
};
mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
};
usbphy: phy@01c13400 {
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -69,12 +69,23 @@
};
mmc3: mmc@01c12000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
pinctrl-names = "default";
pinctrl-0 = <&mmc3_pins_a>;
vmmc-supply = <&reg_vmmc3>;
bus-width = <4>;
non-removable;
status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <10 8>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
};
usbphy: phy@01c13400 {

View file

@ -1,75 +0,0 @@
From c6e2b7dad39a7887f935458d1c8de84db06243e1 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(+)
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -88,6 +88,20 @@
interrupts = <10 8>; /* PH10 / EINT10 */
interrupt-names = "host-wake";
};
+
+ 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>;
+ };
};
usbphy: phy@01c13400 {
@@ -171,6 +185,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>;
@@ -264,6 +284,22 @@
enable-active-high;
gpio = <&pio 7 9 GPIO_ACTIVE_HIGH>;
};
+
+ 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>;
+ };
+ };
};
#include "axp209.dtsi"

View file

@ -1,248 +0,0 @@
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -554,6 +554,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
+ sun7i-a20-lamobo-r1.dtb \
sun7i-a20-m3.dtb \
sun7i-a20-olinuxino-lime.dtb \
sun7i-a20-olinuxino-lime2.dtb \
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-lamobo-r1.dts
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2015 Daniel Golle <daniel@makrotopia.org>
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library 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 library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Lamobo R1";
+ compatible = "lamobo,lamobo-r1", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ spi0: spi@01c05000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>;
+ status = "okay";
+ };
+
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_lamobo>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 0>; /* PH10 */
+ cd-inverted;
+ 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";
+ };
+
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ mmc0_cd_pin_lamobo: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <0>;
+ allwinner,pull = <1>;
+ };
+
+ gmac_power_pin_lamobo: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_lamobo: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <1>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ 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";
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart3: serial@01c28c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_b>;
+ status = "okay";
+ };
+
+ uart7: serial@01c29c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ 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";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_lamobo>;
+
+ green {
+ label = "lamobo:green:usr";
+ gpios = <&pio 7 24 0>;
+ default-state = "on";
+ };
+ };
+
+ reg_ahci_5v: ahci-5v {
+ status = "okay";
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_lamobo>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 0>;
+ status = "okay";
+ };
+};