brcm2708: add linux 4.1 support

Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>

SVN-Revision: 46399
lede-17.01
John Crispin 2015-07-17 12:48:39 +00:00
parent 03b56c9350
commit 208ab54e3e
121 changed files with 139563 additions and 0 deletions

View File

@ -0,0 +1,352 @@
# CONFIG_AIO is not set
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_AMBA_PL08X is not set
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_BCM2708=y
# CONFIG_ARCH_BCM2709 is not set
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
CONFIG_ARCH_HIBERNATION_POSSIBLE=y
CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
CONFIG_ARCH_NR_GPIO=0
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
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_ARM=y
CONFIG_ARM_AMBA=y
# CONFIG_ARM_CPUIDLE is not set
CONFIG_ARM_CPU_SUSPEND=y
CONFIG_ARM_ERRATA_411920=y
CONFIG_ARM_L1_CACHE_SHIFT=5
# CONFIG_ARM_SP805_WATCHDOG is not set
CONFIG_ARM_THUMB=y
CONFIG_ARM_UNWIND=y
CONFIG_AVERAGE=y
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BCM2708_DT=y
CONFIG_BCM2708_GPIO=y
CONFIG_BCM2708_MBOX=y
# CONFIG_BCM2708_NOL2CACHE is not set
CONFIG_BCM2708_VCHIQ=y
CONFIG_BCM2708_VCMEM=y
# CONFIG_BCM2708_WDT is not set
CONFIG_BCM2835_MBOX=y
CONFIG_BCM2835_WDT=y
CONFIG_BCM_VCIO=y
CONFIG_BCM_VC_CMA=y
CONFIG_BCM_VC_SM=y
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_SD=y
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BUILD_BIN2C=y
# CONFIG_CACHE_L2X0 is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMA=y
CONFIG_CMA_ALIGNMENT=8
CONFIG_CMA_AREAS=7
# CONFIG_CMA_DEBUG is not set
# CONFIG_CMA_DEBUGFS is not set
CONFIG_CMA_SIZE_MBYTES=16
# CONFIG_CMA_SIZE_SEL_MAX is not set
CONFIG_CMA_SIZE_SEL_MBYTES=y
# CONFIG_CMA_SIZE_SEL_MIN is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
CONFIG_COMMON_CLK=y
CONFIG_CONFIGFS_FS=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_CPU_32v6=y
CONFIG_CPU_ABRT_EV6=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_CPU_CACHE_V6=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_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_PABRT_V6=y
CONFIG_CPU_PM=y
CONFIG_CPU_TLB_V6=y
CONFIG_CPU_V6=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
# 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_DEVTMPFS=y
CONFIG_DMADEVICES=y
CONFIG_DMA_BCM2708=y
CONFIG_DMA_BCM2708_LEGACY=y
CONFIG_DMA_CMA=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DNOTIFY=y
CONFIG_DTC=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FB=y
CONFIG_FB_BCM2708=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_CMDLINE=y
CONFIG_FIQ=y
CONFIG_FIRMWARE_IN_KERNEL=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FPE_FASTFPE is not set
# CONFIG_FPE_NWFPE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FREEZER=y
CONFIG_FS_MBCACHE=y
CONFIG_FS_POSIX_ACL=y
CONFIG_GENERIC_ALLOCATOR=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_IDLE_POLL_SETUP=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_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_BITREVERSE is not set
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=y
CONFIG_HAVE_ARCH_TRACEHOOK=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_BPF_JIT=y
CONFIG_HAVE_CC_STACKPROTECTOR=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_CLK_PREPARE=y
CONFIG_HAVE_CONTEXT_TRACKING=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DMA_ATTRS=y
CONFIG_HAVE_DMA_CONTIGUOUS=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_GENERIC_DMA_COHERENT=y
CONFIG_HAVE_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_LATENCYTOP_SUPPORT=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_SYSCALL_TRACEPOINTS=y
CONFIG_HAVE_UID16=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HW_CONSOLE=y
CONFIG_HZ_FIXED=0
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_INPUT=y
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_IOMMU_HELPER=y
CONFIG_IOSCHED_CFQ=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_JBD2=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_XZ is not set
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_TRIGGER_INPUT is not set
CONFIG_LIBFDT=y
CONFIG_LOGO=y
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
# CONFIG_LZ4_COMPRESS is not set
# CONFIG_LZ4_DECOMPRESS is not set
CONFIG_MACH_BCM2708=y
CONFIG_MAC_PARTITION=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAILBOX=y
CONFIG_MAX_RAW_DEVS=256
CONFIG_MEMORY_ISOLATION=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_BCM2835=y
CONFIG_MMC_BCM2835_DMA=y
CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
CONFIG_MMC_BCM2835_SDHOST=y
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD is not set
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_MACH_IO_H=y
CONFIG_NEED_MACH_MEMORY_H=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NLS=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NO_BOOTMEM=y
CONFIG_NO_HZ=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_OABI_COMPAT=y
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_NET=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI_DOMAINS_GENERIC is not set
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYS_OFFSET=0
CONFIG_PINCTRL=y
CONFIG_PINCTRL_BCM2835=y
# CONFIG_PL330_DMA is not set
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_POWER_SUPPLY=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_RAW_DRIVER=y
# CONFIG_RCU_EXPEDITE_BOOT is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_SCHED_HRTICK=y
CONFIG_SCSI=y
# CONFIG_SCSI_LOWLEVEL is not set
# CONFIG_SCSI_PROC_FS is not set
# CONFIG_SERIAL_8250_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=1
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
# CONFIG_SERIAL_AMBA_PL010 is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_SQUASHFS is not set
CONFIG_SRCU=y
# CONFIG_STAGING is not set
# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SWIOTLB=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TEXTSEARCH is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_BCM2835=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_OF=y
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_UEVENT_HELPER_PATH=""
# CONFIG_UID16 is not set
CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_COMMON=y
CONFIG_USB_DWCOTG=y
# CONFIG_USB_EHCI_HCD is not set
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_UAS=y
CONFIG_USB_USBNET=y
CONFIG_USE_OF=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VFP=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_WATCHDOG_CORE=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

View File

@ -0,0 +1,383 @@
# CONFIG_AIO is not set
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_AMBA_PL08X is not set
# CONFIG_APM_EMULATION is not set
# CONFIG_ARCH_BCM2708 is not set
CONFIG_ARCH_BCM2709=y
CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
CONFIG_ARCH_HAS_BARRIERS=y
CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
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_NR_GPIO=0
CONFIG_ARCH_REQUIRE_GPIOLIB=y
# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
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_ARM=y
CONFIG_ARM_AMBA=y
CONFIG_ARM_ARCH_TIMER=y
CONFIG_ARM_ARCH_TIMER_EVTSTREAM=y
# CONFIG_ARM_CPUIDLE is not set
CONFIG_ARM_CPU_SUSPEND=y
CONFIG_ARM_L1_CACHE_SHIFT=6
CONFIG_ARM_L1_CACHE_SHIFT_6=y
# CONFIG_ARM_LPAE is not set
# CONFIG_ARM_SP805_WATCHDOG is not set
CONFIG_ARM_THUMB=y
# CONFIG_ARM_THUMBEE is not set
CONFIG_ARM_UNWIND=y
CONFIG_ARM_VIRT_EXT=y
CONFIG_AVERAGE=y
# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BCM2708_GPIO=y
CONFIG_BCM2708_MBOX=y
CONFIG_BCM2708_NOL2CACHE=y
CONFIG_BCM2708_VCHIQ=y
CONFIG_BCM2708_VCMEM=y
# CONFIG_BCM2708_WDT is not set
CONFIG_BCM2709_DT=y
CONFIG_BCM2835_MBOX=y
CONFIG_BCM2835_WDT=y
CONFIG_BCM_VCIO=y
CONFIG_BCM_VC_CMA=y
CONFIG_BCM_VC_SM=y
# CONFIG_BLK_DEV_INITRD is not set
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
CONFIG_BLK_DEV_SD=y
CONFIG_BRCM_CHAR_DRIVERS=y
CONFIG_BUILD_BIN2C=y
# CONFIG_CACHE_L2X0 is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CLKSRC_OF=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_CMA=y
CONFIG_CMA_ALIGNMENT=8
CONFIG_CMA_AREAS=7
# CONFIG_CMA_DEBUG is not set
# CONFIG_CMA_DEBUGFS is not set
CONFIG_CMA_SIZE_MBYTES=16
# CONFIG_CMA_SIZE_SEL_MAX is not set
CONFIG_CMA_SIZE_SEL_MBYTES=y
# CONFIG_CMA_SIZE_SEL_MIN is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
CONFIG_COMMON_CLK=y
CONFIG_CONFIGFS_FS=y
CONFIG_CONSOLE_TRANSLATIONS=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_IDLE=y
CONFIG_CPU_IDLE_GOV_LADDER=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_PABRT_V7=y
CONFIG_CPU_PM=y
CONFIG_CPU_RMAP=y
CONFIG_CPU_TLB_V7=y
CONFIG_CPU_V7=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_DCACHE_WORD_ACCESS=y
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S"
# 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_DEVTMPFS=y
CONFIG_DMADEVICES=y
CONFIG_DMA_BCM2708=y
CONFIG_DMA_BCM2708_LEGACY=y
CONFIG_DMA_CMA=y
CONFIG_DMA_ENGINE=y
CONFIG_DMA_OF=y
CONFIG_DMA_VIRTUAL_CHANNELS=y
CONFIG_DNOTIFY=y
CONFIG_DTC=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_ENABLE_MUST_CHECK=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
CONFIG_FB=y
CONFIG_FB_BCM2708=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_IMAGEBLIT=y
CONFIG_FB_CMDLINE=y
CONFIG_FIQ=y
CONFIG_FIRMWARE_IN_KERNEL=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=y
CONFIG_FONT_SUPPORT=y
# CONFIG_FPE_FASTFPE is not set
# CONFIG_FPE_NWFPE is not set
CONFIG_FRAMEBUFFER_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
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_SHOW=y
CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GENERIC_PINCONF=y
CONFIG_GENERIC_SCHED_CLOCK=y
CONFIG_GENERIC_SMP_IDLE_THREAD=y
CONFIG_GENERIC_STRNCPY_FROM_USER=y
CONFIG_GENERIC_STRNLEN_USER=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_DEVRES=y
CONFIG_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_BITREVERSE=y
CONFIG_HAVE_ARCH_JUMP_LABEL=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=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_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_HOTPLUG_CPU=y
CONFIG_HW_CONSOLE=y
CONFIG_HZ_FIXED=0
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_INPUT=y
CONFIG_INPUT_MOUSEDEV=y
# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_IOMMU_HELPER=y
CONFIG_IOSCHED_CFQ=y
CONFIG_IRQCHIP=y
CONFIG_IRQ_DOMAIN=y
CONFIG_IRQ_FORCED_THREADING=y
CONFIG_IRQ_WORK=y
CONFIG_JBD2=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_XZ is not set
# CONFIG_LCD_CLASS_DEVICE is not set
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_TRIGGER_INPUT is not set
CONFIG_LIBFDT=y
CONFIG_LOCK_SPIN_ON_OWNER=y
CONFIG_LOGO=y
CONFIG_LOGO_LINUX_CLUT224=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
# CONFIG_LZ4_COMPRESS is not set
# CONFIG_LZ4_DECOMPRESS is not set
CONFIG_MACH_BCM2709=y
CONFIG_MAC_PARTITION=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_MAILBOX=y
CONFIG_MAX_RAW_DEVS=256
CONFIG_MEMORY_ISOLATION=y
CONFIG_MIGHT_HAVE_CACHE_L2X0=y
CONFIG_MIGRATION=y
CONFIG_MMC=y
CONFIG_MMC_BCM2835=y
CONFIG_MMC_BCM2835_DMA=y
CONFIG_MMC_BCM2835_PIO_DMA_BARRIER=2
CONFIG_MMC_BCM2835_SDHOST=y
CONFIG_MMC_BLOCK=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MTD is not set
CONFIG_MUTEX_SPIN_ON_OWNER=y
CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_NEED_MACH_IO_H=y
CONFIG_NEED_MACH_MEMORY_H=y
CONFIG_NEON=y
CONFIG_NET_FLOW_LIMIT=y
CONFIG_NLS=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NO_BOOTMEM=y
CONFIG_NO_HZ=y
CONFIG_NO_HZ_COMMON=y
CONFIG_NO_HZ_IDLE=y
CONFIG_NR_CPUS=4
CONFIG_OABI_COMPAT=y
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_NET=y
CONFIG_OF_RESERVED_MEM=y
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0x80000000
# CONFIG_PCI_DOMAINS_GENERIC is not set
# CONFIG_PCI_SYSCALL is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PHYS_OFFSET=0
CONFIG_PINCTRL=y
CONFIG_PINCTRL_BCM2835=y
# CONFIG_PL330_DMA is not set
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_PM_SLEEP_SMP=y
CONFIG_POWER_SUPPLY=y
CONFIG_PRINTK_TIME=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_RAW_DRIVER=y
# CONFIG_RCU_EXPEDITE_BOOT is not set
CONFIG_RCU_STALL_COMMON=y
CONFIG_RFS_ACCEL=y
CONFIG_RPS=y
CONFIG_RWSEM_SPIN_ON_OWNER=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_SCHED_HRTICK=y
CONFIG_SCSI=y
# CONFIG_SCSI_LOWLEVEL is not set
# CONFIG_SCSI_PROC_FS is not set
# CONFIG_SERIAL_8250_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=1
CONFIG_SERIAL_8250_RUNTIME_UARTS=0
# CONFIG_SERIAL_AMBA_PL010 is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SMP=y
CONFIG_SMP_ON_UP=y
# CONFIG_SQUASHFS is not set
CONFIG_SRCU=y
# CONFIG_STAGING is not set
CONFIG_STOP_MACHINE=y
# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SWIOTLB=y
CONFIG_SWP_EMULATE=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TEXTSEARCH is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_BCM2835=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_OF=y
# CONFIG_THUMB2_KERNEL is not set
CONFIG_TICK_CPU_ACCOUNTING=y
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_TREE_RCU=y
CONFIG_UEVENT_HELPER_PATH=""
# CONFIG_UID16 is not set
CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h"
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_COMMON=y
CONFIG_USB_DWCOTG=y
# CONFIG_USB_EHCI_HCD is not set
CONFIG_USB_NET_DRIVERS=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_UAS=y
CONFIG_USB_USBNET=y
CONFIG_USE_OF=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VFP=y
CONFIG_VFPv3=y
CONFIG_VMSPLIT_2G=y
# CONFIG_VMSPLIT_3G is not set
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_WATCHDOG_CORE=y
CONFIG_XPS=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,615 @@
From eef200f75c4a6f6701f1693f8f59ab2c83d1abcd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 8 Oct 2014 18:50:05 +0100
Subject: [PATCH 002/121] Add bcm2708_gpio driver
Signed-off-by: popcornmix <popcornmix@gmail.com>
bcm2708: Add extension to configure internal pulls
The bcm2708 gpio controller supports internal pulls to be used as pull-up,
pull-down or being entirely disabled. As it can be useful for a driver to
change the pull configuration from it's default pull-down state, add an
extension which allows configuring the pull per gpio.
Signed-off-by: Julian Scheel <julian@jusst.de>
bcm2708-gpio: Revert the use of pinctrl_request_gpio
In non-DT systems, pinctrl_request_gpio always fails causing
"requests probe deferral" messages. In DT systems, it isn't useful
because the reference counting is independent of the normal pinctrl
pin reservations.
gpio: Only clear the currently occurring interrupt. Avoids losing interrupts
See: linux #760
bcm2708_gpio: Avoid calling irq_unmask for all interrupts
When setting up the interrupts, specify that the handle_simple_irq
handler should be used. This leaves interrupt acknowledgement to
the caller, and prevents irq_unmask from being called for all
interrupts.
Issue: linux #760
---
arch/arm/mach-bcm2708/Kconfig | 8 +
arch/arm/mach-bcm2708/Makefile | 1 +
arch/arm/mach-bcm2708/bcm2708.c | 25 ++
arch/arm/mach-bcm2708/bcm2708_gpio.c | 426 ++++++++++++++++++++++++++++++
arch/arm/mach-bcm2708/include/mach/gpio.h | 17 ++
arch/arm/mach-bcm2709/bcm2709.c | 25 ++
include/linux/platform_data/bcm2708.h | 23 ++
7 files changed, 525 insertions(+)
create mode 100644 arch/arm/mach-bcm2708/bcm2708_gpio.c
create mode 100644 arch/arm/mach-bcm2708/include/mach/gpio.h
create mode 100644 include/linux/platform_data/bcm2708.h
--- a/arch/arm/mach-bcm2708/Kconfig
+++ b/arch/arm/mach-bcm2708/Kconfig
@@ -20,6 +20,14 @@ config BCM2708_DT
help
Enable Device Tree support for BCM2708
+config BCM2708_GPIO
+ bool "BCM2708 gpio support"
+ depends on MACH_BCM2708
+ select ARCH_REQUIRE_GPIOLIB
+ default y
+ help
+ Include support for the Broadcom(R) BCM2708 gpio.
+
config BCM2708_NOL2CACHE
bool "Videocore L2 cache disable"
depends on MACH_BCM2708
--- a/arch/arm/mach-bcm2708/Makefile
+++ b/arch/arm/mach-bcm2708/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_MACH_BCM2708) += bcm2708.o armctrl.o
+obj-$(CONFIG_BCM2708_GPIO) += bcm2708_gpio.o
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -298,6 +298,31 @@ static struct platform_device bcm2708_vc
},
};
+#ifdef CONFIG_BCM2708_GPIO
+#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
+
+static struct resource bcm2708_gpio_resources[] = {
+ [0] = { /* general purpose I/O */
+ .start = GPIO_BASE,
+ .end = GPIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 gpio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+
+static struct platform_device bcm2708_gpio_device = {
+ .name = BCM_GPIO_DRIVER_NAME,
+ .id = -1, /* only one VideoCore I/O area */
+ .resource = bcm2708_gpio_resources,
+ .num_resources = ARRAY_SIZE(bcm2708_gpio_resources),
+ .dev = {
+ .dma_mask = &gpio_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
+ },
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
--- /dev/null
+++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c
@@ -0,0 +1,426 @@
+/*
+ * linux/arch/arm/mach-bcm2708/bcm2708_gpio.c
+ *
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <mach/gpio.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <mach/platform.h>
+#include <linux/pinctrl/consumer.h>
+
+#include <linux/platform_data/bcm2708.h>
+
+#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
+#define DRIVER_NAME BCM_GPIO_DRIVER_NAME
+#define BCM_GPIO_USE_IRQ 1
+
+#define GPIOFSEL(x) (0x00+(x)*4)
+#define GPIOSET(x) (0x1c+(x)*4)
+#define GPIOCLR(x) (0x28+(x)*4)
+#define GPIOLEV(x) (0x34+(x)*4)
+#define GPIOEDS(x) (0x40+(x)*4)
+#define GPIOREN(x) (0x4c+(x)*4)
+#define GPIOFEN(x) (0x58+(x)*4)
+#define GPIOHEN(x) (0x64+(x)*4)
+#define GPIOLEN(x) (0x70+(x)*4)
+#define GPIOAREN(x) (0x7c+(x)*4)
+#define GPIOAFEN(x) (0x88+(x)*4)
+#define GPIOUD(x) (0x94+(x)*4)
+#define GPIOUDCLK(x) (0x98+(x)*4)
+
+#define GPIO_BANKS 2
+
+enum { GPIO_FSEL_INPUT, GPIO_FSEL_OUTPUT,
+ GPIO_FSEL_ALT5, GPIO_FSEL_ALT_4,
+ GPIO_FSEL_ALT0, GPIO_FSEL_ALT1,
+ GPIO_FSEL_ALT2, GPIO_FSEL_ALT3,
+};
+
+ /* Each of the two spinlocks protects a different set of hardware
+ * regiters and data structurs. This decouples the code of the IRQ from
+ * the GPIO code. This also makes the case of a GPIO routine call from
+ * the IRQ code simpler.
+ */
+static DEFINE_SPINLOCK(lock); /* GPIO registers */
+
+struct bcm2708_gpio {
+ struct list_head list;
+ void __iomem *base;
+ struct gpio_chip gc;
+ unsigned long rising[(BCM2708_NR_GPIOS + 31) / 32];
+ unsigned long falling[(BCM2708_NR_GPIOS + 31) / 32];
+ unsigned long high[(BCM2708_NR_GPIOS + 31) / 32];
+ unsigned long low[(BCM2708_NR_GPIOS + 31) / 32];
+};
+
+static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset,
+ int function)
+{
+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
+ unsigned long flags;
+ unsigned gpiodir;
+ unsigned gpio_bank = offset / 10;
+ unsigned gpio_field_offset = (offset - 10 * gpio_bank) * 3;
+
+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set_function %p (%d,%d)\n", gc, offset, function);
+ if (offset >= BCM2708_NR_GPIOS)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lock, flags);
+
+ gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
+ gpiodir &= ~(7 << gpio_field_offset);
+ gpiodir |= function << gpio_field_offset;
+ writel(gpiodir, gpio->base + GPIOFSEL(gpio_bank));
+ spin_unlock_irqrestore(&lock, flags);
+ gpiodir = readl(gpio->base + GPIOFSEL(gpio_bank));
+
+ return 0;
+}
+
+static int bcm2708_gpio_dir_in(struct gpio_chip *gc, unsigned offset)
+{
+ return bcm2708_set_function(gc, offset, GPIO_FSEL_INPUT);
+}
+
+static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
+static int bcm2708_gpio_dir_out(struct gpio_chip *gc, unsigned offset,
+ int value)
+{
+ int ret;
+ ret = bcm2708_set_function(gc, offset, GPIO_FSEL_OUTPUT);
+ if (ret >= 0)
+ bcm2708_gpio_set(gc, offset, value);
+ return ret;
+}
+
+static int bcm2708_gpio_get(struct gpio_chip *gc, unsigned offset)
+{
+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
+ unsigned gpio_bank = offset / 32;
+ unsigned gpio_field_offset = (offset - 32 * gpio_bank);
+ unsigned lev;
+
+ if (offset >= BCM2708_NR_GPIOS)
+ return 0;
+ lev = readl(gpio->base + GPIOLEV(gpio_bank));
+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_get %p (%d)=%d\n", gc, offset, 0x1 & (lev>>gpio_field_offset));
+ return 0x1 & (lev >> gpio_field_offset);
+}
+
+static void bcm2708_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
+{
+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
+ unsigned gpio_bank = offset / 32;
+ unsigned gpio_field_offset = (offset - 32 * gpio_bank);
+//printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_set %p (%d=%d)\n", gc, offset, value);
+ if (offset >= BCM2708_NR_GPIOS)
+ return;
+ if (value)
+ writel(1 << gpio_field_offset, gpio->base + GPIOSET(gpio_bank));
+ else
+ writel(1 << gpio_field_offset, gpio->base + GPIOCLR(gpio_bank));
+}
+
+/**********************
+ * extension to configure pullups
+ */
+int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
+ bcm2708_gpio_pull_t value)
+{
+ struct bcm2708_gpio *gpio = container_of(gc, struct bcm2708_gpio, gc);
+ unsigned gpio_bank = offset / 32;
+ unsigned gpio_field_offset = (offset - 32 * gpio_bank);
+
+ if (offset >= BCM2708_NR_GPIOS)
+ return -EINVAL;
+
+ switch (value) {
+ case BCM2708_PULL_UP:
+ writel(2, gpio->base + GPIOUD(0));
+ break;
+ case BCM2708_PULL_DOWN:
+ writel(1, gpio->base + GPIOUD(0));
+ break;
+ case BCM2708_PULL_OFF:
+ writel(0, gpio->base + GPIOUD(0));
+ break;
+ }
+
+ udelay(5);
+ writel(1 << gpio_field_offset, gpio->base + GPIOUDCLK(gpio_bank));
+ udelay(5);
+ writel(0, gpio->base + GPIOUD(0));
+ writel(0 << gpio_field_offset, gpio->base + GPIOUDCLK(gpio_bank));
+
+ return 0;
+}
+EXPORT_SYMBOL(bcm2708_gpio_setpull);
+
+/*************************************************************************************************************************
+ * bcm2708 GPIO IRQ
+ */
+
+#if BCM_GPIO_USE_IRQ
+
+static int bcm2708_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+ return gpio_to_irq(gpio);
+}
+
+static int bcm2708_gpio_irq_set_type(struct irq_data *d, unsigned type)
+{
+ unsigned irq = d->irq;
+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
+ unsigned gn = irq_to_gpio(irq);
+ unsigned gb = gn / 32;
+ unsigned go = gn % 32;
+
+ gpio->rising[gb] &= ~(1 << go);
+ gpio->falling[gb] &= ~(1 << go);
+ gpio->high[gb] &= ~(1 << go);
+ gpio->low[gb] &= ~(1 << go);
+
+ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
+ return -EINVAL;
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ gpio->rising[gb] |= (1 << go);
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ gpio->falling[gb] |= (1 << go);
+ if (type & IRQ_TYPE_LEVEL_HIGH)
+ gpio->high[gb] |= (1 << go);
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ gpio->low[gb] |= (1 << go);
+ return 0;
+}
+
+static void bcm2708_gpio_irq_mask(struct irq_data *d)
+{
+ unsigned irq = d->irq;
+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
+ unsigned gn = irq_to_gpio(irq);
+ unsigned gb = gn / 32;
+ unsigned long rising = readl(gpio->base + GPIOREN(gb));
+ unsigned long falling = readl(gpio->base + GPIOFEN(gb));
+ unsigned long high = readl(gpio->base + GPIOHEN(gb));
+ unsigned long low = readl(gpio->base + GPIOLEN(gb));
+
+ gn = gn % 32;
+
+ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb));
+ writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb));
+ writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb));
+ writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb));
+}
+
+static void bcm2708_gpio_irq_unmask(struct irq_data *d)
+{
+ unsigned irq = d->irq;
+ struct bcm2708_gpio *gpio = irq_get_chip_data(irq);
+ unsigned gn = irq_to_gpio(irq);
+ unsigned gb = gn / 32;
+ unsigned go = gn % 32;
+ unsigned long rising = readl(gpio->base + GPIOREN(gb));
+ unsigned long falling = readl(gpio->base + GPIOFEN(gb));
+ unsigned long high = readl(gpio->base + GPIOHEN(gb));
+ unsigned long low = readl(gpio->base + GPIOLEN(gb));
+
+ if (gpio->rising[gb] & (1 << go)) {
+ writel(rising | (1 << go), gpio->base + GPIOREN(gb));
+ } else {
+ writel(rising & ~(1 << go), gpio->base + GPIOREN(gb));
+ }
+
+ if (gpio->falling[gb] & (1 << go)) {
+ writel(falling | (1 << go), gpio->base + GPIOFEN(gb));
+ } else {
+ writel(falling & ~(1 << go), gpio->base + GPIOFEN(gb));
+ }
+
+ if (gpio->high[gb] & (1 << go)) {
+ writel(high | (1 << go), gpio->base + GPIOHEN(gb));
+ } else {
+ writel(high & ~(1 << go), gpio->base + GPIOHEN(gb));
+ }
+
+ if (gpio->low[gb] & (1 << go)) {
+ writel(low | (1 << go), gpio->base + GPIOLEN(gb));
+ } else {
+ writel(low & ~(1 << go), gpio->base + GPIOLEN(gb));
+ }
+}
+
+static struct irq_chip bcm2708_irqchip = {
+ .name = "GPIO",
+ .irq_enable = bcm2708_gpio_irq_unmask,
+ .irq_disable = bcm2708_gpio_irq_mask,
+ .irq_unmask = bcm2708_gpio_irq_unmask,
+ .irq_mask = bcm2708_gpio_irq_mask,
+ .irq_set_type = bcm2708_gpio_irq_set_type,
+};
+
+static irqreturn_t bcm2708_gpio_interrupt(int irq, void *dev_id)
+{
+ unsigned long edsr;
+ unsigned bank;
+ int i;
+ unsigned gpio;
+ unsigned level_bits;
+ struct bcm2708_gpio *gpio_data = dev_id;
+
+ for (bank = 0; bank < GPIO_BANKS; bank++) {
+ edsr = readl(__io_address(GPIO_BASE) + GPIOEDS(bank));
+ level_bits = gpio_data->high[bank] | gpio_data->low[bank];
+
+ for_each_set_bit(i, &edsr, 32) {
+ gpio = i + bank * 32;
+ /* ack edge triggered IRQs immediately */
+ if (!(level_bits & (1<<i)))
+ writel(1<<i,
+ __io_address(GPIO_BASE) + GPIOEDS(bank));
+ generic_handle_irq(gpio_to_irq(gpio));
+ /* ack level triggered IRQ after handling them */
+ if (level_bits & (1<<i))
+ writel(1<<i,
+ __io_address(GPIO_BASE) + GPIOEDS(bank));
+ }
+ }
+ return IRQ_HANDLED;
+}
+
+static struct irqaction bcm2708_gpio_irq = {
+ .name = "BCM2708 GPIO catchall handler",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = bcm2708_gpio_interrupt,
+};
+
+static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
+{
+ unsigned irq;
+
+ ucb->gc.to_irq = bcm2708_gpio_to_irq;
+
+ for (irq = GPIO_IRQ_START; irq < (GPIO_IRQ_START + GPIO_IRQS); irq++) {
+ irq_set_chip_data(irq, ucb);
+ irq_set_chip_and_handler(irq, &bcm2708_irqchip,
+ handle_simple_irq);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+ bcm2708_gpio_irq.dev_id = ucb;
+ setup_irq(IRQ_GPIO3, &bcm2708_gpio_irq);
+}
+
+#else
+
+static void bcm2708_gpio_irq_init(struct bcm2708_gpio *ucb)
+{
+}
+
+#endif /* #if BCM_GPIO_USE_IRQ ***************************************************************************************************************** */
+
+static int bcm2708_gpio_probe(struct platform_device *dev)
+{
+ struct bcm2708_gpio *ucb;
+ struct resource *res;
+ int bank;
+ int err = 0;
+
+ printk(KERN_INFO DRIVER_NAME ": bcm2708_gpio_probe %p\n", dev);
+
+ ucb = kzalloc(sizeof(*ucb), GFP_KERNEL);
+ if (NULL == ucb) {
+ printk(KERN_ERR DRIVER_NAME ": failed to allocate "
+ "mailbox memory\n");
+ err = -ENOMEM;
+ goto err;
+ }
+
+ res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+
+ platform_set_drvdata(dev, ucb);
+ ucb->base = __io_address(GPIO_BASE);
+
+ ucb->gc.label = "bcm2708_gpio";
+ ucb->gc.base = 0;
+ ucb->gc.ngpio = BCM2708_NR_GPIOS;
+ ucb->gc.owner = THIS_MODULE;
+
+ ucb->gc.direction_input = bcm2708_gpio_dir_in;
+ ucb->gc.direction_output = bcm2708_gpio_dir_out;
+ ucb->gc.get = bcm2708_gpio_get;
+ ucb->gc.set = bcm2708_gpio_set;
+ ucb->gc.can_sleep = 0;
+
+ for (bank = 0; bank < GPIO_BANKS; bank++) {
+ writel(0, ucb->base + GPIOREN(bank));
+ writel(0, ucb->base + GPIOFEN(bank));
+ writel(0, ucb->base + GPIOHEN(bank));
+ writel(0, ucb->base + GPIOLEN(bank));
+ writel(0, ucb->base + GPIOAREN(bank));
+ writel(0, ucb->base + GPIOAFEN(bank));
+ writel(~0, ucb->base + GPIOEDS(bank));
+ }
+
+ bcm2708_gpio_irq_init(ucb);
+
+ err = gpiochip_add(&ucb->gc);
+
+err:
+ return err;
+
+}
+
+static int bcm2708_gpio_remove(struct platform_device *dev)
+{
+ int err = 0;
+ struct bcm2708_gpio *ucb = platform_get_drvdata(dev);
+
+ printk(KERN_ERR DRIVER_NAME ": bcm2708_gpio_remove %p\n", dev);
+
+ gpiochip_remove(&ucb->gc);
+
+ platform_set_drvdata(dev, NULL);
+ kfree(ucb);
+
+ return err;
+}
+
+static struct platform_driver bcm2708_gpio_driver = {
+ .probe = bcm2708_gpio_probe,
+ .remove = bcm2708_gpio_remove,
+ .driver = {
+ .name = "bcm2708_gpio"},
+};
+
+static int __init bcm2708_gpio_init(void)
+{
+ return platform_driver_register(&bcm2708_gpio_driver);
+}
+
+static void __exit bcm2708_gpio_exit(void)
+{
+ platform_driver_unregister(&bcm2708_gpio_driver);
+}
+
+module_init(bcm2708_gpio_init);
+module_exit(bcm2708_gpio_exit);
+
+MODULE_DESCRIPTION("Broadcom BCM2708 GPIO driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/arch/arm/mach-bcm2708/include/mach/gpio.h
@@ -0,0 +1,17 @@
+/*
+ * arch/arm/mach-bcm2708/include/mach/gpio.h
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#define BCM2708_NR_GPIOS 54 // number of gpio lines
+
+#define gpio_to_irq(x) ((x) + GPIO_IRQ_START)
+#define irq_to_gpio(x) ((x) - GPIO_IRQ_START)
+
+#endif
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -329,6 +329,31 @@ static struct platform_device bcm2708_vc
},
};
+#ifdef CONFIG_BCM2708_GPIO
+#define BCM_GPIO_DRIVER_NAME "bcm2708_gpio"
+
+static struct resource bcm2708_gpio_resources[] = {
+ [0] = { /* general purpose I/O */
+ .start = GPIO_BASE,
+ .end = GPIO_BASE + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static u64 gpio_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+
+static struct platform_device bcm2708_gpio_device = {
+ .name = BCM_GPIO_DRIVER_NAME,
+ .id = -1, /* only one VideoCore I/O area */
+ .resource = bcm2708_gpio_resources,
+ .num_resources = ARRAY_SIZE(bcm2708_gpio_resources),
+ .dev = {
+ .dma_mask = &gpio_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON),
+ },
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
--- /dev/null
+++ b/include/linux/platform_data/bcm2708.h
@@ -0,0 +1,23 @@
+/*
+ * include/linux/platform_data/bcm2708.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * (C) 2014 Julian Scheel <julian@jusst.de>
+ *
+ */
+#ifndef __BCM2708_H_
+#define __BCM2708_H_
+
+typedef enum {
+ BCM2708_PULL_OFF,
+ BCM2708_PULL_UP,
+ BCM2708_PULL_DOWN
+} bcm2708_gpio_pull_t;
+
+extern int bcm2708_gpio_setpull(struct gpio_chip *gc, unsigned offset,
+ bcm2708_gpio_pull_t value);
+
+#endif

View File

@ -0,0 +1,623 @@
From 6f5003498da677a660cbdfaf9be78d3c0aff2e4c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 1 May 2015 19:11:03 +0200
Subject: [PATCH 003/121] mailbox: bcm2708: Add bcm2708-vcio
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: popcornmix <popcornmix@gmail.com>
Copy the arch vcio.c driver to drivers/mailbox.
This is done to make it available on ARCH_BCM2835.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
mailbox: bcm2708-vcio: Allocation does not need to be atomic
No need to do atomic allocation in a context that can sleep.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
mailbox: bcm2708-vcio: Check the correct status register before writing
With the VC reader blocked and the ARM writing, MAIL0_STA reads
empty permanently while MAIL1_STA goes from empty (0x40000000)
to non-empty (0x00000001-0x00000007) to full (0x80000008).
Suggested-by: Phil Elwell <phil@raspberrypi.org>
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
drivers/mailbox/Kconfig | 6 +
drivers/mailbox/Makefile | 2 +
drivers/mailbox/bcm2708-vcio.c | 427 ++++++++++++++++++++++++++
include/linux/platform_data/mailbox-bcm2708.h | 126 ++++++++
4 files changed, 561 insertions(+)
create mode 100644 drivers/mailbox/bcm2708-vcio.c
create mode 100644 include/linux/platform_data/mailbox-bcm2708.h
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -7,6 +7,12 @@ menuconfig MAILBOX
if MAILBOX
+config BCM2708_MBOX
+ bool "Broadcom BCM2708 Mailbox (vcio)"
+ depends on MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835
+ help
+ Broadcom BCM2708 Mailbox (vcio)
+
config ARM_MHU
tristate "ARM MHU Mailbox"
depends on ARM_AMBA
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -2,6 +2,8 @@
obj-$(CONFIG_MAILBOX) += mailbox.o
+obj-$(CONFIG_BCM2708_MBOX) += bcm2708-vcio.o
+
obj-$(CONFIG_ARM_MHU) += arm_mhu.o
obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
--- /dev/null
+++ b/drivers/mailbox/bcm2708-vcio.c
@@ -0,0 +1,427 @@
+/*
+ * linux/arch/arm/mach-bcm2708/vcio.c
+ *
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This device provides a shared mechanism for writing to the mailboxes,
+ * semaphores, doorbells etc. that are shared between the ARM and the
+ * VideoCore processor
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioctl.h>
+#include <linux/platform_data/mailbox-bcm2708.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+
+#define DRIVER_NAME "bcm2708_vcio"
+#define DEVICE_FILE_NAME "vcio"
+
+/* offsets from a mail box base address */
+#define MAIL0_RD 0x00 /* read - and next 4 words */
+#define MAIL0_POL 0x10 /* read without popping the fifo */
+#define MAIL0_SND 0x14 /* sender ID (bottom two bits) */
+#define MAIL0_STA 0x18 /* status */
+#define MAIL0_CNF 0x1C /* configuration */
+#define MAIL1_WRT 0x20 /* write - and next 4 words */
+#define MAIL1_STA 0x38 /* status */
+
+/* On MACH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
+#ifndef ARM_MS_EMPTY
+#define ARM_MS_EMPTY BIT(30)
+#define ARM_MS_FULL BIT(31)
+
+#define ARM_MC_IHAVEDATAIRQEN BIT(0)
+#endif
+
+#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
+#define MBOX_MSG_LSB(chan, data28) (((data28) << 4) | ((chan) & 0xf))
+#define MBOX_CHAN(msg) ((msg) & 0xf)
+#define MBOX_DATA28(msg) ((msg) & ~0xf)
+#define MBOX_DATA28_LSB(msg) (((uint32_t)msg) >> 4)
+
+#define MBOX_MAGIC 0xd0d0c0de
+
+#define MAJOR_NUM 100
+#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
+
+static struct class *vcio_class;
+
+struct vc_mailbox {
+ void __iomem *regs;
+ uint32_t msg[MBOX_CHAN_COUNT];
+ struct semaphore sema[MBOX_CHAN_COUNT];
+ uint32_t magic;
+};
+
+static void mbox_init(struct vc_mailbox *mbox_out)
+{
+ int i;
+
+ for (i = 0; i < MBOX_CHAN_COUNT; i++) {
+ mbox_out->msg[i] = 0;
+ sema_init(&mbox_out->sema[i], 0);
+ }
+
+ /* Enable the interrupt on data reception */
+ writel(ARM_MC_IHAVEDATAIRQEN, mbox_out->regs + MAIL0_CNF);
+
+ mbox_out->magic = MBOX_MAGIC;
+}
+
+static int mbox_write(struct vc_mailbox *mbox, unsigned chan, uint32_t data28)
+{
+ if (mbox->magic != MBOX_MAGIC)
+ return -EINVAL;
+
+ /* wait for the mailbox FIFO to have some space in it */
+ while (0 != (readl(mbox->regs + MAIL1_STA) & ARM_MS_FULL))
+ cpu_relax();
+
+ writel(MBOX_MSG(chan, data28), mbox->regs + MAIL1_WRT);
+
+ return 0;
+}
+
+static int mbox_read(struct vc_mailbox *mbox, unsigned chan, uint32_t *data28)
+{
+ if (mbox->magic != MBOX_MAGIC)
+ return -EINVAL;
+
+ down(&mbox->sema[chan]);
+ *data28 = MBOX_DATA28(mbox->msg[chan]);
+ mbox->msg[chan] = 0;
+
+ return 0;
+}
+
+static irqreturn_t mbox_irq_handler(int irq, void *dev_id)
+{
+ /* wait for the mailbox FIFO to have some data in it */
+ struct vc_mailbox *mbox = (struct vc_mailbox *)dev_id;
+ int status = readl(mbox->regs + MAIL0_STA);
+ int ret = IRQ_NONE;
+
+ while (!(status & ARM_MS_EMPTY)) {
+ uint32_t msg = readl(mbox->regs + MAIL0_RD);
+ int chan = MBOX_CHAN(msg);
+
+ if (chan < MBOX_CHAN_COUNT) {
+ if (mbox->msg[chan]) {
+ pr_err(DRIVER_NAME
+ ": mbox chan %d overflow - drop %08x\n",
+ chan, msg);
+ } else {
+ mbox->msg[chan] = (msg | 0xf);
+ up(&mbox->sema[chan]);
+ }
+ } else {
+ pr_err(DRIVER_NAME
+ ": invalid channel selector (msg %08x)\n", msg);
+ }
+ ret = IRQ_HANDLED;
+ status = readl(mbox->regs + MAIL0_STA);
+ }
+ return ret;
+}
+
+/* Mailbox Methods */
+
+static struct device *mbox_dev; /* we assume there's only one! */
+
+static int dev_mbox_write(struct device *dev, unsigned chan, uint32_t data28)
+{
+ struct vc_mailbox *mailbox = dev_get_drvdata(dev);
+ int rc;
+
+ device_lock(dev);
+ rc = mbox_write(mailbox, chan, data28);
+ device_unlock(dev);
+
+ return rc;
+}
+
+static int dev_mbox_read(struct device *dev, unsigned chan, uint32_t *data28)
+{
+ struct vc_mailbox *mailbox = dev_get_drvdata(dev);
+ int rc;
+
+ device_lock(dev);
+ rc = mbox_read(mailbox, chan, data28);
+ device_unlock(dev);
+
+ return rc;
+}
+
+extern int bcm_mailbox_write(unsigned chan, uint32_t data28)
+{
+ if (!mbox_dev)
+ return -ENODEV;
+
+ return dev_mbox_write(mbox_dev, chan, data28);
+}
+EXPORT_SYMBOL_GPL(bcm_mailbox_write);
+
+extern int bcm_mailbox_read(unsigned chan, uint32_t *data28)
+{
+ if (!mbox_dev)
+ return -ENODEV;
+
+ return dev_mbox_read(mbox_dev, chan, data28);
+}
+EXPORT_SYMBOL_GPL(bcm_mailbox_read);
+
+static int mbox_copy_from_user(void *dst, const void *src, int size)
+{
+ if ((uint32_t)src < TASK_SIZE)
+ return copy_from_user(dst, src, size);
+
+ memcpy(dst, src, size);
+
+ return 0;
+}
+
+static int mbox_copy_to_user(void *dst, const void *src, int size)
+{
+ if ((uint32_t)dst < TASK_SIZE)
+ return copy_to_user(dst, src, size);
+
+ memcpy(dst, src, size);
+
+ return 0;
+}
+
+static DEFINE_MUTEX(mailbox_lock);
+extern int bcm_mailbox_property(void *data, int size)
+{
+ uint32_t success;
+ dma_addr_t mem_bus; /* the memory address accessed from videocore */
+ void *mem_kern; /* the memory address accessed from driver */
+ int s = 0;
+
+ mutex_lock(&mailbox_lock);
+ /* allocate some memory for the messages communicating with GPU */
+ mem_kern = dma_alloc_coherent(NULL, PAGE_ALIGN(size), &mem_bus,
+ GFP_KERNEL);
+ if (mem_kern) {
+ /* create the message */
+ mbox_copy_from_user(mem_kern, data, size);
+
+ /* send the message */
+ wmb();
+ s = bcm_mailbox_write(MBOX_CHAN_PROPERTY, (uint32_t)mem_bus);
+ if (s == 0)
+ s = bcm_mailbox_read(MBOX_CHAN_PROPERTY, &success);
+ if (s == 0) {
+ /* copy the response */
+ rmb();
+ mbox_copy_to_user(data, mem_kern, size);
+ }
+ dma_free_coherent(NULL, PAGE_ALIGN(size), mem_kern, mem_bus);
+ } else {
+ s = -ENOMEM;
+ }
+ if (s != 0)
+ pr_err(DRIVER_NAME ": %s failed (%d)\n", __func__, s);
+
+ mutex_unlock(&mailbox_lock);
+ return s;
+}
+EXPORT_SYMBOL_GPL(bcm_mailbox_property);
+
+/* Platform Device for Mailbox */
+
+/*
+ * Is the device open right now? Used to prevent
+ * concurent access into the same device
+ */
+static bool device_is_open;
+
+/* This is called whenever a process attempts to open the device file */
+static int device_open(struct inode *inode, struct file *file)
+{
+ /* We don't want to talk to two processes at the same time */
+ if (device_is_open)
+ return -EBUSY;
+
+ device_is_open = true;
+ try_module_get(THIS_MODULE);
+
+ return 0;
+}
+
+static int device_release(struct inode *inode, struct file *file)
+{
+ /* We're now ready for our next caller */
+ device_is_open = false;
+
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+/*
+ * This function is called whenever a process tries to do an ioctl on our
+ * device file. We get two extra parameters (additional to the inode and file
+ * structures, which all device functions get): the number of the ioctl called
+ * and the parameter given to the ioctl function.
+ *
+ * If the ioctl is write or read/write (meaning output is returned to the
+ * calling process), the ioctl call returns the output of this function.
+ *
+ */
+static long device_ioctl(struct file *file, unsigned int ioctl_num,
+ unsigned long ioctl_param)
+{
+ unsigned size;
+
+ switch (ioctl_num) {
+ case IOCTL_MBOX_PROPERTY:
+ /*
+ * Receive a pointer to a message (in user space) and set that
+ * to be the device's message. Get the parameter given to
+ * ioctl by the process.
+ */
+ mbox_copy_from_user(&size, (void *)ioctl_param, sizeof(size));
+ return bcm_mailbox_property((void *)ioctl_param, size);
+ default:
+ pr_err(DRIVER_NAME "unknown ioctl: %d\n", ioctl_num);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* Module Declarations */
+
+/*
+ * This structure will hold the functions to be called
+ * when a process does something to the device we
+ * created. Since a pointer to this structure is kept in
+ * the devices table, it can't be local to
+ * init_module. NULL is for unimplemented functios.
+ */
+const struct file_operations fops = {
+ .unlocked_ioctl = device_ioctl,
+ .open = device_open,
+ .release = device_release, /* a.k.a. close */
+};
+
+static int bcm_vcio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *vdev;
+ struct vc_mailbox *mailbox;
+ struct resource *res;
+ int irq, ret;
+
+ mailbox = devm_kzalloc(dev, sizeof(*mailbox), GFP_KERNEL);
+ if (!mailbox)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mailbox->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mailbox->regs))
+ return PTR_ERR(mailbox->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, mbox_irq_handler,
+ IRQF_IRQPOLL,
+ dev_name(dev), mailbox);
+ if (ret) {
+ dev_err(dev, "Interrupt request failed %d\n", ret);
+ return ret;
+ }
+
+ ret = register_chrdev(MAJOR_NUM, DEVICE_FILE_NAME, &fops);
+ if (ret < 0) {
+ pr_err("Character device registration failed %d\n", ret);
+ return ret;
+ }
+
+ vcio_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(vcio_class)) {
+ ret = PTR_ERR(vcio_class);
+ pr_err("Class creation failed %d\n", ret);
+ goto err_class;
+ }
+
+ vdev = device_create(vcio_class, NULL, MKDEV(MAJOR_NUM, 0), NULL,
+ "vcio");
+ if (IS_ERR(vdev)) {
+ ret = PTR_ERR(vdev);
+ pr_err("Device creation failed %d\n", ret);
+ goto err_dev;
+ }
+
+ mbox_init(mailbox);
+ platform_set_drvdata(pdev, mailbox);
+ mbox_dev = dev;
+
+ dev_info(dev, "mailbox at %p\n", mailbox->regs);
+
+ return 0;
+
+err_dev:
+ class_destroy(vcio_class);
+err_class:
+ unregister_chrdev(MAJOR_NUM, DEVICE_FILE_NAME);
+
+ return ret;
+}
+
+static int bcm_vcio_remove(struct platform_device *pdev)
+{
+ mbox_dev = NULL;
+ platform_set_drvdata(pdev, NULL);
+ device_destroy(vcio_class, MKDEV(MAJOR_NUM, 0));
+ class_destroy(vcio_class);
+ unregister_chrdev(MAJOR_NUM, DEVICE_FILE_NAME);
+
+ return 0;
+}
+
+static const struct of_device_id bcm_vcio_of_match_table[] = {
+ { .compatible = "brcm,bcm2708-vcio", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm_vcio_of_match_table);
+
+static struct platform_driver bcm_mbox_driver = {
+ .probe = bcm_vcio_probe,
+ .remove = bcm_vcio_remove,
+
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm_vcio_of_match_table,
+ },
+};
+
+static int __init bcm_mbox_init(void)
+{
+ return platform_driver_register(&bcm_mbox_driver);
+}
+
+static void __exit bcm_mbox_exit(void)
+{
+ platform_driver_unregister(&bcm_mbox_driver);
+}
+
+arch_initcall(bcm_mbox_init); /* Initialize early */
+module_exit(bcm_mbox_exit);
+
+MODULE_AUTHOR("Gray Girling");
+MODULE_DESCRIPTION("ARM I/O to VideoCore processor");
+MODULE_LICENSE("GPL");
--- /dev/null
+++ b/include/linux/platform_data/mailbox-bcm2708.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2010 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _PLAT_MAILBOX_BCM2708_H
+#define _PLAT_MAILBOX_BCM2708_H
+
+/* Routines to handle I/O via the VideoCore "ARM control" registers
+ * (semaphores, doorbells, mailboxes)
+ */
+
+/* Constants shared with the ARM identifying separate mailbox channels */
+#define MBOX_CHAN_POWER 0 /* for use by the power management interface */
+#define MBOX_CHAN_FB 1 /* for use by the frame buffer */
+#define MBOX_CHAN_VCHIQ 3 /* for use by the VCHIQ interface */
+#define MBOX_CHAN_PROPERTY 8 /* for use by the property channel */
+#define MBOX_CHAN_COUNT 9
+
+enum {
+ VCMSG_PROCESS_REQUEST = 0x00000000
+};
+
+enum {
+ VCMSG_REQUEST_SUCCESSFUL = 0x80000000,
+ VCMSG_REQUEST_FAILED = 0x80000001
+};
+
+/* Mailbox property tags */
+enum {
+ VCMSG_PROPERTY_END = 0x00000000,
+ VCMSG_GET_FIRMWARE_REVISION = 0x00000001,
+ VCMSG_GET_BOARD_MODEL = 0x00010001,
+ VCMSG_GET_BOARD_REVISION = 0x00010002,
+ VCMSG_GET_BOARD_MAC_ADDRESS = 0x00010003,
+ VCMSG_GET_BOARD_SERIAL = 0x00010004,
+ VCMSG_GET_ARM_MEMORY = 0x00010005,
+ VCMSG_GET_VC_MEMORY = 0x00010006,
+ VCMSG_GET_CLOCKS = 0x00010007,
+ VCMSG_GET_COMMAND_LINE = 0x00050001,
+ VCMSG_GET_DMA_CHANNELS = 0x00060001,
+ VCMSG_GET_POWER_STATE = 0x00020001,
+ VCMSG_GET_TIMING = 0x00020002,
+ VCMSG_SET_POWER_STATE = 0x00028001,
+ VCMSG_GET_CLOCK_STATE = 0x00030001,
+ VCMSG_SET_CLOCK_STATE = 0x00038001,
+ VCMSG_GET_CLOCK_RATE = 0x00030002,
+ VCMSG_SET_CLOCK_RATE = 0x00038002,
+ VCMSG_GET_VOLTAGE = 0x00030003,
+ VCMSG_SET_VOLTAGE = 0x00038003,
+ VCMSG_GET_MAX_CLOCK = 0x00030004,
+ VCMSG_GET_MAX_VOLTAGE = 0x00030005,
+ VCMSG_GET_TEMPERATURE = 0x00030006,
+ VCMSG_GET_MIN_CLOCK = 0x00030007,
+ VCMSG_GET_MIN_VOLTAGE = 0x00030008,
+ VCMSG_GET_TURBO = 0x00030009,
+ VCMSG_GET_MAX_TEMPERATURE = 0x0003000a,
+ VCMSG_GET_STC = 0x0003000b,
+ VCMSG_SET_TURBO = 0x00038009,
+ VCMSG_SET_ALLOCATE_MEM = 0x0003000c,
+ VCMSG_SET_LOCK_MEM = 0x0003000d,
+ VCMSG_SET_UNLOCK_MEM = 0x0003000e,
+ VCMSG_SET_RELEASE_MEM = 0x0003000f,
+ VCMSG_SET_EXECUTE_CODE = 0x00030010,
+ VCMSG_SET_EXECUTE_QPU = 0x00030011,
+ VCMSG_SET_ENABLE_QPU = 0x00030012,
+ VCMSG_GET_RESOURCE_HANDLE = 0x00030014,
+ VCMSG_GET_EDID_BLOCK = 0x00030020,
+ VCMSG_GET_CUSTOMER_OTP = 0x00030021,
+ VCMSG_SET_CUSTOMER_OTP = 0x00038021,
+ VCMSG_SET_ALLOCATE_BUFFER = 0x00040001,
+ VCMSG_SET_RELEASE_BUFFER = 0x00048001,
+ VCMSG_SET_BLANK_SCREEN = 0x00040002,
+ VCMSG_TST_BLANK_SCREEN = 0x00044002,
+ VCMSG_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
+ VCMSG_TST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ VCMSG_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
+ VCMSG_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
+ VCMSG_TST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
+ VCMSG_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
+ VCMSG_GET_DEPTH = 0x00040005,
+ VCMSG_TST_DEPTH = 0x00044005,
+ VCMSG_SET_DEPTH = 0x00048005,
+ VCMSG_GET_PIXEL_ORDER = 0x00040006,
+ VCMSG_TST_PIXEL_ORDER = 0x00044006,
+ VCMSG_SET_PIXEL_ORDER = 0x00048006,
+ VCMSG_GET_ALPHA_MODE = 0x00040007,
+ VCMSG_TST_ALPHA_MODE = 0x00044007,
+ VCMSG_SET_ALPHA_MODE = 0x00048007,
+ VCMSG_GET_PITCH = 0x00040008,
+ VCMSG_TST_PITCH = 0x00044008,
+ VCMSG_SET_PITCH = 0x00048008,
+ VCMSG_GET_VIRTUAL_OFFSET = 0x00040009,
+ VCMSG_TST_VIRTUAL_OFFSET = 0x00044009,
+ VCMSG_SET_VIRTUAL_OFFSET = 0x00048009,
+ VCMSG_GET_OVERSCAN = 0x0004000a,
+ VCMSG_TST_OVERSCAN = 0x0004400a,
+ VCMSG_SET_OVERSCAN = 0x0004800a,
+ VCMSG_GET_PALETTE = 0x0004000b,
+ VCMSG_TST_PALETTE = 0x0004400b,
+ VCMSG_SET_PALETTE = 0x0004800b,
+ VCMSG_GET_LAYER = 0x0004000c,
+ VCMSG_TST_LAYER = 0x0004400c,
+ VCMSG_SET_LAYER = 0x0004800c,
+ VCMSG_GET_TRANSFORM = 0x0004000d,
+ VCMSG_TST_TRANSFORM = 0x0004400d,
+ VCMSG_SET_TRANSFORM = 0x0004800d,
+ VCMSG_TST_VSYNC = 0x0004400e,
+ VCMSG_SET_VSYNC = 0x0004800e,
+ VCMSG_SET_CURSOR_INFO = 0x00008010,
+ VCMSG_SET_CURSOR_STATE = 0x00008011,
+};
+
+int bcm_mailbox_read(unsigned chan, uint32_t *data28);
+int bcm_mailbox_write(unsigned chan, uint32_t data28);
+int bcm_mailbox_property(void *data, int size);
+
+#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,432 @@
From 70cf7eac2e13367cb8939741ee140c6bbac32f62 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 1 May 2013 19:54:32 +0100
Subject: [PATCH 005/121] bcm2708 watchdog driver
Signed-off-by: popcornmix <popcornmix@gmail.com>
---
drivers/watchdog/Kconfig | 8 +-
drivers/watchdog/Makefile | 1 +
drivers/watchdog/bcm2708_wdog.c | 382 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 390 insertions(+), 1 deletion(-)
create mode 100644 drivers/watchdog/bcm2708_wdog.c
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -451,6 +451,12 @@ config RETU_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called retu_wdt.
+config BCM2708_WDT
+ tristate "BCM2708 Watchdog"
+ depends on ARCH_BCM2708 || ARCH_BCM2709
+ help
+ Enables BCM2708 watchdog support.
+
config MOXART_WDT
tristate "MOXART watchdog"
depends on ARCH_MOXART
@@ -1225,7 +1231,7 @@ config BCM63XX_WDT
config BCM2835_WDT
tristate "Broadcom BCM2835 hardware watchdog"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
select WATCHDOG_CORE
help
Watchdog driver for the built in watchdog hardware in Broadcom
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_
obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
+obj-$(CONFIG_BCM2708_WDT) += bcm2708_wdog.o
obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
--- /dev/null
+++ b/drivers/watchdog/bcm2708_wdog.c
@@ -0,0 +1,382 @@
+/*
+ * Broadcom BCM2708 watchdog driver.
+ *
+ * (c) Copyright 2010 Broadcom Europe Ltd
+ *
+ * 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.
+ *
+ * BCM2708 watchdog driver. Loosely based on wdt driver.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <mach/platform.h>
+
+#define SECS_TO_WDOG_TICKS(x) ((x) << 16)
+#define WDOG_TICKS_TO_SECS(x) ((x) >> 16)
+
+static unsigned long wdog_is_open;
+static uint32_t wdog_ticks; /* Ticks to load into wdog timer */
+static char expect_close;
+
+/*
+ * Module parameters
+ */
+
+#define WD_TIMO 10 /* Default heartbeat = 60 seconds */
+static int heartbeat = WD_TIMO; /* Heartbeat in seconds */
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat in seconds. (0 < heartbeat < 65536, default="
+ __MODULE_STRING(WD_TIMO) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+static DEFINE_SPINLOCK(wdog_lock);
+
+/**
+ * Start the watchdog driver.
+ */
+
+static int wdog_start(unsigned long timeout)
+{
+ uint32_t cur;
+ unsigned long flags;
+ spin_lock_irqsave(&wdog_lock, flags);
+
+ /* enable the watchdog */
+ iowrite32(PM_PASSWORD | (timeout & PM_WDOG_TIME_SET),
+ __io_address(PM_WDOG));
+ cur = ioread32(__io_address(PM_RSTC));
+ iowrite32(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) |
+ PM_RSTC_WRCFG_FULL_RESET, __io_address(PM_RSTC));
+
+ spin_unlock_irqrestore(&wdog_lock, flags);
+ return 0;
+}
+
+/**
+ * Stop the watchdog driver.
+ */
+
+static int wdog_stop(void)
+{
+ iowrite32(PM_PASSWORD | PM_RSTC_RESET, __io_address(PM_RSTC));
+ printk(KERN_INFO "watchdog stopped\n");
+ return 0;
+}
+
+/**
+ * Reload counter one with the watchdog heartbeat. We don't bother
+ * reloading the cascade counter.
+ */
+
+static void wdog_ping(void)
+{
+ wdog_start(wdog_ticks);
+}
+
+/**
+ * @t: the new heartbeat value that needs to be set.
+ *
+ * Set a new heartbeat value for the watchdog device. If the heartbeat
+ * value is incorrect we keep the old value and return -EINVAL. If
+ * successful we return 0.
+ */
+
+static int wdog_set_heartbeat(int t)
+{
+ if (t < 1 || t > WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET))
+ return -EINVAL;
+
+ heartbeat = t;
+ wdog_ticks = SECS_TO_WDOG_TICKS(t);
+ return 0;
+}
+
+/**
+ * @file: file handle to the watchdog
+ * @buf: buffer to write (unused as data does not matter here
+ * @count: count of bytes
+ * @ppos: pointer to the position to write. No seeks allowed
+ *
+ * A write to a watchdog device is defined as a keepalive signal.
+ *
+ * if 'nowayout' is set then normally a close() is ignored. But
+ * if you write 'V' first then the close() will stop the timer.
+ */
+
+static ssize_t wdog_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != count; i++) {
+ char c;
+ if (get_user(c, buf + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ wdog_ping();
+ }
+ return count;
+}
+
+static int wdog_get_status(void)
+{
+ unsigned long flags;
+ int status = 0;
+ spin_lock_irqsave(&wdog_lock, flags);
+ /* FIXME: readback reset reason */
+ spin_unlock_irqrestore(&wdog_lock, flags);
+ return status;
+}
+
+static uint32_t wdog_get_remaining(void)
+{
+ uint32_t ret = ioread32(__io_address(PM_WDOG));
+ return ret & PM_WDOG_TIME_SET;
+}
+
+/**
+ * @file: file handle to the device
+ * @cmd: watchdog command
+ * @arg: argument pointer
+ *
+ * The watchdog API defines a common set of functions for all watchdogs
+ * according to their available features. We only actually usefully support
+ * querying capabilities and current status.
+ */
+
+static long wdog_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ int new_heartbeat;
+ int status;
+ int options;
+ uint32_t remaining;
+
+ struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT|
+ WDIOF_MAGICCLOSE|
+ WDIOF_KEEPALIVEPING,
+ .firmware_version = 1,
+ .identity = "BCM2708",
+ };
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ status = wdog_get_status();
+ return put_user(status, p);
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
+ case WDIOC_KEEPALIVE:
+ wdog_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+ if (wdog_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+ wdog_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+ case WDIOC_GETTIMELEFT:
+ remaining = WDOG_TICKS_TO_SECS(wdog_get_remaining());
+ return put_user(remaining, p);
+ case WDIOC_SETOPTIONS:
+ if (get_user(options, p))
+ return -EFAULT;
+ if (options & WDIOS_DISABLECARD)
+ wdog_stop();
+ if (options & WDIOS_ENABLECARD)
+ wdog_start(wdog_ticks);
+ return 0;
+ default:
+ return -ENOTTY;
+ }
+}
+
+/**
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ * The watchdog device has been opened. The watchdog device is single
+ * open and on opening we load the counters.
+ */
+
+static int wdog_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(0, &wdog_is_open))
+ return -EBUSY;
+ /*
+ * Activate
+ */
+ wdog_start(wdog_ticks);
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * @inode: inode to board
+ * @file: file handle to board
+ *
+ * The watchdog has a configurable API. There is a religious dispute
+ * between people who want their watchdog to be able to shut down and
+ * those who want to be sure if the watchdog manager dies the machine
+ * reboots. In the former case we disable the counters, in the latter
+ * case you have to open it again very soon.
+ */
+
+static int wdog_release(struct inode *inode, struct file *file)
+{
+ if (expect_close == 42) {
+ wdog_stop();
+ } else {
+ printk(KERN_CRIT
+ "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
+ wdog_ping();
+ }
+ clear_bit(0, &wdog_is_open);
+ expect_close = 0;
+ return 0;
+}
+
+/**
+ * @this: our notifier block
+ * @code: the event being reported
+ * @unused: unused
+ *
+ * Our notifier is called on system shutdowns. Turn the watchdog
+ * off so that it does not fire during the next reboot.
+ */
+
+static int wdog_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ wdog_stop();
+ return NOTIFY_DONE;
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+
+static const struct file_operations wdog_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = wdog_write,
+ .unlocked_ioctl = wdog_ioctl,
+ .open = wdog_open,
+ .release = wdog_release,
+};
+
+static struct miscdevice wdog_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &wdog_fops,
+};
+
+/*
+ * The WDT card needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdog_notifier = {
+ .notifier_call = wdog_notify_sys,
+};
+
+/**
+ * cleanup_module:
+ *
+ * Unload the watchdog. You cannot do this with any file handles open.
+ * If your watchdog is set to continue ticking on close and you unload
+ * it, well it keeps ticking. We won't get the interrupt but the board
+ * will not touch PC memory so all is fine. You just have to load a new
+ * module in 60 seconds or reboot.
+ */
+
+static void __exit wdog_exit(void)
+{
+ misc_deregister(&wdog_miscdev);
+ unregister_reboot_notifier(&wdog_notifier);
+}
+
+static int __init wdog_init(void)
+{
+ int ret;
+
+ /* Check that the heartbeat value is within it's range;
+ if not reset to the default */
+ if (wdog_set_heartbeat(heartbeat)) {
+ wdog_set_heartbeat(WD_TIMO);
+ printk(KERN_INFO "bcm2708_wdog: heartbeat value must be "
+ "0 < heartbeat < %d, using %d\n",
+ WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
+ WD_TIMO);
+ }
+
+ ret = register_reboot_notifier(&wdog_notifier);
+ if (ret) {
+ printk(KERN_ERR
+ "wdt: cannot register reboot notifier (err=%d)\n", ret);
+ goto out_reboot;
+ }
+
+ ret = misc_register(&wdog_miscdev);
+ if (ret) {
+ printk(KERN_ERR
+ "wdt: cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto out_misc;
+ }
+
+ printk(KERN_INFO "bcm2708 watchdog, heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
+ return 0;
+
+out_misc:
+ unregister_reboot_notifier(&wdog_notifier);
+out_reboot:
+ return ret;
+}
+
+module_init(wdog_init);
+module_exit(wdog_exit);
+
+MODULE_AUTHOR("Luke Diamand");
+MODULE_DESCRIPTION("Driver for BCM2708 watchdog");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_ALIAS_MISCDEV(TEMP_MINOR);
+MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,992 @@
From 8909329c134abdf242dc345a4528e98e86c85c33 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 16:07:06 +0100
Subject: [PATCH 013/121] vc_mem: Add vc_mem driver
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Signed-off-by: popcornmix <popcornmix@gmail.com>
BCM270x: Move vc_mem
Make the vc_mem module available for ARCH_BCM2835 by moving it.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm2709/include/mach/vc_mem.h | 35 ---
arch/arm/mach-bcm2709/vc_mem.c | 431 ----------------------------
drivers/char/broadcom/Kconfig | 12 +-
drivers/char/broadcom/Makefile | 1 +
drivers/char/broadcom/vc_mem.c | 423 +++++++++++++++++++++++++++
include/linux/broadcom/vc_mem.h | 35 +++
6 files changed, 470 insertions(+), 467 deletions(-)
delete mode 100644 arch/arm/mach-bcm2709/include/mach/vc_mem.h
delete mode 100644 arch/arm/mach-bcm2709/vc_mem.c
create mode 100644 drivers/char/broadcom/vc_mem.c
create mode 100644 include/linux/broadcom/vc_mem.h
--- a/arch/arm/mach-bcm2709/include/mach/vc_mem.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*****************************************************************************
-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#if !defined( VC_MEM_H )
-#define VC_MEM_H
-
-#include <linux/ioctl.h>
-
-#define VC_MEM_IOC_MAGIC 'v'
-
-#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
-#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
-#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
-#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
-
-#if defined( __KERNEL__ )
-#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
-
-extern unsigned long mm_vc_mem_phys_addr;
-extern unsigned int mm_vc_mem_size;
-extern int vc_mem_get_current_size( void );
-#endif
-
-#endif /* VC_MEM_H */
--- a/arch/arm/mach-bcm2709/vc_mem.c
+++ /dev/null
@@ -1,431 +0,0 @@
-/*****************************************************************************
-* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/device.h>
-#include <linux/cdev.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/debugfs.h>
-#include <asm/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_data/mailbox-bcm2708.h>
-
-#ifdef CONFIG_ARCH_KONA
-#include <chal/chal_ipc.h>
-#elif defined(CONFIG_ARCH_BCM2708) || defined(CONFIG_ARCH_BCM2709)
-#else
-#include <csp/chal_ipc.h>
-#endif
-
-#include "mach/vc_mem.h"
-
-#define DRIVER_NAME "vc-mem"
-
-// Device (/dev) related variables
-static dev_t vc_mem_devnum = 0;
-static struct class *vc_mem_class = NULL;
-static struct cdev vc_mem_cdev;
-static int vc_mem_inited = 0;
-
-#ifdef CONFIG_DEBUG_FS
-static struct dentry *vc_mem_debugfs_entry;
-#endif
-
-/*
- * Videocore memory addresses and size
- *
- * Drivers that wish to know the videocore memory addresses and sizes should
- * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
- * headers. This allows the other drivers to not be tied down to a a certain
- * address/size at compile time.
- *
- * In the future, the goal is to have the videocore memory virtual address and
- * size be calculated at boot time rather than at compile time. The decision of
- * where the videocore memory resides and its size would be in the hands of the
- * bootloader (and/or kernel). When that happens, the values of these variables
- * would be calculated and assigned in the init function.
- */
-// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
-unsigned long mm_vc_mem_phys_addr = 0x00000000;
-unsigned int mm_vc_mem_size = 0;
-unsigned int mm_vc_mem_base = 0;
-
-EXPORT_SYMBOL(mm_vc_mem_phys_addr);
-EXPORT_SYMBOL(mm_vc_mem_size);
-EXPORT_SYMBOL(mm_vc_mem_base);
-
-static uint phys_addr = 0;
-static uint mem_size = 0;
-static uint mem_base = 0;
-
-
-/****************************************************************************
-*
-* vc_mem_open
-*
-***************************************************************************/
-
-static int
-vc_mem_open(struct inode *inode, struct file *file)
-{
- (void) inode;
- (void) file;
-
- pr_debug("%s: called file = 0x%p\n", __func__, file);
-
- return 0;
-}
-
-/****************************************************************************
-*
-* vc_mem_release
-*
-***************************************************************************/
-
-static int
-vc_mem_release(struct inode *inode, struct file *file)
-{
- (void) inode;
- (void) file;
-
- pr_debug("%s: called file = 0x%p\n", __func__, file);
-
- return 0;
-}
-
-/****************************************************************************
-*
-* vc_mem_get_size
-*
-***************************************************************************/
-
-static void
-vc_mem_get_size(void)
-{
-}
-
-/****************************************************************************
-*
-* vc_mem_get_base
-*
-***************************************************************************/
-
-static void
-vc_mem_get_base(void)
-{
-}
-
-/****************************************************************************
-*
-* vc_mem_get_current_size
-*
-***************************************************************************/
-
-int
-vc_mem_get_current_size(void)
-{
- return mm_vc_mem_size;
-}
-
-EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
-
-/****************************************************************************
-*
-* vc_mem_ioctl
-*
-***************************************************************************/
-
-static long
-vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- int rc = 0;
-
- (void) cmd;
- (void) arg;
-
- pr_debug("%s: called file = 0x%p\n", __func__, file);
-
- switch (cmd) {
- case VC_MEM_IOC_MEM_PHYS_ADDR:
- {
- pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
- __func__, (void *) mm_vc_mem_phys_addr);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
- sizeof (mm_vc_mem_phys_addr)) != 0) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_SIZE:
- {
- // Get the videocore memory size first
- vc_mem_get_size();
-
- pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
- mm_vc_mem_size);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_size,
- sizeof (mm_vc_mem_size)) != 0) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_BASE:
- {
- // Get the videocore memory base
- vc_mem_get_base();
-
- pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
- mm_vc_mem_base);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_base,
- sizeof (mm_vc_mem_base)) != 0) {
- rc = -EFAULT;
- }
- break;
- }
- case VC_MEM_IOC_MEM_LOAD:
- {
- // Get the videocore memory base
- vc_mem_get_base();
-
- pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
- mm_vc_mem_base);
-
- if (copy_to_user((void *) arg, &mm_vc_mem_base,
- sizeof (mm_vc_mem_base)) != 0) {
- rc = -EFAULT;
- }
- break;
- }
- default:
- {
- return -ENOTTY;
- }
- }
- pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
-
- return rc;
-}
-
-/****************************************************************************
-*
-* vc_mem_mmap
-*
-***************************************************************************/
-
-static int
-vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- int rc = 0;
- unsigned long length = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-
- pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
- __func__, (long) vma->vm_start, (long) vma->vm_end,
- (long) vma->vm_pgoff);
-
- if (offset + length > mm_vc_mem_size) {
- pr_err("%s: length %ld is too big\n", __func__, length);
- return -EINVAL;
- }
- // Do not cache the memory map
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- rc = remap_pfn_range(vma, vma->vm_start,
- (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
- vma->vm_pgoff, length, vma->vm_page_prot);
- if (rc != 0) {
- pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
- }
-
- return rc;
-}
-
-/****************************************************************************
-*
-* File Operations for the driver.
-*
-***************************************************************************/
-
-static const struct file_operations vc_mem_fops = {
- .owner = THIS_MODULE,
- .open = vc_mem_open,
- .release = vc_mem_release,
- .unlocked_ioctl = vc_mem_ioctl,
- .mmap = vc_mem_mmap,
-};
-
-#ifdef CONFIG_DEBUG_FS
-static void vc_mem_debugfs_deinit(void)
-{
- debugfs_remove_recursive(vc_mem_debugfs_entry);
- vc_mem_debugfs_entry = NULL;
-}
-
-
-static int vc_mem_debugfs_init(
- struct device *dev)
-{
- vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
- if (!vc_mem_debugfs_entry) {
- dev_warn(dev, "could not create debugfs entry\n");
- return -EFAULT;
- }
-
- if (!debugfs_create_x32("vc_mem_phys_addr",
- 0444,
- vc_mem_debugfs_entry,
- (u32 *)&mm_vc_mem_phys_addr)) {
- dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
- __func__);
- goto fail;
- }
-
- if (!debugfs_create_x32("vc_mem_size",
- 0444,
- vc_mem_debugfs_entry,
- (u32 *)&mm_vc_mem_size)) {
- dev_warn(dev, "%s:could not create vc_mem_size entry\n",
- __func__);
- goto fail;
- }
-
- if (!debugfs_create_x32("vc_mem_base",
- 0444,
- vc_mem_debugfs_entry,
- (u32 *)&mm_vc_mem_base)) {
- dev_warn(dev, "%s:could not create vc_mem_base entry\n",
- __func__);
- goto fail;
- }
-
- return 0;
-
-fail:
- vc_mem_debugfs_deinit();
- return -EFAULT;
-}
-
-#endif /* CONFIG_DEBUG_FS */
-
-
-/****************************************************************************
-*
-* vc_mem_init
-*
-***************************************************************************/
-
-static int __init
-vc_mem_init(void)
-{
- int rc = -EFAULT;
- struct device *dev;
-
- pr_debug("%s: called\n", __func__);
-
- mm_vc_mem_phys_addr = phys_addr;
- mm_vc_mem_size = mem_size;
- mm_vc_mem_base = mem_base;
-
- vc_mem_get_size();
-
- pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
- mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
-
- if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
- pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
- __func__, rc);
- goto out_err;
- }
-
- cdev_init(&vc_mem_cdev, &vc_mem_fops);
- if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
- pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
- goto out_unregister;
- }
-
- vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
- if (IS_ERR(vc_mem_class)) {
- rc = PTR_ERR(vc_mem_class);
- pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
- goto out_cdev_del;
- }
-
- dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
- DRIVER_NAME);
- if (IS_ERR(dev)) {
- rc = PTR_ERR(dev);
- pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
- goto out_class_destroy;
- }
-
-#ifdef CONFIG_DEBUG_FS
- /* don't fail if the debug entries cannot be created */
- vc_mem_debugfs_init(dev);
-#endif
-
- vc_mem_inited = 1;
- return 0;
-
- device_destroy(vc_mem_class, vc_mem_devnum);
-
- out_class_destroy:
- class_destroy(vc_mem_class);
- vc_mem_class = NULL;
-
- out_cdev_del:
- cdev_del(&vc_mem_cdev);
-
- out_unregister:
- unregister_chrdev_region(vc_mem_devnum, 1);
-
- out_err:
- return -1;
-}
-
-/****************************************************************************
-*
-* vc_mem_exit
-*
-***************************************************************************/
-
-static void __exit
-vc_mem_exit(void)
-{
- pr_debug("%s: called\n", __func__);
-
- if (vc_mem_inited) {
-#if CONFIG_DEBUG_FS
- vc_mem_debugfs_deinit();
-#endif
- device_destroy(vc_mem_class, vc_mem_devnum);
- class_destroy(vc_mem_class);
- cdev_del(&vc_mem_cdev);
- unregister_chrdev_region(vc_mem_devnum, 1);
- }
-}
-
-module_init(vc_mem_init);
-module_exit(vc_mem_exit);
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Broadcom Corporation");
-
-module_param(phys_addr, uint, 0644);
-module_param(mem_size, uint, 0644);
-module_param(mem_base, uint, 0644);
--- a/drivers/char/broadcom/Kconfig
+++ b/drivers/char/broadcom/Kconfig
@@ -7,9 +7,19 @@ menuconfig BRCM_CHAR_DRIVERS
help
Broadcom's char drivers
+if BRCM_CHAR_DRIVERS
+
config BCM_VC_CMA
bool "Videocore CMA"
- depends on CMA && BRCM_CHAR_DRIVERS && BCM2708_VCHIQ
+ depends on CMA && BCM2708_VCHIQ
default n
help
Helper for videocore CMA access.
+
+config BCM2708_VCMEM
+ bool "Videocore Memory"
+ default y
+ help
+ Helper for videocore memory access and total size allocation.
+
+endif
--- a/drivers/char/broadcom/Makefile
+++ b/drivers/char/broadcom/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
+obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
--- /dev/null
+++ b/drivers/char/broadcom/vc_mem.c
@@ -0,0 +1,423 @@
+/*****************************************************************************
+* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_data/mailbox-bcm2708.h>
+#include <linux/broadcom/vc_mem.h>
+
+#define DRIVER_NAME "vc-mem"
+
+// Device (/dev) related variables
+static dev_t vc_mem_devnum = 0;
+static struct class *vc_mem_class = NULL;
+static struct cdev vc_mem_cdev;
+static int vc_mem_inited = 0;
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *vc_mem_debugfs_entry;
+#endif
+
+/*
+ * Videocore memory addresses and size
+ *
+ * Drivers that wish to know the videocore memory addresses and sizes should
+ * use these variables instead of the MM_IO_BASE and MM_ADDR_IO defines in
+ * headers. This allows the other drivers to not be tied down to a a certain
+ * address/size at compile time.
+ *
+ * In the future, the goal is to have the videocore memory virtual address and
+ * size be calculated at boot time rather than at compile time. The decision of
+ * where the videocore memory resides and its size would be in the hands of the
+ * bootloader (and/or kernel). When that happens, the values of these variables
+ * would be calculated and assigned in the init function.
+ */
+// in the 2835 VC in mapped above ARM, but ARM has full access to VC space
+unsigned long mm_vc_mem_phys_addr = 0x00000000;
+unsigned int mm_vc_mem_size = 0;
+unsigned int mm_vc_mem_base = 0;
+
+EXPORT_SYMBOL(mm_vc_mem_phys_addr);
+EXPORT_SYMBOL(mm_vc_mem_size);
+EXPORT_SYMBOL(mm_vc_mem_base);
+
+static uint phys_addr = 0;
+static uint mem_size = 0;
+static uint mem_base = 0;
+
+
+/****************************************************************************
+*
+* vc_mem_open
+*
+***************************************************************************/
+
+static int
+vc_mem_open(struct inode *inode, struct file *file)
+{
+ (void) inode;
+ (void) file;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+}
+
+/****************************************************************************
+*
+* vc_mem_release
+*
+***************************************************************************/
+
+static int
+vc_mem_release(struct inode *inode, struct file *file)
+{
+ (void) inode;
+ (void) file;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ return 0;
+}
+
+/****************************************************************************
+*
+* vc_mem_get_size
+*
+***************************************************************************/
+
+static void
+vc_mem_get_size(void)
+{
+}
+
+/****************************************************************************
+*
+* vc_mem_get_base
+*
+***************************************************************************/
+
+static void
+vc_mem_get_base(void)
+{
+}
+
+/****************************************************************************
+*
+* vc_mem_get_current_size
+*
+***************************************************************************/
+
+int
+vc_mem_get_current_size(void)
+{
+ return mm_vc_mem_size;
+}
+
+EXPORT_SYMBOL_GPL(vc_mem_get_current_size);
+
+/****************************************************************************
+*
+* vc_mem_ioctl
+*
+***************************************************************************/
+
+static long
+vc_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int rc = 0;
+
+ (void) cmd;
+ (void) arg;
+
+ pr_debug("%s: called file = 0x%p\n", __func__, file);
+
+ switch (cmd) {
+ case VC_MEM_IOC_MEM_PHYS_ADDR:
+ {
+ pr_debug("%s: VC_MEM_IOC_MEM_PHYS_ADDR=0x%p\n",
+ __func__, (void *) mm_vc_mem_phys_addr);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_phys_addr,
+ sizeof (mm_vc_mem_phys_addr)) != 0) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_SIZE:
+ {
+ // Get the videocore memory size first
+ vc_mem_get_size();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_SIZE=%u\n", __func__,
+ mm_vc_mem_size);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_size,
+ sizeof (mm_vc_mem_size)) != 0) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_BASE:
+ {
+ // Get the videocore memory base
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_BASE=%u\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
+ sizeof (mm_vc_mem_base)) != 0) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ case VC_MEM_IOC_MEM_LOAD:
+ {
+ // Get the videocore memory base
+ vc_mem_get_base();
+
+ pr_debug("%s: VC_MEM_IOC_MEM_LOAD=%u\n", __func__,
+ mm_vc_mem_base);
+
+ if (copy_to_user((void *) arg, &mm_vc_mem_base,
+ sizeof (mm_vc_mem_base)) != 0) {
+ rc = -EFAULT;
+ }
+ break;
+ }
+ default:
+ {
+ return -ENOTTY;
+ }
+ }
+ pr_debug("%s: file = 0x%p returning %d\n", __func__, file, rc);
+
+ return rc;
+}
+
+/****************************************************************************
+*
+* vc_mem_mmap
+*
+***************************************************************************/
+
+static int
+vc_mem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ int rc = 0;
+ unsigned long length = vma->vm_end - vma->vm_start;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+
+ pr_debug("%s: vm_start = 0x%08lx vm_end = 0x%08lx vm_pgoff = 0x%08lx\n",
+ __func__, (long) vma->vm_start, (long) vma->vm_end,
+ (long) vma->vm_pgoff);
+
+ if (offset + length > mm_vc_mem_size) {
+ pr_err("%s: length %ld is too big\n", __func__, length);
+ return -EINVAL;
+ }
+ // Do not cache the memory map
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ rc = remap_pfn_range(vma, vma->vm_start,
+ (mm_vc_mem_phys_addr >> PAGE_SHIFT) +
+ vma->vm_pgoff, length, vma->vm_page_prot);
+ if (rc != 0) {
+ pr_err("%s: remap_pfn_range failed (rc=%d)\n", __func__, rc);
+ }
+
+ return rc;
+}
+
+/****************************************************************************
+*
+* File Operations for the driver.
+*
+***************************************************************************/
+
+static const struct file_operations vc_mem_fops = {
+ .owner = THIS_MODULE,
+ .open = vc_mem_open,
+ .release = vc_mem_release,
+ .unlocked_ioctl = vc_mem_ioctl,
+ .mmap = vc_mem_mmap,
+};
+
+#ifdef CONFIG_DEBUG_FS
+static void vc_mem_debugfs_deinit(void)
+{
+ debugfs_remove_recursive(vc_mem_debugfs_entry);
+ vc_mem_debugfs_entry = NULL;
+}
+
+
+static int vc_mem_debugfs_init(
+ struct device *dev)
+{
+ vc_mem_debugfs_entry = debugfs_create_dir(DRIVER_NAME, NULL);
+ if (!vc_mem_debugfs_entry) {
+ dev_warn(dev, "could not create debugfs entry\n");
+ return -EFAULT;
+ }
+
+ if (!debugfs_create_x32("vc_mem_phys_addr",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_phys_addr)) {
+ dev_warn(dev, "%s:could not create vc_mem_phys entry\n",
+ __func__);
+ goto fail;
+ }
+
+ if (!debugfs_create_x32("vc_mem_size",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_size)) {
+ dev_warn(dev, "%s:could not create vc_mem_size entry\n",
+ __func__);
+ goto fail;
+ }
+
+ if (!debugfs_create_x32("vc_mem_base",
+ 0444,
+ vc_mem_debugfs_entry,
+ (u32 *)&mm_vc_mem_base)) {
+ dev_warn(dev, "%s:could not create vc_mem_base entry\n",
+ __func__);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ vc_mem_debugfs_deinit();
+ return -EFAULT;
+}
+
+#endif /* CONFIG_DEBUG_FS */
+
+
+/****************************************************************************
+*
+* vc_mem_init
+*
+***************************************************************************/
+
+static int __init
+vc_mem_init(void)
+{
+ int rc = -EFAULT;
+ struct device *dev;
+
+ pr_debug("%s: called\n", __func__);
+
+ mm_vc_mem_phys_addr = phys_addr;
+ mm_vc_mem_size = mem_size;
+ mm_vc_mem_base = mem_base;
+
+ vc_mem_get_size();
+
+ pr_info("vc-mem: phys_addr:0x%08lx mem_base=0x%08x mem_size:0x%08x(%u MiB)\n",
+ mm_vc_mem_phys_addr, mm_vc_mem_base, mm_vc_mem_size, mm_vc_mem_size / (1024 * 1024));
+
+ if ((rc = alloc_chrdev_region(&vc_mem_devnum, 0, 1, DRIVER_NAME)) < 0) {
+ pr_err("%s: alloc_chrdev_region failed (rc=%d)\n",
+ __func__, rc);
+ goto out_err;
+ }
+
+ cdev_init(&vc_mem_cdev, &vc_mem_fops);
+ if ((rc = cdev_add(&vc_mem_cdev, vc_mem_devnum, 1)) != 0) {
+ pr_err("%s: cdev_add failed (rc=%d)\n", __func__, rc);
+ goto out_unregister;
+ }
+
+ vc_mem_class = class_create(THIS_MODULE, DRIVER_NAME);
+ if (IS_ERR(vc_mem_class)) {
+ rc = PTR_ERR(vc_mem_class);
+ pr_err("%s: class_create failed (rc=%d)\n", __func__, rc);
+ goto out_cdev_del;
+ }
+
+ dev = device_create(vc_mem_class, NULL, vc_mem_devnum, NULL,
+ DRIVER_NAME);
+ if (IS_ERR(dev)) {
+ rc = PTR_ERR(dev);
+ pr_err("%s: device_create failed (rc=%d)\n", __func__, rc);
+ goto out_class_destroy;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ /* don't fail if the debug entries cannot be created */
+ vc_mem_debugfs_init(dev);
+#endif
+
+ vc_mem_inited = 1;
+ return 0;
+
+ device_destroy(vc_mem_class, vc_mem_devnum);
+
+ out_class_destroy:
+ class_destroy(vc_mem_class);
+ vc_mem_class = NULL;
+
+ out_cdev_del:
+ cdev_del(&vc_mem_cdev);
+
+ out_unregister:
+ unregister_chrdev_region(vc_mem_devnum, 1);
+
+ out_err:
+ return -1;
+}
+
+/****************************************************************************
+*
+* vc_mem_exit
+*
+***************************************************************************/
+
+static void __exit
+vc_mem_exit(void)
+{
+ pr_debug("%s: called\n", __func__);
+
+ if (vc_mem_inited) {
+#if CONFIG_DEBUG_FS
+ vc_mem_debugfs_deinit();
+#endif
+ device_destroy(vc_mem_class, vc_mem_devnum);
+ class_destroy(vc_mem_class);
+ cdev_del(&vc_mem_cdev);
+ unregister_chrdev_region(vc_mem_devnum, 1);
+ }
+}
+
+module_init(vc_mem_init);
+module_exit(vc_mem_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Broadcom Corporation");
+
+module_param(phys_addr, uint, 0644);
+module_param(mem_size, uint, 0644);
+module_param(mem_base, uint, 0644);
--- /dev/null
+++ b/include/linux/broadcom/vc_mem.h
@@ -0,0 +1,35 @@
+/*****************************************************************************
+* Copyright 2010 - 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#ifndef _VC_MEM_H
+#define _VC_MEM_H
+
+#include <linux/ioctl.h>
+
+#define VC_MEM_IOC_MAGIC 'v'
+
+#define VC_MEM_IOC_MEM_PHYS_ADDR _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
+#define VC_MEM_IOC_MEM_SIZE _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
+#define VC_MEM_IOC_MEM_BASE _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
+#define VC_MEM_IOC_MEM_LOAD _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
+
+#if defined( __KERNEL__ )
+#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
+
+extern unsigned long mm_vc_mem_phys_addr;
+extern unsigned int mm_vc_mem_size;
+extern int vc_mem_get_current_size( void );
+#endif
+
+#endif /* _VC_MEM_H */

View File

@ -0,0 +1,172 @@
From 250314915c749fccd25d98aca0b9a2d29f55ec1c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:51:55 +0100
Subject: [PATCH 015/121] Add hwrng (hardware random number generator) driver
---
drivers/char/hw_random/Kconfig | 13 +++-
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/bcm2708-rng.c | 118 +++++++++++++++++++++++++++++++++++
3 files changed, 131 insertions(+), 1 deletion(-)
create mode 100755 drivers/char/hw_random/bcm2708-rng.c
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -90,7 +90,7 @@ config HW_RANDOM_BCM63XX
config HW_RANDOM_BCM2835
tristate "Broadcom BCM2835 Random Number Generator support"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
default HW_RANDOM
---help---
This driver provides kernel-side support for the Random Number
@@ -333,6 +333,17 @@ config HW_RANDOM_TPM
If unsure, say Y.
+config HW_RANDOM_BCM2708
+ tristate "BCM2708 generic true random number generator support"
+ depends on HW_RANDOM && (ARCH_BCM2708 || ARCH_BCM2709)
+ ---help---
+ This driver provides the kernel-side support for the BCM2708 hardware.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bcm2708-rng.
+
+ If unsure, say N.
+
config HW_RANDOM_MSM
tristate "Qualcomm SoCs Random Number Generator support"
depends on HW_RANDOM && ARCH_QCOM
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -4,6 +4,7 @@
obj-$(CONFIG_HW_RANDOM) += rng-core.o
rng-core-y := core.o
+obj-$(CONFIG_HW_RANDOM_BCM2708) += bcm2708-rng.o
obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o
obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
--- /dev/null
+++ b/drivers/char/hw_random/bcm2708-rng.c
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/hw_random.h>
+#include <linux/printk.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#define RNG_CTRL (0x0)
+#define RNG_STATUS (0x4)
+#define RNG_DATA (0x8)
+#define RNG_FF_THRESHOLD (0xc)
+
+/* enable rng */
+#define RNG_RBGEN 0x1
+/* double speed, less random mode */
+#define RNG_RBG2X 0x2
+
+/* the initial numbers generated are "less random" so will be discarded */
+#define RNG_WARMUP_COUNT 0x40000
+
+static int bcm2708_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ void __iomem *rng_base = (void __iomem *)rng->priv;
+ unsigned words;
+ /* wait for a random number to be in fifo */
+ do {
+ words = __raw_readl(rng_base + RNG_STATUS)>>24;
+ }
+ while (words == 0);
+ /* read the random number */
+ *buffer = __raw_readl(rng_base + RNG_DATA);
+ return 4;
+}
+
+static struct hwrng bcm2708_rng_ops = {
+ .name = "bcm2708",
+ .data_read = bcm2708_rng_data_read,
+};
+
+static int __init bcm2708_rng_init(void)
+{
+ void __iomem *rng_base;
+ int err;
+
+ /* map peripheral */
+ rng_base = ioremap(RNG_BASE, 0x10);
+ pr_info("bcm2708_rng_init=%p\n", rng_base);
+ if (!rng_base) {
+ pr_err("bcm2708_rng_init failed to ioremap\n");
+ return -ENOMEM;
+ }
+ bcm2708_rng_ops.priv = (unsigned long)rng_base;
+
+ /* set warm-up count & enable */
+ __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
+ __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
+
+ /* register driver */
+ err = hwrng_register(&bcm2708_rng_ops);
+ if (err) {
+ pr_err("bcm2708_rng_init hwrng_register()=%d\n", err);
+ iounmap(rng_base);
+ }
+ return err;
+}
+
+static void __exit bcm2708_rng_exit(void)
+{
+ void __iomem *rng_base = (void __iomem *)bcm2708_rng_ops.priv;
+ pr_info("bcm2708_rng_exit\n");
+ /* disable rng hardware */
+ __raw_writel(0, rng_base + RNG_CTRL);
+ /* unregister driver */
+ hwrng_unregister(&bcm2708_rng_ops);
+ iounmap(rng_base);
+}
+
+module_init(bcm2708_rng_init);
+module_exit(bcm2708_rng_exit);
+
+MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL and additional rights");

View File

@ -0,0 +1,848 @@
From e074d656e4011eae32577e4d20d7ce6dfa15f6e8 Mon Sep 17 00:00:00 2001
From: Aron Szabo <aron@aron.ws>
Date: Sat, 16 Jun 2012 12:15:55 +0200
Subject: [PATCH 016/121] lirc: added support for RaspberryPi GPIO
lirc_rpi: Use read_current_timer to determine transmitter delay. Thanks to jjmz and others
See: https://github.com/raspberrypi/linux/issues/525
lirc: Remove restriction on gpio pins that can be used with lirc
Compute Module, for example could use different pins
lirc_rpi: Add parameter to specify input pin pull
Depending on the connected IR circuitry it might be desirable to change the
gpios internal pull from it pull-down default behaviour. Add a module
parameter to allow the user to set it explicitly.
Signed-off-by: Julian Scheel <julian@jusst.de>
lirc-rpi: Use the higher-level irq control functions
This module used to access the irq_chip methods of the
gpio controller directly, rather than going through the
standard enable_irq/irq_set_irq_type functions. This
caused problems on pinctrl-bcm2835 which only implements
the irq_enable/disable methods and not irq_unmask/mask.
lirc-rpi: Correct the interrupt usage
1) Correct the use of enable_irq (i.e. don't call it so often)
2) Correct the shutdown sequence.
3) Avoid a bcm2708_gpio driver quirk by setting the irq flags earlier
lirc-rpi: use getnstimeofday instead of read_current_timer
read_current_timer isn't guaranteed to return values in
microseconds, and indeed it doesn't on a Pi2.
Issue: linux#827
lirc-rpi: Add device tree support, and a suitable overlay
The overlay supports DT parameters that match the old module
parameters, except that gpio_in_pull should be set using the
strings "up", "down" or "off".
lirc-rpi: Also support pinctrl-bcm2835 in non-DT mode
---
drivers/staging/media/lirc/Kconfig | 6 +
drivers/staging/media/lirc/Makefile | 1 +
drivers/staging/media/lirc/lirc_rpi.c | 765 ++++++++++++++++++++++++++++++++++
3 files changed, 772 insertions(+)
create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -32,6 +32,12 @@ config LIRC_PARALLEL
help
Driver for Homebrew Parallel Port Receivers
+config LIRC_RPI
+ tristate "Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi"
+ depends on LIRC
+ help
+ Driver for Homebrew GPIO Port Receiver/Transmitter for the RaspberryPi
+
config LIRC_SASEM
tristate "Sasem USB IR Remote"
depends on LIRC && USB
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
+obj-$(CONFIG_LIRC_RPI) += lirc_rpi.o
obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o
obj-$(CONFIG_LIRC_SIR) += lirc_sir.o
--- /dev/null
+++ b/drivers/staging/media/lirc/lirc_rpi.c
@@ -0,0 +1,765 @@
+/*
+ * lirc_rpi.c
+ *
+ * lirc_rpi - Device driver that records pulse- and pause-lengths
+ * (space-lengths) (just like the lirc_serial driver does)
+ * between GPIO interrupt events on the Raspberry Pi.
+ * Lots of code has been taken from the lirc_serial module,
+ * so I would like say thanks to the authors.
+ *
+ * Copyright (C) 2012 Aron Robert Szabo <aron@reon.hu>,
+ * Michael Bishop <cleverca22@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/timekeeping.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <mach/gpio.h>
+#include <linux/gpio.h>
+#include <linux/of_platform.h>
+
+#include <linux/platform_data/bcm2708.h>
+
+#define LIRC_DRIVER_NAME "lirc_rpi"
+#define RBUF_LEN 256
+#define LIRC_TRANSMITTER_LATENCY 50
+
+#ifndef MAX_UDELAY_MS
+#define MAX_UDELAY_US 5000
+#else
+#define MAX_UDELAY_US (MAX_UDELAY_MS*1000)
+#endif
+
+#define dprintk(fmt, args...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG LIRC_DRIVER_NAME ": " \
+ fmt, ## args); \
+ } while (0)
+
+/* module parameters */
+
+/* set the default GPIO input pin */
+static int gpio_in_pin = 18;
+/* set the default pull behaviour for input pin */
+static int gpio_in_pull = BCM2708_PULL_DOWN;
+/* set the default GPIO output pin */
+static int gpio_out_pin = 17;
+/* enable debugging messages */
+static bool debug;
+/* -1 = auto, 0 = active high, 1 = active low */
+static int sense = -1;
+/* use softcarrier by default */
+static bool softcarrier = 1;
+/* 0 = do not invert output, 1 = invert output */
+static bool invert = 0;
+
+struct gpio_chip *gpiochip;
+static int irq_num;
+
+/* forward declarations */
+static long send_pulse(unsigned long length);
+static void send_space(long length);
+static void lirc_rpi_exit(void);
+
+static struct platform_device *lirc_rpi_dev;
+static struct timeval lasttv = { 0, 0 };
+static struct lirc_buffer rbuf;
+static spinlock_t lock;
+
+/* initialized/set in init_timing_params() */
+static unsigned int freq = 38000;
+static unsigned int duty_cycle = 50;
+static unsigned long period;
+static unsigned long pulse_width;
+static unsigned long space_width;
+
+static void safe_udelay(unsigned long usecs)
+{
+ while (usecs > MAX_UDELAY_US) {
+ udelay(MAX_UDELAY_US);
+ usecs -= MAX_UDELAY_US;
+ }
+ udelay(usecs);
+}
+
+static unsigned long read_current_us(void)
+{
+ struct timespec now;
+ getnstimeofday(&now);
+ return (now.tv_sec * 1000000) + (now.tv_nsec/1000);
+}
+
+static int init_timing_params(unsigned int new_duty_cycle,
+ unsigned int new_freq)
+{
+ if (1000 * 1000000L / new_freq * new_duty_cycle / 100 <=
+ LIRC_TRANSMITTER_LATENCY)
+ return -EINVAL;
+ if (1000 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <=
+ LIRC_TRANSMITTER_LATENCY)
+ return -EINVAL;
+ duty_cycle = new_duty_cycle;
+ freq = new_freq;
+ period = 1000 * 1000000L / freq;
+ pulse_width = period * duty_cycle / 100;
+ space_width = period - pulse_width;
+ dprintk("in init_timing_params, freq=%d pulse=%ld, "
+ "space=%ld\n", freq, pulse_width, space_width);
+ return 0;
+}
+
+static long send_pulse_softcarrier(unsigned long length)
+{
+ int flag;
+ unsigned long actual, target;
+ unsigned long actual_us, initial_us, target_us;
+
+ length *= 1000;
+
+ actual = 0; target = 0; flag = 0;
+ actual_us = read_current_us();
+
+ while (actual < length) {
+ if (flag) {
+ gpiochip->set(gpiochip, gpio_out_pin, invert);
+ target += space_width;
+ } else {
+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
+ target += pulse_width;
+ }
+ initial_us = actual_us;
+ target_us = actual_us + (target - actual) / 1000;
+ /*
+ * Note - we've checked in ioctl that the pulse/space
+ * widths are big enough so that d is > 0
+ */
+ if ((int)(target_us - actual_us) > 0)
+ udelay(target_us - actual_us);
+ actual_us = read_current_us();
+ actual += (actual_us - initial_us) * 1000;
+ flag = !flag;
+ }
+ return (actual-length) / 1000;
+}
+
+static long send_pulse(unsigned long length)
+{
+ if (length <= 0)
+ return 0;
+
+ if (softcarrier) {
+ return send_pulse_softcarrier(length);
+ } else {
+ gpiochip->set(gpiochip, gpio_out_pin, !invert);
+ safe_udelay(length);
+ return 0;
+ }
+}
+
+static void send_space(long length)
+{
+ gpiochip->set(gpiochip, gpio_out_pin, invert);
+ if (length <= 0)
+ return;
+ safe_udelay(length);
+}
+
+static void rbwrite(int l)
+{
+ if (lirc_buffer_full(&rbuf)) {
+ /* no new signals will be accepted */
+ dprintk("Buffer overrun\n");
+ return;
+ }
+ lirc_buffer_write(&rbuf, (void *)&l);
+}
+
+static void frbwrite(int l)
+{
+ /* simple noise filter */
+ static int pulse, space;
+ static unsigned int ptr;
+
+ if (ptr > 0 && (l & PULSE_BIT)) {
+ pulse += l & PULSE_MASK;
+ if (pulse > 250) {
+ rbwrite(space);
+ rbwrite(pulse | PULSE_BIT);
+ ptr = 0;
+ pulse = 0;
+ }
+ return;
+ }
+ if (!(l & PULSE_BIT)) {
+ if (ptr == 0) {
+ if (l > 20000) {
+ space = l;
+ ptr++;
+ return;
+ }
+ } else {
+ if (l > 20000) {
+ space += pulse;
+ if (space > PULSE_MASK)
+ space = PULSE_MASK;
+ space += l;
+ if (space > PULSE_MASK)
+ space = PULSE_MASK;
+ pulse = 0;
+ return;
+ }
+ rbwrite(space);
+ rbwrite(pulse | PULSE_BIT);
+ ptr = 0;
+ pulse = 0;
+ }
+ }
+ rbwrite(l);
+}
+
+static irqreturn_t irq_handler(int i, void *blah, struct pt_regs *regs)
+{
+ struct timeval tv;
+ long deltv;
+ int data;
+ int signal;
+
+ /* use the GPIO signal level */
+ signal = gpiochip->get(gpiochip, gpio_in_pin);
+
+ if (sense != -1) {
+ /* get current time */
+ do_gettimeofday(&tv);
+
+ /* calc time since last interrupt in microseconds */
+ deltv = tv.tv_sec-lasttv.tv_sec;
+ if (tv.tv_sec < lasttv.tv_sec ||
+ (tv.tv_sec == lasttv.tv_sec &&
+ tv.tv_usec < lasttv.tv_usec)) {
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": AIEEEE: your clock just jumped backwards\n");
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": %d %d %lx %lx %lx %lx\n", signal, sense,
+ tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
+ data = PULSE_MASK;
+ } else if (deltv > 15) {
+ data = PULSE_MASK; /* really long time */
+ if (!(signal^sense)) {
+ /* sanity check */
+ printk(KERN_WARNING LIRC_DRIVER_NAME
+ ": AIEEEE: %d %d %lx %lx %lx %lx\n",
+ signal, sense, tv.tv_sec, lasttv.tv_sec,
+ tv.tv_usec, lasttv.tv_usec);
+ /*
+ * detecting pulse while this
+ * MUST be a space!
+ */
+ sense = sense ? 0 : 1;
+ }
+ } else {
+ data = (int) (deltv*1000000 +
+ (tv.tv_usec - lasttv.tv_usec));
+ }
+ frbwrite(signal^sense ? data : (data|PULSE_BIT));
+ lasttv = tv;
+ wake_up_interruptible(&rbuf.wait_poll);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int is_right_chip(struct gpio_chip *chip, void *data)
+{
+ dprintk("is_right_chip %s %d\n", chip->label, strcmp(data, chip->label));
+
+ if (strcmp(data, chip->label) == 0)
+ return 1;
+ return 0;
+}
+
+static inline int read_bool_property(const struct device_node *np,
+ const char *propname,
+ bool *out_value)
+{
+ u32 value = 0;
+ int err = of_property_read_u32(np, propname, &value);
+ if (err == 0)
+ *out_value = (value != 0);
+ return err;
+}
+
+static void read_pin_settings(struct device_node *node)
+{
+ u32 pin;
+ int index;
+
+ for (index = 0;
+ of_property_read_u32_index(
+ node,
+ "brcm,pins",
+ index,
+ &pin) == 0;
+ index++) {
+ u32 function;
+ int err;
+ err = of_property_read_u32_index(
+ node,
+ "brcm,function",
+ index,
+ &function);
+ if (err == 0) {
+ if (function == 1) /* Output */
+ gpio_out_pin = pin;
+ else if (function == 0) /* Input */
+ gpio_in_pin = pin;
+ }
+ }
+}
+
+static int init_port(void)
+{
+ int i, nlow, nhigh, ret;
+ struct device_node *node;
+
+ node = lirc_rpi_dev->dev.of_node;
+
+ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
+
+ /*
+ * Because of the lack of a setpull function, only support
+ * pinctrl-bcm2835 if using device tree.
+ */
+ if (!gpiochip && node)
+ gpiochip = gpiochip_find("pinctrl-bcm2835", is_right_chip);
+
+ if (!gpiochip) {
+ pr_err(LIRC_DRIVER_NAME ": gpio chip not found!\n");
+ return -ENODEV;
+ }
+
+ if (node) {
+ struct device_node *pins_node;
+
+ pins_node = of_parse_phandle(node, "pinctrl-0", 0);
+ if (!pins_node) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": pinctrl settings not found!\n");
+ ret = -EINVAL;
+ goto exit_init_port;
+ }
+
+ read_pin_settings(pins_node);
+
+ of_property_read_u32(node, "rpi,sense", &sense);
+
+ read_bool_property(node, "rpi,softcarrier", &softcarrier);
+
+ read_bool_property(node, "rpi,invert", &invert);
+
+ read_bool_property(node, "rpi,debug", &debug);
+
+ }
+ else
+ {
+ if (gpio_in_pin >= BCM2708_NR_GPIOS ||
+ gpio_out_pin >= BCM2708_NR_GPIOS) {
+ ret = -EINVAL;
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": invalid GPIO pin(s) specified!\n");
+ goto exit_init_port;
+ }
+
+ if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) {
+ printk(KERN_ALERT LIRC_DRIVER_NAME
+ ": cant claim gpio pin %d\n", gpio_out_pin);
+ ret = -ENODEV;
+ goto exit_init_port;
+ }
+
+ if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) {
+ printk(KERN_ALERT LIRC_DRIVER_NAME
+ ": cant claim gpio pin %d\n", gpio_in_pin);
+ ret = -ENODEV;
+ goto exit_gpio_free_out_pin;
+ }
+
+ bcm2708_gpio_setpull(gpiochip, gpio_in_pin, gpio_in_pull);
+ gpiochip->direction_input(gpiochip, gpio_in_pin);
+ gpiochip->direction_output(gpiochip, gpio_out_pin, 1);
+ }
+
+ gpiochip->set(gpiochip, gpio_out_pin, invert);
+
+ irq_num = gpiochip->to_irq(gpiochip, gpio_in_pin);
+ dprintk("to_irq %d\n", irq_num);
+
+ /* if pin is high, then this must be an active low receiver. */
+ if (sense == -1) {
+ /* wait 1/2 sec for the power supply */
+ msleep(500);
+
+ /*
+ * probe 9 times every 0.04s, collect "votes" for
+ * active high/low
+ */
+ nlow = 0;
+ nhigh = 0;
+ for (i = 0; i < 9; i++) {
+ if (gpiochip->get(gpiochip, gpio_in_pin))
+ nlow++;
+ else
+ nhigh++;
+ msleep(40);
+ }
+ sense = (nlow >= nhigh ? 1 : 0);
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": auto-detected active %s receiver on GPIO pin %d\n",
+ sense ? "low" : "high", gpio_in_pin);
+ } else {
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": manually using active %s receiver on GPIO pin %d\n",
+ sense ? "low" : "high", gpio_in_pin);
+ }
+
+ return 0;
+
+ exit_gpio_free_out_pin:
+ gpio_free(gpio_out_pin);
+
+ exit_init_port:
+ return ret;
+}
+
+// called when the character device is opened
+static int set_use_inc(void *data)
+{
+ int result;
+
+ /* initialize timestamp */
+ do_gettimeofday(&lasttv);
+
+ result = request_irq(irq_num,
+ (irq_handler_t) irq_handler,
+ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING,
+ LIRC_DRIVER_NAME, (void*) 0);
+
+ switch (result) {
+ case -EBUSY:
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": IRQ %d is busy\n",
+ irq_num);
+ return -EBUSY;
+ case -EINVAL:
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": Bad irq number or handler\n");
+ return -EINVAL;
+ default:
+ dprintk("Interrupt %d obtained\n",
+ irq_num);
+ break;
+ };
+
+ /* initialize pulse/space widths */
+ init_timing_params(duty_cycle, freq);
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ /* GPIO Pin Falling/Rising Edge Detect Disable */
+ irq_set_irq_type(irq_num, 0);
+ disable_irq(irq_num);
+
+ free_irq(irq_num, (void *) 0);
+
+ dprintk(KERN_INFO LIRC_DRIVER_NAME
+ ": freed IRQ %d\n", irq_num);
+}
+
+static ssize_t lirc_write(struct file *file, const char *buf,
+ size_t n, loff_t *ppos)
+{
+ int i, count;
+ unsigned long flags;
+ long delta = 0;
+ int *wbuf;
+
+ count = n / sizeof(int);
+ if (n % sizeof(int) || count % 2 == 0)
+ return -EINVAL;
+ wbuf = memdup_user(buf, n);
+ if (IS_ERR(wbuf))
+ return PTR_ERR(wbuf);
+ spin_lock_irqsave(&lock, flags);
+
+ for (i = 0; i < count; i++) {
+ if (i%2)
+ send_space(wbuf[i] - delta);
+ else
+ delta = send_pulse(wbuf[i]);
+ }
+ gpiochip->set(gpiochip, gpio_out_pin, invert);
+
+ spin_unlock_irqrestore(&lock, flags);
+ kfree(wbuf);
+ return n;
+}
+
+static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
+{
+ int result;
+ __u32 value;
+
+ switch (cmd) {
+ case LIRC_GET_SEND_MODE:
+ return -ENOIOCTLCMD;
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ result = get_user(value, (__u32 *) arg);
+ if (result)
+ return result;
+ /* only LIRC_MODE_PULSE supported */
+ if (value != LIRC_MODE_PULSE)
+ return -ENOSYS;
+ break;
+
+ case LIRC_GET_LENGTH:
+ return -ENOSYS;
+ break;
+
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ dprintk("SET_SEND_DUTY_CYCLE\n");
+ result = get_user(value, (__u32 *) arg);
+ if (result)
+ return result;
+ if (value <= 0 || value > 100)
+ return -EINVAL;
+ return init_timing_params(value, freq);
+ break;
+
+ case LIRC_SET_SEND_CARRIER:
+ dprintk("SET_SEND_CARRIER\n");
+ result = get_user(value, (__u32 *) arg);
+ if (result)
+ return result;
+ if (value > 500000 || value < 20000)
+ return -EINVAL;
+ return init_timing_params(duty_cycle, value);
+ break;
+
+ default:
+ return lirc_dev_fop_ioctl(filep, cmd, arg);
+ }
+ return 0;
+}
+
+static const struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .write = lirc_write,
+ .unlocked_ioctl = lirc_ioctl,
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+ .llseek = no_llseek,
+};
+
+static struct lirc_driver driver = {
+ .name = LIRC_DRIVER_NAME,
+ .minor = -1,
+ .code_length = 1,
+ .sample_rate = 0,
+ .data = NULL,
+ .add_to_buf = NULL,
+ .rbuf = &rbuf,
+ .set_use_inc = set_use_inc,
+ .set_use_dec = set_use_dec,
+ .fops = &lirc_fops,
+ .dev = NULL,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id lirc_rpi_of_match[] = {
+ { .compatible = "rpi,lirc-rpi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, lirc_rpi_of_match);
+
+static struct platform_driver lirc_rpi_driver = {
+ .driver = {
+ .name = LIRC_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(lirc_rpi_of_match),
+ },
+};
+
+static int __init lirc_rpi_init(void)
+{
+ struct device_node *node;
+ int result;
+
+ /* Init read buffer. */
+ result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN);
+ if (result < 0)
+ return -ENOMEM;
+
+ result = platform_driver_register(&lirc_rpi_driver);
+ if (result) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": lirc register returned %d\n", result);
+ goto exit_buffer_free;
+ }
+
+ node = of_find_compatible_node(NULL, NULL,
+ lirc_rpi_of_match[0].compatible);
+
+ if (node) {
+ /* DT-enabled */
+ lirc_rpi_dev = of_find_device_by_node(node);
+ WARN_ON(lirc_rpi_dev->dev.of_node != node);
+ of_node_put(node);
+ }
+ else {
+ lirc_rpi_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
+ if (!lirc_rpi_dev) {
+ result = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ result = platform_device_add(lirc_rpi_dev);
+ if (result)
+ goto exit_device_put;
+ }
+
+ return 0;
+
+ exit_device_put:
+ platform_device_put(lirc_rpi_dev);
+
+ exit_driver_unregister:
+ platform_driver_unregister(&lirc_rpi_driver);
+
+ exit_buffer_free:
+ lirc_buffer_free(&rbuf);
+
+ return result;
+}
+
+static void lirc_rpi_exit(void)
+{
+ if (!lirc_rpi_dev->dev.of_node)
+ platform_device_unregister(lirc_rpi_dev);
+ platform_driver_unregister(&lirc_rpi_driver);
+ lirc_buffer_free(&rbuf);
+}
+
+static int __init lirc_rpi_init_module(void)
+{
+ int result;
+
+ result = lirc_rpi_init();
+ if (result)
+ return result;
+
+ result = init_port();
+ if (result < 0)
+ goto exit_rpi;
+
+ driver.features = LIRC_CAN_SET_SEND_DUTY_CYCLE |
+ LIRC_CAN_SET_SEND_CARRIER |
+ LIRC_CAN_SEND_PULSE |
+ LIRC_CAN_REC_MODE2;
+
+ driver.dev = &lirc_rpi_dev->dev;
+ driver.minor = lirc_register_driver(&driver);
+
+ if (driver.minor < 0) {
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": device registration failed with %d\n", result);
+ result = -EIO;
+ goto exit_rpi;
+ }
+
+ printk(KERN_INFO LIRC_DRIVER_NAME ": driver registered!\n");
+
+ return 0;
+
+ exit_rpi:
+ lirc_rpi_exit();
+
+ return result;
+}
+
+static void __exit lirc_rpi_exit_module(void)
+{
+ lirc_unregister_driver(driver.minor);
+
+ gpio_free(gpio_out_pin);
+ gpio_free(gpio_in_pin);
+
+ lirc_rpi_exit();
+
+ printk(KERN_INFO LIRC_DRIVER_NAME ": cleaned up module\n");
+}
+
+module_init(lirc_rpi_init_module);
+module_exit(lirc_rpi_exit_module);
+
+MODULE_DESCRIPTION("Infra-red receiver and blaster driver for Raspberry Pi GPIO.");
+MODULE_AUTHOR("Aron Robert Szabo <aron@reon.hu>");
+MODULE_AUTHOR("Michael Bishop <cleverca22@gmail.com>");
+MODULE_LICENSE("GPL");
+
+module_param(gpio_out_pin, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_out_pin, "GPIO output/transmitter pin number of the BCM"
+ " processor. (default 17");
+
+module_param(gpio_in_pin, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
+ " (default 18");
+
+module_param(gpio_in_pull, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_in_pull, "GPIO input pin pull configuration."
+ " (0 = off, 1 = up, 2 = down, default down)");
+
+module_param(sense, int, S_IRUGO);
+MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit"
+ " (0 = active high, 1 = active low )");
+
+module_param(softcarrier, bool, S_IRUGO);
+MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)");
+
+module_param(invert, bool, S_IRUGO);
+MODULE_PARM_DESC(invert, "Invert output (0 = off, 1 = on, default off");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");

View File

@ -0,0 +1,268 @@
From ccdc49f30be0caec97b9b7e4352b8c63eb45acdd Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:49:20 +0100
Subject: [PATCH 017/121] Add cpufreq driver
Signed-off-by: popcornmix <popcornmix@gmail.com>
---
drivers/cpufreq/Kconfig.arm | 9 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/bcm2835-cpufreq.c | 224 ++++++++++++++++++++++++++++++++++++++
3 files changed, 234 insertions(+)
create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -258,6 +258,15 @@ config ARM_SPEAR_CPUFREQ
help
This adds the CPUFreq driver support for SPEAr SOCs.
+config ARM_BCM2835_CPUFREQ
+ depends on BCM2708_MBOX
+ bool "BCM2835 Driver"
+ default y
+ help
+ This adds the CPUFreq driver for BCM2835
+
+ If in doubt, say N.
+
config ARM_TEGRA_CPUFREQ
bool "TEGRA CPUFreq support"
depends on ARCH_TEGRA
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5p
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
--- /dev/null
+++ b/drivers/cpufreq/bcm2835-cpufreq.c
@@ -0,0 +1,224 @@
+/*****************************************************************************
+* Copyright 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+/*****************************************************************************
+* FILENAME: bcm2835-cpufreq.h
+* DESCRIPTION: This driver dynamically manages the CPU Frequency of the ARM
+* processor. Messages are sent to Videocore either setting or requesting the
+* frequency of the ARM in order to match an appropiate frequency to the current
+* usage of the processor. The policy which selects the frequency to use is
+* defined in the kernel .config file, but can be changed during runtime.
+*****************************************************************************/
+
+/* ---------- INCLUDES ---------- */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/platform_data/mailbox-bcm2708.h>
+
+/* ---------- DEFINES ---------- */
+/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
+#define MODULE_NAME "bcm2835-cpufreq"
+
+#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
+
+/* debug printk macros */
+#ifdef CPUFREQ_DEBUG_ENABLE
+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define print_debug(fmt,...)
+#endif
+#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
+#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
+
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the message id */
+ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
+ uint32_t data_size; /* amount of data being sent or received */
+ uint32_t dev_id; /* the ID of the clock/voltage to get or set */
+ uint32_t val; /* the value (e.g. rate (in Hz)) to set */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+/* ---------- GLOBALS ---------- */
+static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
+
+static struct cpufreq_frequency_table bcm2835_freq_table[] = {
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, CPUFREQ_TABLE_END},
+};
+
+/*
+ ===============================================
+ clk_rate either gets or sets the clock rates.
+ ===============================================
+*/
+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
+{
+ int s, actual_rate=0;
+ struct vc_msg msg;
+
+ /* wipe all previous message data */
+ memset(&msg, 0, sizeof msg);
+
+ msg.msg_size = sizeof msg;
+
+ msg.tag.tag_id = VCMSG_SET_CLOCK_RATE;
+ msg.tag.buffer_size = 8;
+ msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */
+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
+ msg.tag.val = arm_rate * 1000;
+
+ /* send the message */
+ s = bcm_mailbox_property(&msg, sizeof msg);
+
+ /* check if it was all ok and return the rate in KHz */
+ if (s == 0 && (msg.request_code & 0x80000000))
+ actual_rate = msg.tag.val/1000;
+
+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, actual_rate);
+ return actual_rate;
+}
+
+static uint32_t bcm2835_cpufreq_get_clock(int tag)
+{
+ int s;
+ int arm_rate = 0;
+ struct vc_msg msg;
+
+ /* wipe all previous message data */
+ memset(&msg, 0, sizeof msg);
+
+ msg.msg_size = sizeof msg;
+ msg.tag.tag_id = tag;
+ msg.tag.buffer_size = 8;
+ msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */
+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
+
+ /* send the message */
+ s = bcm_mailbox_property(&msg, sizeof msg);
+
+ /* check if it was all ok and return the rate in KHz */
+ if (s == 0 && (msg.request_code & 0x80000000))
+ arm_rate = msg.tag.val/1000;
+
+ print_debug("%s frequency = %d\n",
+ tag == VCMSG_GET_CLOCK_RATE ? "Current":
+ tag == VCMSG_GET_MIN_CLOCK ? "Min":
+ tag == VCMSG_GET_MAX_CLOCK ? "Max":
+ "Unexpected", arm_rate);
+
+ return arm_rate;
+}
+
+/*
+ ====================================================
+ Module Initialisation registers the cpufreq driver
+ ====================================================
+*/
+static int __init bcm2835_cpufreq_module_init(void)
+{
+ print_debug("IN\n");
+ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
+}
+
+/*
+ =============
+ Module exit
+ =============
+*/
+static void __exit bcm2835_cpufreq_module_exit(void)
+{
+ print_debug("IN\n");
+ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
+ return;
+}
+
+/*
+ ==============================================================
+ Initialisation function sets up the CPU policy for first use
+ ==============================================================
+*/
+static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ /* measured value of how long it takes to change frequency */
+ const unsigned int transition_latency = 355000; /* ns */
+
+ /* now find out what the maximum and minimum frequencies are */
+ bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK);
+ bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK);
+
+ print_info("min=%d max=%d\n", bcm2835_freq_table[0].frequency, bcm2835_freq_table[1].frequency);
+ return cpufreq_generic_init(policy, bcm2835_freq_table, transition_latency);
+}
+
+/*
+ =====================================================================
+ Target index function chooses the requested frequency from the table
+ =====================================================================
+*/
+
+static int bcm2835_cpufreq_driver_target_index(struct cpufreq_policy *policy, unsigned int state)
+{
+ unsigned int target_freq = bcm2835_freq_table[state].frequency;
+ unsigned int cur = bcm2835_cpufreq_set_clock(policy->cur, target_freq);
+
+ if (!cur)
+ {
+ print_err("Error occurred setting a new frequency (%d)\n", target_freq);
+ return -EINVAL;
+ }
+ print_debug("%s: %i: freq %d->%d\n", policy->governor->name, state, policy->cur, cur);
+ return 0;
+}
+
+/*
+ ======================================================
+ Get function returns the current frequency from table
+ ======================================================
+*/
+
+static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
+{
+ unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
+ print_debug("%d: freq=%d\n", cpu, actual_rate);
+ return actual_rate <= bcm2835_freq_table[0].frequency ? bcm2835_freq_table[0].frequency : bcm2835_freq_table[1].frequency;
+}
+
+/* the CPUFreq driver */
+static struct cpufreq_driver bcm2835_cpufreq_driver = {
+ .name = "BCM2835 CPUFreq",
+ .init = bcm2835_cpufreq_driver_init,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = bcm2835_cpufreq_driver_target_index,
+ .get = bcm2835_cpufreq_driver_get,
+ .attr = cpufreq_generic_attr,
+};
+
+MODULE_AUTHOR("Dorian Peake and Dom Cobley");
+MODULE_DESCRIPTION("CPU frequency driver for BCM2835 chip");
+MODULE_LICENSE("GPL");
+
+module_init(bcm2835_cpufreq_module_init);
+module_exit(bcm2835_cpufreq_module_exit);

View File

@ -0,0 +1,288 @@
From b7e45ce253f9aa6f3f4b33967b124198d3e2b74f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 19:24:24 +0000
Subject: [PATCH 018/121] Added hwmon/thermal driver for reporting core
temperature. Thanks Dorian
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
BCM270x: Move thermal sensor to Device Tree
Add Device Tree support to bcm2835-thermal driver.
Add thermal sensor device to Device Tree.
Don't add platform device when booting in DT mode.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm2708/bcm2708.c | 6 ++
arch/arm/mach-bcm2709/bcm2709.c | 6 ++
drivers/thermal/Kconfig | 7 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/bcm2835-thermal.c | 190 ++++++++++++++++++++++++++++++++++++++
5 files changed, 210 insertions(+)
create mode 100644 drivers/thermal/bcm2835-thermal.c
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -505,6 +505,10 @@ static struct platform_device bcm2708_al
},
};
+static struct platform_device bcm2835_thermal_device = {
+ .name = "bcm2835_thermal",
+};
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -651,6 +655,8 @@ void __init bcm2708_init(void)
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+ bcm_register_device_dt(&bcm2835_thermal_device);
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -525,6 +525,10 @@ static struct platform_device bcm2708_al
},
};
+static struct platform_device bcm2835_thermal_device = {
+ .name = "bcm2835_thermal",
+};
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -671,6 +675,8 @@ void __init bcm2709_init(void)
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+ bcm_register_device_dt(&bcm2835_thermal_device);
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -238,6 +238,13 @@ config INTEL_POWERCLAMP
enforce idle time which results in more package C-state residency. The
user interface is exposed via generic thermal framework.
+config THERMAL_BCM2835
+ depends on BCM2708_MBOX
+ tristate "BCM2835 Thermal Driver"
+ help
+ This will enable temperature monitoring for the Broadcom BCM2835
+ chip. If built as a module, it will be called 'bcm2835-thermal'.
+
config X86_PKG_TEMP_THERMAL
tristate "X86 package temperature thermal driver"
depends on X86_THERMAL_VECTOR
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_t
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
+obj-$(CONFIG_THERMAL_BCM2835) += bcm2835-thermal.o
obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
--- /dev/null
+++ b/drivers/thermal/bcm2835-thermal.c
@@ -0,0 +1,190 @@
+/*****************************************************************************
+* Copyright 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_data/mailbox-bcm2708.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+
+
+/* --- DEFINITIONS --- */
+#define MODULE_NAME "bcm2835_thermal"
+
+/*#define THERMAL_DEBUG_ENABLE*/
+
+#ifdef THERMAL_DEBUG_ENABLE
+#define print_debug(fmt,...) printk(KERN_INFO "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define print_debug(fmt,...)
+#endif
+#define print_err(fmt,...) printk(KERN_ERR "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
+
+#define VC_TAG_GET_TEMP 0x00030006
+#define VC_TAG_GET_MAX_TEMP 0x0003000A
+
+typedef enum {
+ TEMP,
+ MAX_TEMP,
+} temp_type;
+
+/* --- STRUCTS --- */
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the tag ID for the temperature */
+ uint32_t buffer_size; /* size of the buffer (should be 8) */
+ uint32_t request_code; /* identifies message as a request (should be 0) */
+ uint32_t id; /* extra ID field (should be 0) */
+ uint32_t val; /* returned value of the temperature */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+struct bcm2835_thermal_data {
+ struct thermal_zone_device *thermal_dev;
+ struct vc_msg msg;
+};
+
+/* --- GLOBALS --- */
+static struct bcm2835_thermal_data bcm2835_data;
+
+/* Thermal Device Operations */
+static struct thermal_zone_device_ops ops;
+
+/* --- FUNCTIONS --- */
+
+static int bcm2835_get_temp_or_max(struct thermal_zone_device *thermal_dev, unsigned long *temp, unsigned tag_id)
+{
+ int result = -1, retry = 3;
+ print_debug("IN");
+
+ *temp = 0;
+ while (result != 0 && retry-- > 0) {
+ /* wipe all previous message data */
+ memset(&bcm2835_data.msg, 0, sizeof bcm2835_data.msg);
+
+ /* prepare message */
+ bcm2835_data.msg.msg_size = sizeof bcm2835_data.msg;
+ bcm2835_data.msg.tag.buffer_size = 8;
+ bcm2835_data.msg.tag.tag_id = tag_id;
+
+ /* send the message */
+ result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg);
+ print_debug("Got %stemperature as %u (%d,%x)\n", tag_id==VC_TAG_GET_MAX_TEMP ? "max ":"", (uint)bcm2835_data.msg.tag.val, result, bcm2835_data.msg.request_code);
+ if (!(bcm2835_data.msg.request_code & 0x80000000))
+ result = -1;
+ }
+
+ /* check if it was all ok and return the rate in milli degrees C */
+ if (result == 0)
+ *temp = (uint)bcm2835_data.msg.tag.val;
+ else
+ print_err("Failed to get temperature! (%x:%d)\n", tag_id, result);
+ print_debug("OUT");
+ return result;
+}
+
+static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *temp)
+{
+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_TEMP);
+}
+
+static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int trip_num, unsigned long *temp)
+{
+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_MAX_TEMP);
+}
+
+static int bcm2835_get_trip_type(struct thermal_zone_device * thermal_dev, int trip_num, enum thermal_trip_type *trip_type)
+{
+ *trip_type = THERMAL_TRIP_HOT;
+ return 0;
+}
+
+
+static int bcm2835_get_mode(struct thermal_zone_device *thermal_dev, enum thermal_device_mode *dev_mode)
+{
+ *dev_mode = THERMAL_DEVICE_ENABLED;
+ return 0;
+}
+
+
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+ print_debug("IN");
+ print_debug("THERMAL Driver has been probed!");
+
+ /* check that the device isn't null!*/
+ if(pdev == NULL)
+ {
+ print_debug("Platform device is empty!");
+ return -ENODEV;
+ }
+
+ if(!(bcm2835_data.thermal_dev = thermal_zone_device_register("bcm2835_thermal", 1, 0, NULL, &ops, NULL, 0, 0)))
+ {
+ print_debug("Unable to register the thermal device!");
+ return -EFAULT;
+ }
+ return 0;
+}
+
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+ print_debug("IN");
+
+ thermal_zone_device_unregister(bcm2835_data.thermal_dev);
+
+ print_debug("OUT");
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops ops = {
+ .get_temp = bcm2835_get_temp,
+ .get_trip_temp = bcm2835_get_max_temp,
+ .get_trip_type = bcm2835_get_trip_type,
+ .get_mode = bcm2835_get_mode,
+};
+
+static const struct of_device_id bcm2835_thermal_of_match_table[] = {
+ { .compatible = "brcm,bcm2835-thermal", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
+
+static struct platform_driver bcm2835_thermal_driver = {
+ .probe = bcm2835_thermal_probe,
+ .remove = bcm2835_thermal_remove,
+ .driver = {
+ .name = "bcm2835_thermal",
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2835_thermal_of_match_table,
+ },
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dorian Peake");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+
+module_platform_driver(bcm2835_thermal_driver);

View File

@ -0,0 +1,901 @@
From f65673287078cca868595a556d8613802e9a1743 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 15:41:33 +0100
Subject: [PATCH 019/121] Add Chris Boot's spi driver.
spi: bcm2708: add device tree support
Add DT support to driver and add to .dtsi file.
Setup pins and spidev in .dts file.
SPI is disabled by default.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
BCM2708: don't register SPI controller when using DT
The device for the SPI controller is in the Device Tree.
Only register the device when not using DT.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
spi: bcm2835: make driver available on ARCH_BCM2708
Make this driver available on ARCH_BCM2708
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
bcm2708: Remove the prohibition on mixing SPIDEV and DT
spi-bcm2708: Prepare for Common Clock Framework migration
As part of migrating to use the Common Clock Framework, replace clk_enable()
with clk_prepare_enable() and clk_disable() with clk_disable_unprepare().
This does not affect behaviour under the current clock implementation.
Also add a missing clk_disable_unprepare() in the probe error path.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
---
arch/arm/mach-bcm2708/Kconfig | 7 +
arch/arm/mach-bcm2708/bcm2708.c | 53 ++++
arch/arm/mach-bcm2709/bcm2709.c | 53 ++++
drivers/spi/Kconfig | 10 +-
drivers/spi/Makefile | 1 +
drivers/spi/spi-bcm2708.c | 635 ++++++++++++++++++++++++++++++++++++++++
6 files changed, 758 insertions(+), 1 deletion(-)
create mode 100644 drivers/spi/spi-bcm2708.c
--- a/arch/arm/mach-bcm2708/Kconfig
+++ b/arch/arm/mach-bcm2708/Kconfig
@@ -35,4 +35,11 @@ config BCM2708_NOL2CACHE
help
Do not allow ARM to use GPU's L2 cache. Requires disable_l2cache in config.txt.
+config BCM2708_SPIDEV
+ bool "Bind spidev to SPI0 master"
+ depends on MACH_BCM2708
+ depends on SPI
+ default y
+ help
+ Binds spidev driver to the SPI0 master
endmenu
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
#include <linux/version.h>
@@ -505,6 +506,50 @@ static struct platform_device bcm2708_al
},
};
+static struct resource bcm2708_spi_resources[] = {
+ {
+ .start = SPI0_BASE,
+ .end = SPI0_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_SPI,
+ .end = IRQ_SPI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+
+static u64 bcm2708_spi_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+static struct platform_device bcm2708_spi_device = {
+ .name = "bcm2708_spi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_spi_resources),
+ .resource = bcm2708_spi_resources,
+ .dev = {
+ .dma_mask = &bcm2708_spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON)},
+};
+
+#ifdef CONFIG_BCM2708_SPIDEV
+static struct spi_board_info bcm2708_spi_devices[] = {
+#ifdef CONFIG_SPI_SPIDEV
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 500000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ }, {
+ .modalias = "spidev",
+ .max_speed_hz = 500000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ }
+#endif
+};
+#endif
+
static struct platform_device bcm2835_thermal_device = {
.name = "bcm2835_thermal",
};
@@ -655,6 +700,8 @@ void __init bcm2708_init(void)
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+ bcm_register_device_dt(&bcm2708_spi_device);
+
bcm_register_device_dt(&bcm2835_thermal_device);
if (!use_dt) {
@@ -665,6 +712,12 @@ void __init bcm2708_init(void)
}
system_rev = boardrev;
system_serial_low = serial;
+
+#ifdef CONFIG_BCM2708_SPIDEV
+ if (!use_dt)
+ spi_register_board_info(bcm2708_spi_devices,
+ ARRAY_SIZE(bcm2708_spi_devices));
+#endif
}
static void timer_set_mode(enum clock_event_mode mode,
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -34,6 +34,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
#include <linux/version.h>
@@ -525,6 +526,50 @@ static struct platform_device bcm2708_al
},
};
+static struct resource bcm2708_spi_resources[] = {
+ {
+ .start = SPI0_BASE,
+ .end = SPI0_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_SPI,
+ .end = IRQ_SPI,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+
+static u64 bcm2708_spi_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
+static struct platform_device bcm2708_spi_device = {
+ .name = "bcm2708_spi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_spi_resources),
+ .resource = bcm2708_spi_resources,
+ .dev = {
+ .dma_mask = &bcm2708_spi_dmamask,
+ .coherent_dma_mask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON)},
+};
+
+#ifdef CONFIG_BCM2708_SPIDEV
+static struct spi_board_info bcm2708_spi_devices[] = {
+#ifdef CONFIG_SPI_SPIDEV
+ {
+ .modalias = "spidev",
+ .max_speed_hz = 500000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ }, {
+ .modalias = "spidev",
+ .max_speed_hz = 500000,
+ .bus_num = 0,
+ .chip_select = 1,
+ .mode = SPI_MODE_0,
+ }
+#endif
+};
+#endif
+
static struct platform_device bcm2835_thermal_device = {
.name = "bcm2835_thermal",
};
@@ -675,6 +720,8 @@ void __init bcm2709_init(void)
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+ bcm_register_device_dt(&bcm2708_spi_device);
+
bcm_register_device_dt(&bcm2835_thermal_device);
if (!use_dt) {
@@ -685,6 +732,12 @@ void __init bcm2709_init(void)
}
system_rev = boardrev;
system_serial_low = serial;
+
+#ifdef CONFIG_BCM2708_SPIDEV
+ if (!use_dt)
+ spi_register_board_info(bcm2708_spi_devices,
+ ARRAY_SIZE(bcm2708_spi_devices));
+#endif
}
#ifdef SYSTEM_TIMER
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -77,7 +77,7 @@ config SPI_ATMEL
config SPI_BCM2835
tristate "BCM2835 SPI controller"
- depends on ARCH_BCM2835 || COMPILE_TEST
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 || COMPILE_TEST
depends on GPIOLIB
help
This selects a driver for the Broadcom BCM2835 SPI master.
@@ -87,6 +87,14 @@ config SPI_BCM2835
is for the regular SPI controller. Slave mode operation is not also
not supported.
+config SPI_BCM2708
+ tristate "BCM2708 SPI controller driver (SPI0)"
+ depends on MACH_BCM2708 || MACH_BCM2709
+ help
+ This selects a driver for the Broadcom BCM2708 SPI master (SPI0). This
+ driver is not compatible with the "Universal SPI Master" or the SPI slave
+ device.
+
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN && !BF60x
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63x
obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o
obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o
obj-$(CONFIG_SPI_ADI_V3) += spi-adi-v3.o
+obj-$(CONFIG_SPI_BCM2708) += spi-bcm2708.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
--- /dev/null
+++ b/drivers/spi/spi-bcm2708.c
@@ -0,0 +1,635 @@
+/*
+ * Driver for Broadcom BCM2708 SPI Controllers
+ *
+ * Copyright (C) 2012 Chris Boot
+ *
+ * This driver is inspired by:
+ * spi-ath79.c, Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
+ * spi-atmel.c, Copyright (C) 2006 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+/* SPI register offsets */
+#define SPI_CS 0x00
+#define SPI_FIFO 0x04
+#define SPI_CLK 0x08
+#define SPI_DLEN 0x0c
+#define SPI_LTOH 0x10
+#define SPI_DC 0x14
+
+/* Bitfields in CS */
+#define SPI_CS_LEN_LONG 0x02000000
+#define SPI_CS_DMA_LEN 0x01000000
+#define SPI_CS_CSPOL2 0x00800000
+#define SPI_CS_CSPOL1 0x00400000
+#define SPI_CS_CSPOL0 0x00200000
+#define SPI_CS_RXF 0x00100000
+#define SPI_CS_RXR 0x00080000
+#define SPI_CS_TXD 0x00040000
+#define SPI_CS_RXD 0x00020000
+#define SPI_CS_DONE 0x00010000
+#define SPI_CS_LEN 0x00002000
+#define SPI_CS_REN 0x00001000
+#define SPI_CS_ADCS 0x00000800
+#define SPI_CS_INTR 0x00000400
+#define SPI_CS_INTD 0x00000200
+#define SPI_CS_DMAEN 0x00000100
+#define SPI_CS_TA 0x00000080
+#define SPI_CS_CSPOL 0x00000040
+#define SPI_CS_CLEAR_RX 0x00000020
+#define SPI_CS_CLEAR_TX 0x00000010
+#define SPI_CS_CPOL 0x00000008
+#define SPI_CS_CPHA 0x00000004
+#define SPI_CS_CS_10 0x00000002
+#define SPI_CS_CS_01 0x00000001
+
+#define SPI_TIMEOUT_MS 150
+
+#define DRV_NAME "bcm2708_spi"
+
+struct bcm2708_spi {
+ spinlock_t lock;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ bool stopping;
+
+ struct list_head queue;
+ struct workqueue_struct *workq;
+ struct work_struct work;
+ struct completion done;
+
+ const u8 *tx_buf;
+ u8 *rx_buf;
+ int len;
+};
+
+struct bcm2708_spi_state {
+ u32 cs;
+ u16 cdiv;
+};
+
+/*
+ * This function sets the ALT mode on the SPI pins so that we can use them with
+ * the SPI hardware.
+ *
+ * FIXME: This is a hack. Use pinmux / pinctrl.
+ */
+static void bcm2708_init_pinmode(void)
+{
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+ int pin;
+ u32 *gpio = ioremap(GPIO_BASE, SZ_16K);
+
+ /* SPI is on GPIO 7..11 */
+ for (pin = 7; pin <= 11; pin++) {
+ INP_GPIO(pin); /* set mode to GPIO input first */
+ SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
+ }
+
+ iounmap(gpio);
+
+#undef INP_GPIO
+#undef SET_GPIO_ALT
+}
+
+static inline u32 bcm2708_rd(struct bcm2708_spi *bs, unsigned reg)
+{
+ return readl(bs->base + reg);
+}
+
+static inline void bcm2708_wr(struct bcm2708_spi *bs, unsigned reg, u32 val)
+{
+ writel(val, bs->base + reg);
+}
+
+static inline void bcm2708_rd_fifo(struct bcm2708_spi *bs, int len)
+{
+ u8 byte;
+
+ while (len--) {
+ byte = bcm2708_rd(bs, SPI_FIFO);
+ if (bs->rx_buf)
+ *bs->rx_buf++ = byte;
+ }
+}
+
+static inline void bcm2708_wr_fifo(struct bcm2708_spi *bs, int len)
+{
+ u8 byte;
+ u16 val;
+
+ if (len > bs->len)
+ len = bs->len;
+
+ if (unlikely(bcm2708_rd(bs, SPI_CS) & SPI_CS_LEN)) {
+ /* LoSSI mode */
+ if (unlikely(len % 2)) {
+ printk(KERN_ERR"bcm2708_wr_fifo: length must be even, skipping.\n");
+ bs->len = 0;
+ return;
+ }
+ while (len) {
+ if (bs->tx_buf) {
+ val = *(const u16 *)bs->tx_buf;
+ bs->tx_buf += 2;
+ } else
+ val = 0;
+ bcm2708_wr(bs, SPI_FIFO, val);
+ bs->len -= 2;
+ len -= 2;
+ }
+ return;
+ }
+
+ while (len--) {
+ byte = bs->tx_buf ? *bs->tx_buf++ : 0;
+ bcm2708_wr(bs, SPI_FIFO, byte);
+ bs->len--;
+ }
+}
+
+static irqreturn_t bcm2708_spi_interrupt(int irq, void *dev_id)
+{
+ struct spi_master *master = dev_id;
+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
+ u32 cs;
+
+ spin_lock(&bs->lock);
+
+ cs = bcm2708_rd(bs, SPI_CS);
+
+ if (cs & SPI_CS_DONE) {
+ if (bs->len) { /* first interrupt in a transfer */
+ /* fill the TX fifo with up to 16 bytes */
+ bcm2708_wr_fifo(bs, 16);
+ } else { /* transfer complete */
+ /* disable interrupts */
+ cs &= ~(SPI_CS_INTR | SPI_CS_INTD);
+ bcm2708_wr(bs, SPI_CS, cs);
+
+ /* drain RX FIFO */
+ while (cs & SPI_CS_RXD) {
+ bcm2708_rd_fifo(bs, 1);
+ cs = bcm2708_rd(bs, SPI_CS);
+ }
+
+ /* wake up our bh */
+ complete(&bs->done);
+ }
+ } else if (cs & SPI_CS_RXR) {
+ /* read 12 bytes of data */
+ bcm2708_rd_fifo(bs, 12);
+
+ /* write up to 12 bytes */
+ bcm2708_wr_fifo(bs, 12);
+ }
+
+ spin_unlock(&bs->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm2708_setup_state(struct spi_master *master,
+ struct device *dev, struct bcm2708_spi_state *state,
+ u32 hz, u8 csel, u8 mode, u8 bpw)
+{
+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
+ int cdiv;
+ unsigned long bus_hz;
+ u32 cs = 0;
+
+ bus_hz = clk_get_rate(bs->clk);
+
+ if (hz >= bus_hz) {
+ cdiv = 2; /* bus_hz / 2 is as fast as we can go */
+ } else if (hz) {
+ cdiv = DIV_ROUND_UP(bus_hz, hz);
+
+ /* CDIV must be a power of 2, so round up */
+ cdiv = roundup_pow_of_two(cdiv);
+
+ if (cdiv > 65536) {
+ dev_dbg(dev,
+ "setup: %d Hz too slow, cdiv %u; min %ld Hz\n",
+ hz, cdiv, bus_hz / 65536);
+ return -EINVAL;
+ } else if (cdiv == 65536) {
+ cdiv = 0;
+ } else if (cdiv == 1) {
+ cdiv = 2; /* 1 gets rounded down to 0; == 65536 */
+ }
+ } else {
+ cdiv = 0;
+ }
+
+ switch (bpw) {
+ case 8:
+ break;
+ case 9:
+ /* Reading in LoSSI mode is a special case. See 'BCM2835 ARM Peripherals' datasheet */
+ cs |= SPI_CS_LEN;
+ break;
+ default:
+ dev_dbg(dev, "setup: invalid bits_per_word %u (must be 8 or 9)\n",
+ bpw);
+ return -EINVAL;
+ }
+
+ if (mode & SPI_CPOL)
+ cs |= SPI_CS_CPOL;
+ if (mode & SPI_CPHA)
+ cs |= SPI_CS_CPHA;
+
+ if (!(mode & SPI_NO_CS)) {
+ if (mode & SPI_CS_HIGH) {
+ cs |= SPI_CS_CSPOL;
+ cs |= SPI_CS_CSPOL0 << csel;
+ }
+
+ cs |= csel;
+ } else {
+ cs |= SPI_CS_CS_10 | SPI_CS_CS_01;
+ }
+
+ if (state) {
+ state->cs = cs;
+ state->cdiv = cdiv;
+ dev_dbg(dev, "setup: want %d Hz; "
+ "bus_hz=%lu / cdiv=%u == %lu Hz; "
+ "mode %u: cs 0x%08X\n",
+ hz, bus_hz, cdiv, bus_hz/cdiv, mode, cs);
+ }
+
+ return 0;
+}
+
+static int bcm2708_process_transfer(struct bcm2708_spi *bs,
+ struct spi_message *msg, struct spi_transfer *xfer)
+{
+ struct spi_device *spi = msg->spi;
+ struct bcm2708_spi_state state, *stp;
+ int ret;
+ u32 cs;
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ if (xfer->bits_per_word || xfer->speed_hz) {
+ ret = bcm2708_setup_state(spi->master, &spi->dev, &state,
+ xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
+ spi->chip_select, spi->mode,
+ xfer->bits_per_word ? xfer->bits_per_word :
+ spi->bits_per_word);
+ if (ret)
+ return ret;
+
+ stp = &state;
+ } else {
+ stp = spi->controller_state;
+ }
+
+ reinit_completion(&bs->done);
+ bs->tx_buf = xfer->tx_buf;
+ bs->rx_buf = xfer->rx_buf;
+ bs->len = xfer->len;
+
+ cs = stp->cs | SPI_CS_INTR | SPI_CS_INTD | SPI_CS_TA;
+
+ bcm2708_wr(bs, SPI_CLK, stp->cdiv);
+ bcm2708_wr(bs, SPI_CS, cs);
+
+ ret = wait_for_completion_timeout(&bs->done,
+ msecs_to_jiffies(SPI_TIMEOUT_MS));
+ if (ret == 0) {
+ dev_err(&spi->dev, "transfer timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if (xfer->delay_usecs)
+ udelay(xfer->delay_usecs);
+
+ if (list_is_last(&xfer->transfer_list, &msg->transfers) ||
+ xfer->cs_change) {
+ /* clear TA and interrupt flags */
+ bcm2708_wr(bs, SPI_CS, stp->cs);
+ }
+
+ msg->actual_length += (xfer->len - bs->len);
+
+ return 0;
+}
+
+static void bcm2708_work(struct work_struct *work)
+{
+ struct bcm2708_spi *bs = container_of(work, struct bcm2708_spi, work);
+ unsigned long flags;
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+ int status = 0;
+
+ spin_lock_irqsave(&bs->lock, flags);
+ while (!list_empty(&bs->queue)) {
+ msg = list_first_entry(&bs->queue, struct spi_message, queue);
+ list_del_init(&msg->queue);
+ spin_unlock_irqrestore(&bs->lock, flags);
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ status = bcm2708_process_transfer(bs, msg, xfer);
+ if (status)
+ break;
+ }
+
+ msg->status = status;
+ msg->complete(msg->context);
+
+ spin_lock_irqsave(&bs->lock, flags);
+ }
+ spin_unlock_irqrestore(&bs->lock, flags);
+}
+
+static int bcm2708_spi_setup(struct spi_device *spi)
+{
+ struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
+ struct bcm2708_spi_state *state;
+ int ret;
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ if (!(spi->mode & SPI_NO_CS) &&
+ (spi->chip_select > spi->master->num_chipselect)) {
+ dev_dbg(&spi->dev,
+ "setup: invalid chipselect %u (%u defined)\n",
+ spi->chip_select, spi->master->num_chipselect);
+ return -EINVAL;
+ }
+
+ state = spi->controller_state;
+ if (!state) {
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ spi->controller_state = state;
+ }
+
+ ret = bcm2708_setup_state(spi->master, &spi->dev, state,
+ spi->max_speed_hz, spi->chip_select, spi->mode,
+ spi->bits_per_word);
+ if (ret < 0) {
+ kfree(state);
+ spi->controller_state = NULL;
+ return ret;
+ }
+
+ dev_dbg(&spi->dev,
+ "setup: cd %d: %d Hz, bpw %u, mode 0x%x -> CS=%08x CDIV=%04x\n",
+ spi->chip_select, spi->max_speed_hz, spi->bits_per_word,
+ spi->mode, state->cs, state->cdiv);
+
+ return 0;
+}
+
+static int bcm2708_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct bcm2708_spi *bs = spi_master_get_devdata(spi->master);
+ struct spi_transfer *xfer;
+ int ret;
+ unsigned long flags;
+
+ if (unlikely(list_empty(&msg->transfers)))
+ return -EINVAL;
+
+ if (bs->stopping)
+ return -ESHUTDOWN;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+ if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) {
+ dev_dbg(&spi->dev, "missing rx or tx buf\n");
+ return -EINVAL;
+ }
+
+ if (!xfer->bits_per_word || xfer->speed_hz)
+ continue;
+
+ ret = bcm2708_setup_state(spi->master, &spi->dev, NULL,
+ xfer->speed_hz ? xfer->speed_hz : spi->max_speed_hz,
+ spi->chip_select, spi->mode,
+ xfer->bits_per_word ? xfer->bits_per_word :
+ spi->bits_per_word);
+ if (ret)
+ return ret;
+ }
+
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+ spin_lock_irqsave(&bs->lock, flags);
+ list_add_tail(&msg->queue, &bs->queue);
+ queue_work(bs->workq, &bs->work);
+ spin_unlock_irqrestore(&bs->lock, flags);
+
+ return 0;
+}
+
+static void bcm2708_spi_cleanup(struct spi_device *spi)
+{
+ if (spi->controller_state) {
+ kfree(spi->controller_state);
+ spi->controller_state = NULL;
+ }
+}
+
+static int bcm2708_spi_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ int irq, err = -ENOMEM;
+ struct clk *clk;
+ struct spi_master *master;
+ struct bcm2708_spi *bs;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "could not get IO memory\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "could not get IRQ\n");
+ return irq;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ bcm2708_init_pinmode();
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*bs));
+ if (!master) {
+ dev_err(&pdev->dev, "spi_alloc_master() failed\n");
+ goto out_clk_put;
+ }
+
+ /* the spi->mode bits understood by this driver: */
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_NO_CS;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = 3;
+ master->setup = bcm2708_spi_setup;
+ master->transfer = bcm2708_spi_transfer;
+ master->cleanup = bcm2708_spi_cleanup;
+ master->dev.of_node = pdev->dev.of_node;
+ platform_set_drvdata(pdev, master);
+
+ bs = spi_master_get_devdata(master);
+
+ spin_lock_init(&bs->lock);
+ INIT_LIST_HEAD(&bs->queue);
+ init_completion(&bs->done);
+ INIT_WORK(&bs->work, bcm2708_work);
+
+ bs->base = ioremap(regs->start, resource_size(regs));
+ if (!bs->base) {
+ dev_err(&pdev->dev, "could not remap memory\n");
+ goto out_master_put;
+ }
+
+ bs->workq = create_singlethread_workqueue(dev_name(&pdev->dev));
+ if (!bs->workq) {
+ dev_err(&pdev->dev, "could not create workqueue\n");
+ goto out_iounmap;
+ }
+
+ bs->irq = irq;
+ bs->clk = clk;
+ bs->stopping = false;
+
+ err = request_irq(irq, bcm2708_spi_interrupt, 0, dev_name(&pdev->dev),
+ master);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+ goto out_workqueue;
+ }
+
+ /* initialise the hardware */
+ clk_prepare_enable(clk);
+ bcm2708_wr(bs, SPI_CS, SPI_CS_REN | SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
+
+ err = spi_register_master(master);
+ if (err) {
+ dev_err(&pdev->dev, "could not register SPI master: %d\n", err);
+ goto out_free_irq;
+ }
+
+ dev_info(&pdev->dev, "SPI Controller at 0x%08lx (irq %d)\n",
+ (unsigned long)regs->start, irq);
+
+ return 0;
+
+out_free_irq:
+ free_irq(bs->irq, master);
+ clk_disable_unprepare(bs->clk);
+out_workqueue:
+ destroy_workqueue(bs->workq);
+out_iounmap:
+ iounmap(bs->base);
+out_master_put:
+ spi_master_put(master);
+out_clk_put:
+ clk_put(clk);
+ return err;
+}
+
+static int bcm2708_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcm2708_spi *bs = spi_master_get_devdata(master);
+
+ /* reset the hardware and block queue progress */
+ spin_lock_irq(&bs->lock);
+ bs->stopping = true;
+ bcm2708_wr(bs, SPI_CS, SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX);
+ spin_unlock_irq(&bs->lock);
+
+ flush_work(&bs->work);
+
+ clk_disable_unprepare(bs->clk);
+ clk_put(bs->clk);
+ free_irq(bs->irq, master);
+ iounmap(bs->base);
+
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2708_spi_match[] = {
+ { .compatible = "brcm,bcm2708-spi", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, bcm2708_spi_match);
+
+static struct platform_driver bcm2708_spi_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2708_spi_match,
+ },
+ .probe = bcm2708_spi_probe,
+ .remove = bcm2708_spi_remove,
+};
+
+
+static int __init bcm2708_spi_init(void)
+{
+ return platform_driver_probe(&bcm2708_spi_driver, bcm2708_spi_probe);
+}
+module_init(bcm2708_spi_init);
+
+static void __exit bcm2708_spi_exit(void)
+{
+ platform_driver_unregister(&bcm2708_spi_driver);
+}
+module_exit(bcm2708_spi_exit);
+
+
+//module_platform_driver(bcm2708_spi_driver);
+
+MODULE_DESCRIPTION("SPI controller driver for Broadcom BCM2708");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -0,0 +1,792 @@
From 31dade83cc4f448f81d7d460c59d02b9ebc3b05b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 17 Jun 2015 15:44:08 +0100
Subject: [PATCH 020/121] Add Chris Boot's i2c driver
i2c-bcm2708: fixed baudrate
Fixed issue where the wrong CDIV value was set for baudrates below 3815 Hz (for 250MHz bus clock).
In that case the computed CDIV value was more than 0xffff. However the CDIV register width is only 16 bits.
This resulted in incorrect setting of CDIV and higher baudrate than intended.
Example: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0x1704 -> 42430Hz
After correction: 3500Hz -> CDIV=0x11704 -> CDIV(16bit)=0xffff -> 3815Hz
The correct baudrate is shown in the log after the cdiv > 0xffff correction.
Perform I2C combined transactions when possible
Perform I2C combined transactions whenever possible, within the
restrictions of the Broadcomm Serial Controller.
Disable DONE interrupt during TA poll
Prevent interrupt from being triggered if poll is missed and transfer
starts and finishes.
i2c: Make combined transactions optional and disabled by default
i2c: bcm2708: add device tree support
Add DT support to driver and add to .dtsi file.
Setup pins in .dts file.
i2c is disabled by default.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
bcm2708: don't register i2c controllers when using DT
The devices for the i2c controllers are in the Device Tree.
Only register devices when not using DT.
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
I2C: Only register the I2C device for the current board revision
i2c_bcm2708: Fix clock reference counting
Fix grabbing lock from atomic context in i2c driver
2 main changes:
- check for timeouts in the bcm2708_bsc_setup function as indicated by this comment:
/* poll for transfer start bit (should only take 1-20 polls) */
This implies that the setup function can now fail so account for this everywhere it's called
- Removed the clk_get_rate call from inside the setup function as it locks a mutex and that's not ok since we call it from under a spin lock.
i2c-bcm2708: When using DT, leave the GPIO setup to pinctrl
---
arch/arm/mach-bcm2708/bcm2708.c | 51 ++++
arch/arm/mach-bcm2709/bcm2709.c | 51 ++++
drivers/i2c/busses/Kconfig | 21 +-
drivers/i2c/busses/Makefile | 2 +
drivers/i2c/busses/i2c-bcm2708.c | 522 +++++++++++++++++++++++++++++++++++++++
5 files changed, 646 insertions(+), 1 deletion(-)
create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -83,6 +83,7 @@ static unsigned uart_clock = UART0_CLOCK
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
+static bool vc_i2c_override = false;
static unsigned use_dt = 0;
@@ -550,6 +551,45 @@ static struct spi_board_info bcm2708_spi
};
#endif
+static struct resource bcm2708_bsc0_resources[] = {
+ {
+ .start = BSC0_BASE,
+ .end = BSC0_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = INTERRUPT_I2C,
+ .end = INTERRUPT_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device bcm2708_bsc0_device = {
+ .name = "bcm2708_i2c",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_bsc0_resources),
+ .resource = bcm2708_bsc0_resources,
+};
+
+
+static struct resource bcm2708_bsc1_resources[] = {
+ {
+ .start = BSC1_BASE,
+ .end = BSC1_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = INTERRUPT_I2C,
+ .end = INTERRUPT_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device bcm2708_bsc1_device = {
+ .name = "bcm2708_i2c",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bcm2708_bsc1_resources),
+ .resource = bcm2708_bsc1_resources,
+};
+
static struct platform_device bcm2835_thermal_device = {
.name = "bcm2835_thermal",
};
@@ -702,6 +742,15 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&bcm2708_spi_device);
+ if (vc_i2c_override) {
+ bcm_register_device_dt(&bcm2708_bsc0_device);
+ bcm_register_device_dt(&bcm2708_bsc1_device);
+ } else if ((boardrev & 0xffffff) == 0x2 || (boardrev & 0xffffff) == 0x3) {
+ bcm_register_device_dt(&bcm2708_bsc0_device);
+ } else {
+ bcm_register_device_dt(&bcm2708_bsc1_device);
+ }
+
bcm_register_device_dt(&bcm2835_thermal_device);
if (!use_dt) {
@@ -893,3 +942,5 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
+module_param(vc_i2c_override, bool, 0644);
+MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -85,6 +85,7 @@ static unsigned uart_clock = UART0_CLOCK
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
+static bool vc_i2c_override = false;
static unsigned use_dt = 0;
@@ -570,6 +571,45 @@ static struct spi_board_info bcm2708_spi
};
#endif
+static struct resource bcm2708_bsc0_resources[] = {
+ {
+ .start = BSC0_BASE,
+ .end = BSC0_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = INTERRUPT_I2C,
+ .end = INTERRUPT_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device bcm2708_bsc0_device = {
+ .name = "bcm2708_i2c",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_bsc0_resources),
+ .resource = bcm2708_bsc0_resources,
+};
+
+
+static struct resource bcm2708_bsc1_resources[] = {
+ {
+ .start = BSC1_BASE,
+ .end = BSC1_BASE + SZ_256 - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = INTERRUPT_I2C,
+ .end = INTERRUPT_I2C,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device bcm2708_bsc1_device = {
+ .name = "bcm2708_i2c",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(bcm2708_bsc1_resources),
+ .resource = bcm2708_bsc1_resources,
+};
+
static struct platform_device bcm2835_thermal_device = {
.name = "bcm2835_thermal",
};
@@ -722,6 +762,15 @@ void __init bcm2709_init(void)
bcm_register_device_dt(&bcm2708_spi_device);
+ if (vc_i2c_override) {
+ bcm_register_device_dt(&bcm2708_bsc0_device);
+ bcm_register_device_dt(&bcm2708_bsc1_device);
+ } else if ((boardrev & 0xffffff) == 0x2 || (boardrev & 0xffffff) == 0x3) {
+ bcm_register_device_dt(&bcm2708_bsc0_device);
+ } else {
+ bcm_register_device_dt(&bcm2708_bsc1_device);
+ }
+
bcm_register_device_dt(&bcm2835_thermal_device);
if (!use_dt) {
@@ -1061,3 +1110,5 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
+module_param(vc_i2c_override, bool, 0644);
+MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -8,6 +8,25 @@ menu "I2C Hardware Bus support"
comment "PC SMBus host controller drivers"
depends on PCI
+config I2C_BCM2708
+ tristate "BCM2708 BSC"
+ depends on MACH_BCM2708 || MACH_BCM2709
+ help
+ Enabling this option will add BSC (Broadcom Serial Controller)
+ support for the BCM2708. BSC is a Broadcom proprietary bus compatible
+ with I2C/TWI/SMBus.
+
+config I2C_BCM2708_BAUDRATE
+ prompt "BCM2708 I2C baudrate"
+ depends on I2C_BCM2708
+ int
+ default 100000
+ help
+ Set the I2C baudrate. This will alter the default value. A
+ different baudrate can be set by using a module parameter as well. If
+ no parameter is provided when loading, this is the value that will be
+ used.
+
config I2C_ALI1535
tristate "ALI 1535"
depends on PCI
@@ -362,7 +381,7 @@ config I2C_AXXIA
config I2C_BCM2835
tristate "Broadcom BCM2835 I2C controller"
- depends on ARCH_BCM2835
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
help
If you say yes to this option, support will be included for the
BCM2835 I2C controller.
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -2,6 +2,8 @@
# Makefile for the i2c bus drivers.
#
+obj-$(CONFIG_I2C_BCM2708) += i2c-bcm2708.o
+
# ACPI drivers
obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -0,0 +1,522 @@
+/*
+ * Driver for Broadcom BCM2708 BSC Controllers
+ *
+ * Copyright (C) 2012 Chris Boot & Frank Buss
+ *
+ * This driver is inspired by:
+ * i2c-ocores.c, by Peter Korsgaard <jacmet@sunsite.dk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+
+/* BSC register offsets */
+#define BSC_C 0x00
+#define BSC_S 0x04
+#define BSC_DLEN 0x08
+#define BSC_A 0x0c
+#define BSC_FIFO 0x10
+#define BSC_DIV 0x14
+#define BSC_DEL 0x18
+#define BSC_CLKT 0x1c
+
+/* Bitfields in BSC_C */
+#define BSC_C_I2CEN 0x00008000
+#define BSC_C_INTR 0x00000400
+#define BSC_C_INTT 0x00000200
+#define BSC_C_INTD 0x00000100
+#define BSC_C_ST 0x00000080
+#define BSC_C_CLEAR_1 0x00000020
+#define BSC_C_CLEAR_2 0x00000010
+#define BSC_C_READ 0x00000001
+
+/* Bitfields in BSC_S */
+#define BSC_S_CLKT 0x00000200
+#define BSC_S_ERR 0x00000100
+#define BSC_S_RXF 0x00000080
+#define BSC_S_TXE 0x00000040
+#define BSC_S_RXD 0x00000020
+#define BSC_S_TXD 0x00000010
+#define BSC_S_RXR 0x00000008
+#define BSC_S_TXW 0x00000004
+#define BSC_S_DONE 0x00000002
+#define BSC_S_TA 0x00000001
+
+#define I2C_TIMEOUT_MS 150
+#define I2C_WAIT_LOOP_COUNT 40
+
+#define DRV_NAME "bcm2708_i2c"
+
+static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
+module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(baudrate, "The I2C baudrate");
+
+static bool combined = false;
+module_param(combined, bool, 0644);
+MODULE_PARM_DESC(combined, "Use combined transactions");
+
+struct bcm2708_i2c {
+ struct i2c_adapter adapter;
+
+ spinlock_t lock;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ u32 cdiv;
+
+ struct completion done;
+
+ struct i2c_msg *msg;
+ int pos;
+ int nmsgs;
+ bool error;
+};
+
+/*
+ * This function sets the ALT mode on the I2C pins so that we can use them with
+ * the BSC hardware.
+ *
+ * FIXME: This is a hack. Use pinmux / pinctrl.
+ */
+static void bcm2708_i2c_init_pinmode(int id)
+{
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+ int pin;
+ u32 *gpio = ioremap(GPIO_BASE, SZ_16K);
+
+ BUG_ON(id != 0 && id != 1);
+ /* BSC0 is on GPIO 0 & 1, BSC1 is on GPIO 2 & 3 */
+ for (pin = id*2+0; pin <= id*2+1; pin++) {
+ printk("bcm2708_i2c_init_pinmode(%d,%d)\n", id, pin);
+ INP_GPIO(pin); /* set mode to GPIO input first */
+ SET_GPIO_ALT(pin, 0); /* set mode to ALT 0 */
+ }
+
+ iounmap(gpio);
+
+#undef INP_GPIO
+#undef SET_GPIO_ALT
+}
+
+static inline u32 bcm2708_rd(struct bcm2708_i2c *bi, unsigned reg)
+{
+ return readl(bi->base + reg);
+}
+
+static inline void bcm2708_wr(struct bcm2708_i2c *bi, unsigned reg, u32 val)
+{
+ writel(val, bi->base + reg);
+}
+
+static inline void bcm2708_bsc_reset(struct bcm2708_i2c *bi)
+{
+ bcm2708_wr(bi, BSC_C, 0);
+ bcm2708_wr(bi, BSC_S, BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
+}
+
+static inline void bcm2708_bsc_fifo_drain(struct bcm2708_i2c *bi)
+{
+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_RXD) && (bi->pos < bi->msg->len))
+ bi->msg->buf[bi->pos++] = bcm2708_rd(bi, BSC_FIFO);
+}
+
+static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
+{
+ while ((bcm2708_rd(bi, BSC_S) & BSC_S_TXD) && (bi->pos < bi->msg->len))
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+}
+
+static inline int bcm2708_bsc_setup(struct bcm2708_i2c *bi)
+{
+ u32 cdiv, s;
+ u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
+ int wait_loops = I2C_WAIT_LOOP_COUNT;
+
+ /* Can't call clk_get_rate as it locks a mutex and here we are spinlocked.
+ * Use the value that we cached in the probe.
+ */
+ cdiv = bi->cdiv;
+
+ if (bi->msg->flags & I2C_M_RD)
+ c |= BSC_C_INTR | BSC_C_READ;
+ else
+ c |= BSC_C_INTT;
+
+ bcm2708_wr(bi, BSC_DIV, cdiv);
+ bcm2708_wr(bi, BSC_A, bi->msg->addr);
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+ if (combined)
+ {
+ /* Do the next two messages meet combined transaction criteria?
+ - Current message is a write, next message is a read
+ - Both messages to same slave address
+ - Write message can fit inside FIFO (16 bytes or less) */
+ if ( (bi->nmsgs > 1) &&
+ !(bi->msg[0].flags & I2C_M_RD) && (bi->msg[1].flags & I2C_M_RD) &&
+ (bi->msg[0].addr == bi->msg[1].addr) && (bi->msg[0].len <= 16)) {
+ /* Fill FIFO with entire write message (16 byte FIFO) */
+ while (bi->pos < bi->msg->len) {
+ bcm2708_wr(bi, BSC_FIFO, bi->msg->buf[bi->pos++]);
+ }
+ /* Start write transfer (no interrupts, don't clear FIFO) */
+ bcm2708_wr(bi, BSC_C, BSC_C_I2CEN | BSC_C_ST);
+
+ /* poll for transfer start bit (should only take 1-20 polls) */
+ do {
+ s = bcm2708_rd(bi, BSC_S);
+ } while (!(s & (BSC_S_TA | BSC_S_ERR | BSC_S_CLKT | BSC_S_DONE)) && --wait_loops >= 0);
+
+ /* did we time out or some error occured? */
+ if (wait_loops < 0 || (s & (BSC_S_ERR | BSC_S_CLKT))) {
+ return -1;
+ }
+
+ /* Send next read message before the write transfer finishes. */
+ bi->nmsgs--;
+ bi->msg++;
+ bi->pos = 0;
+ bcm2708_wr(bi, BSC_DLEN, bi->msg->len);
+ c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_INTR | BSC_C_ST | BSC_C_READ;
+ }
+ }
+ bcm2708_wr(bi, BSC_C, c);
+
+ return 0;
+}
+
+static irqreturn_t bcm2708_i2c_interrupt(int irq, void *dev_id)
+{
+ struct bcm2708_i2c *bi = dev_id;
+ bool handled = true;
+ u32 s;
+ int ret;
+
+ spin_lock(&bi->lock);
+
+ /* we may see camera interrupts on the "other" I2C channel
+ Just return if we've not sent anything */
+ if (!bi->nmsgs || !bi->msg) {
+ goto early_exit;
+ }
+
+ s = bcm2708_rd(bi, BSC_S);
+
+ if (s & (BSC_S_CLKT | BSC_S_ERR)) {
+ bcm2708_bsc_reset(bi);
+ bi->error = true;
+
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ } else if (s & BSC_S_DONE) {
+ bi->nmsgs--;
+
+ if (bi->msg->flags & I2C_M_RD) {
+ bcm2708_bsc_fifo_drain(bi);
+ }
+
+ bcm2708_bsc_reset(bi);
+
+ if (bi->nmsgs) {
+ /* advance to next message */
+ bi->msg++;
+ bi->pos = 0;
+ ret = bcm2708_bsc_setup(bi);
+ if (ret < 0) {
+ bcm2708_bsc_reset(bi);
+ bi->error = true;
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ goto early_exit;
+ }
+ } else {
+ bi->msg = 0; /* to inform the that all work is done */
+ bi->nmsgs = 0;
+ /* wake up our bh */
+ complete(&bi->done);
+ }
+ } else if (s & BSC_S_TXW) {
+ bcm2708_bsc_fifo_fill(bi);
+ } else if (s & BSC_S_RXR) {
+ bcm2708_bsc_fifo_drain(bi);
+ } else {
+ handled = false;
+ }
+
+early_exit:
+ spin_unlock(&bi->lock);
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int bcm2708_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct bcm2708_i2c *bi = adap->algo_data;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&bi->lock, flags);
+
+ reinit_completion(&bi->done);
+ bi->msg = msgs;
+ bi->pos = 0;
+ bi->nmsgs = num;
+ bi->error = false;
+
+ ret = bcm2708_bsc_setup(bi);
+
+ spin_unlock_irqrestore(&bi->lock, flags);
+
+ /* check the result of the setup */
+ if (ret < 0)
+ {
+ dev_err(&adap->dev, "transfer setup timed out\n");
+ goto error_timeout;
+ }
+
+ ret = wait_for_completion_timeout(&bi->done, msecs_to_jiffies(I2C_TIMEOUT_MS));
+ if (ret == 0) {
+ dev_err(&adap->dev, "transfer timed out\n");
+ goto error_timeout;
+ }
+
+ ret = bi->error ? -EIO : num;
+ return ret;
+
+error_timeout:
+ spin_lock_irqsave(&bi->lock, flags);
+ bcm2708_bsc_reset(bi);
+ bi->msg = 0; /* to inform the interrupt handler that there's nothing else to be done */
+ bi->nmsgs = 0;
+ spin_unlock_irqrestore(&bi->lock, flags);
+ return -ETIMEDOUT;
+}
+
+static u32 bcm2708_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | /*I2C_FUNC_10BIT_ADDR |*/ I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm bcm2708_i2c_algorithm = {
+ .master_xfer = bcm2708_i2c_master_xfer,
+ .functionality = bcm2708_i2c_functionality,
+};
+
+static int bcm2708_i2c_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ int irq, err = -ENOMEM;
+ struct clk *clk;
+ struct bcm2708_i2c *bi;
+ struct i2c_adapter *adap;
+ unsigned long bus_hz;
+ u32 cdiv;
+
+ if (pdev->dev.of_node) {
+ u32 bus_clk_rate;
+ pdev->id = of_alias_get_id(pdev->dev.of_node, "i2c");
+ if (pdev->id < 0) {
+ dev_err(&pdev->dev, "alias is missing\n");
+ return -EINVAL;
+ }
+ if (!of_property_read_u32(pdev->dev.of_node,
+ "clock-frequency", &bus_clk_rate))
+ baudrate = bus_clk_rate;
+ else
+ dev_warn(&pdev->dev,
+ "Could not read clock-frequency property\n");
+ }
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs) {
+ dev_err(&pdev->dev, "could not get IO memory\n");
+ return -ENXIO;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "could not get IRQ\n");
+ return irq;
+ }
+
+ clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "could not find clk: %ld\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ err = clk_prepare_enable(clk);
+ if (err) {
+ dev_err(&pdev->dev, "could not enable clk: %d\n", err);
+ goto out_clk_put;
+ }
+
+ if (!pdev->dev.of_node)
+ bcm2708_i2c_init_pinmode(pdev->id);
+
+ bi = kzalloc(sizeof(*bi), GFP_KERNEL);
+ if (!bi)
+ goto out_clk_disable;
+
+ platform_set_drvdata(pdev, bi);
+
+ adap = &bi->adapter;
+ adap->class = I2C_CLASS_HWMON | I2C_CLASS_DDC;
+ adap->algo = &bcm2708_i2c_algorithm;
+ adap->algo_data = bi;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+ strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name));
+ adap->dev.of_node = pdev->dev.of_node;
+
+ switch (pdev->id) {
+ case 0:
+ adap->class = I2C_CLASS_HWMON;
+ break;
+ case 1:
+ adap->class = I2C_CLASS_DDC;
+ break;
+ default:
+ dev_err(&pdev->dev, "can only bind to BSC 0 or 1\n");
+ err = -ENXIO;
+ goto out_free_bi;
+ }
+
+ spin_lock_init(&bi->lock);
+ init_completion(&bi->done);
+
+ bi->base = ioremap(regs->start, resource_size(regs));
+ if (!bi->base) {
+ dev_err(&pdev->dev, "could not remap memory\n");
+ goto out_free_bi;
+ }
+
+ bi->irq = irq;
+ bi->clk = clk;
+
+ err = request_irq(irq, bcm2708_i2c_interrupt, IRQF_SHARED,
+ dev_name(&pdev->dev), bi);
+ if (err) {
+ dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
+ goto out_iounmap;
+ }
+
+ bcm2708_bsc_reset(bi);
+
+ err = i2c_add_numbered_adapter(adap);
+ if (err < 0) {
+ dev_err(&pdev->dev, "could not add I2C adapter: %d\n", err);
+ goto out_free_irq;
+ }
+
+ bus_hz = clk_get_rate(bi->clk);
+ cdiv = bus_hz / baudrate;
+ if (cdiv > 0xffff) {
+ cdiv = 0xffff;
+ baudrate = bus_hz / cdiv;
+ }
+ bi->cdiv = cdiv;
+
+ dev_info(&pdev->dev, "BSC%d Controller at 0x%08lx (irq %d) (baudrate %d)\n",
+ pdev->id, (unsigned long)regs->start, irq, baudrate);
+
+ return 0;
+
+out_free_irq:
+ free_irq(bi->irq, bi);
+out_iounmap:
+ iounmap(bi->base);
+out_free_bi:
+ kfree(bi);
+out_clk_disable:
+ clk_disable_unprepare(clk);
+out_clk_put:
+ clk_put(clk);
+ return err;
+}
+
+static int bcm2708_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm2708_i2c *bi = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ i2c_del_adapter(&bi->adapter);
+ free_irq(bi->irq, bi);
+ iounmap(bi->base);
+ clk_disable_unprepare(bi->clk);
+ clk_put(bi->clk);
+ kfree(bi);
+
+ return 0;
+}
+
+static const struct of_device_id bcm2708_i2c_of_match[] = {
+ { .compatible = "brcm,bcm2708-i2c" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm2708_i2c_of_match);
+
+static struct platform_driver bcm2708_i2c_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = bcm2708_i2c_of_match,
+ },
+ .probe = bcm2708_i2c_probe,
+ .remove = bcm2708_i2c_remove,
+};
+
+// module_platform_driver(bcm2708_i2c_driver);
+
+
+static int __init bcm2708_i2c_init(void)
+{
+ return platform_driver_register(&bcm2708_i2c_driver);
+}
+
+static void __exit bcm2708_i2c_exit(void)
+{
+ platform_driver_unregister(&bcm2708_i2c_driver);
+}
+
+module_init(bcm2708_i2c_init);
+module_exit(bcm2708_i2c_exit);
+
+
+
+MODULE_DESCRIPTION("BSC controller driver for Broadcom BCM2708");
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,481 @@
From 5b2523aae9c5beb443315a7814633fc740992d07 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 11 May 2015 09:00:42 +0100
Subject: [PATCH 023/121] scripts: Add mkknlimg and knlinfo scripts from tools
repo
The Raspberry Pi firmware looks for a trailer on the kernel image to
determine whether it was compiled with Device Tree support enabled.
If the firmware finds a kernel without this trailer, or which has a
trailer indicating that it isn't DT-capable, it disables DT support
and reverts to using ATAGs.
The mkknlimg utility adds that trailer, having first analysed the
image to look for signs of DT support and the kernel version string.
knlinfo displays the contents of the trailer in the given kernel image.
scripts/mkknlimg: Add support for ARCH_BCM2835
Add a new trailer field indicating whether this is an ARCH_BCM2835
build, as opposed to MACH_BCM2708/9. If the loader finds this flag
is set it changes the default base dtb file name from bcm270x...
to bcm283y...
Also update knlinfo to show the status of the field.
---
scripts/knlinfo | 168 +++++++++++++++++++++++++++++++++
scripts/mkknlimg | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 443 insertions(+)
create mode 100755 scripts/knlinfo
create mode 100755 scripts/mkknlimg
--- /dev/null
+++ b/scripts/knlinfo
@@ -0,0 +1,168 @@
+#!/usr/bin/env perl
+# ----------------------------------------------------------------------
+# knlinfo by Phil Elwell for Raspberry Pi
+#
+# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
+#
+# Licensed under the terms of the GNU General Public License.
+# ----------------------------------------------------------------------
+
+use strict;
+use integer;
+
+use Fcntl ":seek";
+
+my $trailer_magic = 'RPTL';
+
+my %atom_formats =
+(
+ 'DTOK' => \&format_bool,
+ 'KVer' => \&format_string,
+ '283x' => \&format_bool,
+);
+
+if (@ARGV != 1)
+{
+ print ("Usage: knlinfo <kernel image>\n");
+ exit(1);
+}
+
+my $kernel_file = $ARGV[0];
+
+
+my ($atoms, $pos) = read_trailer($kernel_file);
+
+exit(1) if (!$atoms);
+
+printf("Kernel trailer found at %d/0x%x:\n", $pos, $pos);
+
+foreach my $atom (@$atoms)
+{
+ printf(" %s: %s\n", $atom->[0], format_atom($atom));
+}
+
+exit(0);
+
+sub read_trailer
+{
+ my ($kernel_file) = @_;
+ my $fh;
+
+ if (!open($fh, '<', $kernel_file))
+ {
+ print ("* Failed to open '$kernel_file'\n");
+ return undef;
+ }
+
+ if (!seek($fh, -12, SEEK_END))
+ {
+ print ("* seek error in '$kernel_file'\n");
+ return undef;
+ }
+
+ my $last_bytes;
+ sysread($fh, $last_bytes, 12);
+
+ my ($trailer_len, $data_len, $magic) = unpack('VVa4', $last_bytes);
+
+ if (($magic ne $trailer_magic) || ($data_len != 4))
+ {
+ print ("* no trailer\n");
+ return undef;
+ }
+ if (!seek($fh, -12, SEEK_END))
+ {
+ print ("* seek error in '$kernel_file'\n");
+ return undef;
+ }
+
+ $trailer_len -= 12;
+
+ while ($trailer_len > 0)
+ {
+ if ($trailer_len < 8)
+ {
+ print ("* truncated atom header in trailer\n");
+ return undef;
+ }
+ if (!seek($fh, -8, SEEK_CUR))
+ {
+ print ("* seek error in '$kernel_file'\n");
+ return undef;
+ }
+ $trailer_len -= 8;
+
+ my $atom_hdr;
+ sysread($fh, $atom_hdr, 8);
+ my ($atom_len, $atom_type) = unpack('Va4', $atom_hdr);
+
+ if ($trailer_len < $atom_len)
+ {
+ print ("* truncated atom data in trailer\n");
+ return undef;
+ }
+
+ my $rounded_len = (($atom_len + 3) & ~3);
+ if (!seek($fh, -(8 + $rounded_len), SEEK_CUR))
+ {
+ print ("* seek error in '$kernel_file'\n");
+ return undef;
+ }
+ $trailer_len -= $rounded_len;
+
+ my $atom_data;
+ sysread($fh, $atom_data, $atom_len);
+
+ if (!seek($fh, -$atom_len, SEEK_CUR))
+ {
+ print ("* seek error in '$kernel_file'\n");
+ return undef;
+ }
+
+ push @$atoms, [ $atom_type, $atom_data ];
+ }
+
+ if (($$atoms[-1][0] eq "\x00\x00\x00\x00") &&
+ ($$atoms[-1][1] eq ""))
+ {
+ pop @$atoms;
+ }
+ else
+ {
+ print ("* end marker missing from trailer\n");
+ }
+
+ return ($atoms, tell($fh));
+}
+
+sub format_atom
+{
+ my ($atom) = @_;
+
+ my $format_func = $atom_formats{$atom->[0]} || \&format_hex;
+ return $format_func->($atom->[1]);
+}
+
+sub format_bool
+{
+ my ($data) = @_;
+ return unpack('V', $data) ? 'true' : 'false';
+}
+
+sub format_int
+{
+ my ($data) = @_;
+ return unpack('V', $data);
+}
+
+sub format_string
+{
+ my ($data) = @_;
+ return '"'.$data.'"';
+}
+
+sub format_hex
+{
+ my ($data) = @_;
+ return unpack('H*', $data);
+}
--- /dev/null
+++ b/scripts/mkknlimg
@@ -0,0 +1,275 @@
+#!/usr/bin/env perl
+# ----------------------------------------------------------------------
+# mkknlimg by Phil Elwell for Raspberry Pi
+# based on extract-ikconfig by Dick Streefland
+#
+# (c) 2009,2010 Dick Streefland <dick@streefland.net>
+# (c) 2014,2015 Raspberry Pi (Trading) Limited <info@raspberrypi.org>
+#
+# Licensed under the terms of the GNU General Public License.
+# ----------------------------------------------------------------------
+
+use strict;
+use warnings;
+use integer;
+
+my $trailer_magic = 'RPTL';
+
+my $tmpfile1 = "/tmp/mkknlimg_$$.1";
+my $tmpfile2 = "/tmp/mkknlimg_$$.2";
+
+my $dtok = 0;
+my $is_283x = 0;
+
+while (@ARGV && ($ARGV[0] =~ /^-/))
+{
+ my $arg = shift(@ARGV);
+ if ($arg eq '--dtok')
+ {
+ $dtok = 1;
+ }
+ elsif ($arg eq '--283x')
+ {
+ $is_283x = 1;
+ }
+ else
+ {
+ print ("* Unknown option '$arg'\n");
+ usage();
+ }
+}
+
+usage() if (@ARGV != 2);
+
+my $kernel_file = $ARGV[0];
+my $out_file = $ARGV[1];
+
+if (! -r $kernel_file)
+{
+ print ("* File '$kernel_file' not found\n");
+ usage();
+}
+
+my @wanted_config_lines =
+(
+ 'CONFIG_BCM2708_DT',
+ 'CONFIG_ARCH_BCM2835'
+);
+
+my @wanted_strings =
+(
+ 'bcm2708_fb',
+ 'brcm,bcm2835-mmc',
+ 'brcm,bcm2835-sdhost',
+ 'brcm,bcm2708-pinctrl',
+ 'brcm,bcm2835-gpio',
+ 'brcm,bcm2835-pm-wdt'
+);
+
+my $res = try_extract($kernel_file, $tmpfile1);
+$res = try_decompress('\037\213\010', 'xy', 'gunzip', 0,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+$res = try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+$res = try_decompress('BZh', 'xy', 'bunzip2', 0,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+$res = try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+$res = try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+$res = try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
+ $kernel_file, $tmpfile1, $tmpfile2) if (!$res);
+
+my $append_trailer;
+my $trailer;
+my $kver = '?';
+
+$append_trailer = $dtok;
+
+if ($res)
+{
+ $kver = $res->{''} || '?';
+ print("Version: $kver\n");
+
+ $append_trailer = $dtok;
+ if (!$dtok)
+ {
+ if (config_bool($res, 'bcm2708_fb') ||
+ config_bool($res, 'brcm,bcm2835-mmc') ||
+ config_bool($res, 'brcm,bcm2835-sdhost'))
+ {
+ $dtok ||= config_bool($res, 'CONFIG_BCM2708_DT');
+ $dtok ||= config_bool($res, 'CONFIG_ARCH_BCM2835');
+ $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
+ $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
+ $is_283x ||= config_bool($res, 'CONFIG_ARCH_BCM2835');
+ $is_283x ||= config_bool($res, 'brcm,bcm2835-pm-wdt');
+ $append_trailer = 1;
+ }
+ else
+ {
+ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
+ }
+ }
+}
+elsif (!$dtok)
+{
+ print ("* Is this a valid kernel? In pass-through mode.\n");
+}
+
+if ($append_trailer)
+{
+ printf("DT: %s\n", $dtok ? "y" : "n");
+ printf("283x: %s\n", $is_283x ? "y" : "n");
+
+ my @atoms;
+
+ push @atoms, [ $trailer_magic, pack('V', 0) ];
+ push @atoms, [ 'KVer', $kver ];
+ push @atoms, [ 'DTOK', pack('V', $dtok) ];
+ push @atoms, [ '283x', pack('V', $is_283x) ];
+
+ $trailer = pack_trailer(\@atoms);
+ $atoms[0]->[1] = pack('V', length($trailer));
+
+ $trailer = pack_trailer(\@atoms);
+}
+
+my $ofh;
+my $total_len = 0;
+
+if ($out_file eq $kernel_file)
+{
+ die "* Failed to open '$out_file' for append\n"
+ if (!open($ofh, '>>', $out_file));
+ $total_len = tell($ofh);
+}
+else
+{
+ die "* Failed to open '$kernel_file'\n"
+ if (!open(my $ifh, '<', $kernel_file));
+ die "* Failed to create '$out_file'\n"
+ if (!open($ofh, '>', $out_file));
+
+ my $copybuf;
+ while (1)
+ {
+ my $bytes = sysread($ifh, $copybuf, 64*1024);
+ last if (!$bytes);
+ syswrite($ofh, $copybuf, $bytes);
+ $total_len += $bytes;
+ }
+ close($ifh);
+}
+
+if ($trailer)
+{
+ # Pad to word-alignment
+ syswrite($ofh, "\x000\x000\x000", (-$total_len & 0x3));
+ syswrite($ofh, $trailer);
+}
+
+close($ofh);
+
+exit($trailer ? 0 : 1);
+
+END {
+ unlink($tmpfile1) if ($tmpfile1);
+ unlink($tmpfile2) if ($tmpfile2);
+}
+
+
+sub usage
+{
+ print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
+ exit(1);
+}
+
+sub try_extract
+{
+ my ($knl, $tmp) = @_;
+
+ my $ver = `strings "$knl" | grep -a -E "^Linux version [1-9]"`;
+
+ return undef if (!$ver);
+
+ chomp($ver);
+
+ my $res = { ''=>$ver };
+ my $string_pattern = '^('.join('|', @wanted_strings).')$';
+
+ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
+ foreach my $match (@matches)
+ {
+ chomp($match);
+ $res->{$match} = 1;
+ }
+
+ my $config_pattern = '^('.join('|', @wanted_config_lines).')=(.*)$';
+ my $cf1 = 'IKCFG_ST\037\213\010';
+ my $cf2 = '0123456789';
+
+ my $pos = `tr "$cf1\n$cf2" "\n$cf2=" < "$knl" | grep -abo "^$cf2"`;
+ if ($pos)
+ {
+ $pos =~ s/:.*[\r\n]*$//s;
+ $pos += 8;
+ my $err = (system("tail -c+$pos \"$knl\" | zcat > $tmp 2> /dev/null") >> 8);
+ if (($err == 0) || ($err == 2))
+ {
+ if (open(my $fh, '<', $tmp))
+ {
+ while (my $line = <$fh>)
+ {
+ chomp($line);
+ $res->{$1} = $2 if ($line =~ /$config_pattern/);
+ }
+
+ close($fh);
+ }
+ }
+ }
+
+ return $res;
+}
+
+
+sub try_decompress
+{
+ my ($magic, $subst, $zcat, $idx, $knl, $tmp1, $tmp2) = @_;
+
+ my $pos = `tr "$magic\n$subst" "\n$subst=" < "$knl" | grep -abo "^$subst"`;
+ if ($pos)
+ {
+ chomp($pos);
+ $pos = (split(/[\r\n]+/, $pos))[$idx];
+ return undef if (!defined($pos));
+ $pos =~ s/:.*[\r\n]*$//s;
+ my $cmd = "tail -c+$pos \"$knl\" | $zcat > $tmp2 2> /dev/null";
+ my $err = (system($cmd) >> 8);
+ return undef if (($err != 0) && ($err != 2));
+
+ return try_extract($tmp2, $tmp1);
+ }
+
+ return undef;
+}
+
+sub pack_trailer
+{
+ my ($atoms) = @_;
+ my $trailer = pack('VV', 0, 0);
+ for (my $i = $#$atoms; $i>=0; $i--)
+ {
+ my $atom = $atoms->[$i];
+ $trailer .= pack('a*x!4Va4', $atom->[1], length($atom->[1]), $atom->[0]);
+ }
+ return $trailer;
+}
+
+sub config_bool
+{
+ my ($configs, $wanted) = @_;
+ my $val = $configs->{$wanted} || 'n';
+ return (($val eq 'y') || ($val eq '1'));
+}

View File

@ -0,0 +1,58 @@
From 2d9c312e5b7a52fc0e311f909bb475ecc68b1199 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 5 Dec 2014 17:26:26 +0000
Subject: [PATCH 024/121] fdt: Add support for the CONFIG_CMDLINE_EXTEND option
---
drivers/of/fdt.c | 29 ++++++++++++++++++++++++-----
1 file changed, 24 insertions(+), 5 deletions(-)
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -933,22 +933,38 @@ int __init early_init_dt_scan_chosen(uns
/* Retrieve command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
- if (p != NULL && l > 0)
- strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
- p = of_get_flat_dt_prop(node, "bootargs-append", &l);
- if (p != NULL && l > 0)
- strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
/*
* CONFIG_CMDLINE is meant to be a default in case nothing else
* managed to set the command line, unless CONFIG_CMDLINE_FORCE
* is set in which case we override whatever was found earlier.
+ *
+ * However, it can be useful to be able to treat the default as
+ * a starting point to be extended using CONFIG_CMDLINE_EXTEND.
*/
+ ((char *)data)[0] = '\0';
+
#ifdef CONFIG_CMDLINE
-#ifndef CONFIG_CMDLINE_FORCE
- if (!((char *)data)[0])
+ strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+
+ if (p != NULL && l > 0) {
+#if defined(CONFIG_CMDLINE_EXTEND)
+ int len = strlen(data);
+ if (len > 0) {
+ strlcat(data, " ", COMMAND_LINE_SIZE);
+ len++;
+ }
+ strlcpy((char *)data + len, p, min((int)l, COMMAND_LINE_SIZE - len));
+#elif defined(CONFIG_CMDLINE_FORCE)
+ pr_warning("Ignoring bootargs property (using the default kernel command line)\n");
+#else
+ /* Neither extend nor force - just override */
+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
#endif
- strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+ }
+#else /* CONFIG_CMDLINE */
+ if (p != NULL && l > 0)
+ strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
#endif /* CONFIG_CMDLINE */
pr_debug("Command line is: %s\n", (char*)data);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,91 @@
From 4559e395eaf5d2a4c9af93066c8edc7d184287e3 Mon Sep 17 00:00:00 2001
From: Siarhei Siamashka <siarhei.siamashka@gmail.com>
Date: Mon, 17 Jun 2013 13:32:11 +0300
Subject: [PATCH 026/121] fbdev: add FBIOCOPYAREA ioctl
Based on the patch authored by Ali Gholami Rudi at
https://lkml.org/lkml/2009/7/13/153
Provide an ioctl for userspace applications, but only if this operation
is hardware accelerated (otherwide it does not make any sense).
Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
---
drivers/video/fbdev/core/fbmem.c | 30 ++++++++++++++++++++++++++++++
include/uapi/linux/fb.h | 5 +++++
2 files changed, 35 insertions(+)
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1084,6 +1084,25 @@ fb_blank(struct fb_info *info, int blank
}
EXPORT_SYMBOL(fb_blank);
+static int fb_copyarea_user(struct fb_info *info,
+ struct fb_copyarea *copy)
+{
+ int ret = 0;
+ if (!lock_fb_info(info))
+ return -ENODEV;
+ if (copy->dx + copy->width > info->var.xres ||
+ copy->sx + copy->width > info->var.xres ||
+ copy->dy + copy->height > info->var.yres ||
+ copy->sy + copy->height > info->var.yres) {
+ ret = -EINVAL;
+ goto out;
+ }
+ info->fbops->fb_copyarea(info, copy);
+out:
+ unlock_fb_info(info);
+ return ret;
+}
+
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg)
{
@@ -1094,6 +1113,7 @@ static long do_fb_ioctl(struct fb_info *
struct fb_cmap cmap_from;
struct fb_cmap_user cmap;
struct fb_event event;
+ struct fb_copyarea copy;
void __user *argp = (void __user *)arg;
long ret = 0;
@@ -1211,6 +1231,15 @@ static long do_fb_ioctl(struct fb_info *
unlock_fb_info(info);
console_unlock();
break;
+ case FBIOCOPYAREA:
+ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
+ /* only provide this ioctl if it is accelerated */
+ if (copy_from_user(&copy, argp, sizeof(copy)))
+ return -EFAULT;
+ ret = fb_copyarea_user(info, &copy);
+ break;
+ }
+ /* fall through */
default:
if (!lock_fb_info(info))
return -ENODEV;
@@ -1365,6 +1394,7 @@ static long fb_compat_ioctl(struct file
case FBIOPAN_DISPLAY:
case FBIOGET_CON2FBMAP:
case FBIOPUT_CON2FBMAP:
+ case FBIOCOPYAREA:
arg = (unsigned long) compat_ptr(arg);
case FBIOBLANK:
ret = do_fb_ioctl(info, cmd, arg);
--- a/include/uapi/linux/fb.h
+++ b/include/uapi/linux/fb.h
@@ -34,6 +34,11 @@
#define FBIOPUT_MODEINFO 0x4617
#define FBIOGET_DISPINFO 0x4618
#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+/*
+ * HACK: use 'z' in order not to clash with any other ioctl numbers which might
+ * be concurrently added to the mainline kernel
+ */
+#define FBIOCOPYAREA _IOW('z', 0x21, struct fb_copyarea)
#define FB_TYPE_PACKED_PIXELS 0 /* Packed Pixels */
#define FB_TYPE_PLANES 1 /* Non interleaved planes */

View File

@ -0,0 +1,209 @@
From 68d4d166abf2d287a3b333bbae60e2c9c027fa71 Mon Sep 17 00:00:00 2001
From: Harm Hanemaaijer <fgenfb@yahoo.com>
Date: Thu, 20 Jun 2013 20:21:39 +0200
Subject: [PATCH 029/121] Speed up console framebuffer imageblit function
Especially on platforms with a slower CPU but a relatively high
framebuffer fill bandwidth, like current ARM devices, the existing
console monochrome imageblit function used to draw console text is
suboptimal for common pixel depths such as 16bpp and 32bpp. The existing
code is quite general and can deal with several pixel depths. By creating
special case functions for 16bpp and 32bpp, by far the most common pixel
formats used on modern systems, a significant speed-up is attained
which can be readily felt on ARM-based devices like the Raspberry Pi
and the Allwinner platform, but should help any platform using the
fb layer.
The special case functions allow constant folding, eliminating a number
of instructions including divide operations, and allow the use of an
unrolled loop, eliminating instructions with a variable shift size,
reducing source memory access instructions, and eliminating excessive
branching. These unrolled loops also allow much better code optimization
by the C compiler. The code that selects which optimized variant is used
is also simplified, eliminating integer divide instructions.
The speed-up, measured by timing 'cat file.txt' in the console, varies
between 40% and 70%, when testing on the Raspberry Pi and Allwinner
ARM-based platforms, depending on font size and the pixel depth, with
the greater benefit for 32bpp.
Signed-off-by: Harm Hanemaaijer <fgenfb@yahoo.com>
---
drivers/video/fbdev/core/cfbimgblt.c | 152 +++++++++++++++++++++++++++++++++--
1 file changed, 147 insertions(+), 5 deletions(-)
--- a/drivers/video/fbdev/core/cfbimgblt.c
+++ b/drivers/video/fbdev/core/cfbimgblt.c
@@ -28,6 +28,11 @@
*
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
+ * Modified by Harm Hanemaaijer (fgenfb@yahoo.com) 2013:
+ * - Provide optimized versions of fast_imageblit for 16 and 32bpp that are
+ * significantly faster than the previous implementation.
+ * - Simplify the fast/slow_imageblit selection code, avoiding integer
+ * divides.
*/
#include <linux/module.h>
#include <linux/string.h>
@@ -262,6 +267,133 @@ static inline void fast_imageblit(const
}
}
+/*
+ * Optimized fast_imageblit for bpp == 16. ppw = 2, bit_mask = 3 folded
+ * into the code, main loop unrolled.
+ */
+
+static inline void fast_imageblit16(const struct fb_image *image,
+ struct fb_info *p, u8 __iomem * dst1,
+ u32 fgcolor, u32 bgcolor)
+{
+ u32 fgx = fgcolor, bgx = bgcolor;
+ u32 spitch = (image->width + 7) / 8;
+ u32 end_mask, eorx;
+ const char *s = image->data, *src;
+ u32 __iomem *dst;
+ const u32 *tab = NULL;
+ int i, j, k;
+
+ tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le;
+
+ fgx <<= 16;
+ bgx <<= 16;
+ fgx |= fgcolor;
+ bgx |= bgcolor;
+
+ eorx = fgx ^ bgx;
+ k = image->width / 2;
+
+ for (i = image->height; i--;) {
+ dst = (u32 __iomem *) dst1;
+ src = s;
+
+ j = k;
+ while (j >= 4) {
+ u8 bits = *src;
+ end_mask = tab[(bits >> 6) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 4) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 2) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[bits & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ src++;
+ j -= 4;
+ }
+ if (j != 0) {
+ u8 bits = *src;
+ end_mask = tab[(bits >> 6) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ if (j >= 2) {
+ end_mask = tab[(bits >> 4) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ if (j == 3) {
+ end_mask = tab[(bits >> 2) & 3];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
+ }
+ }
+ }
+ dst1 += p->fix.line_length;
+ s += spitch;
+ }
+}
+
+/*
+ * Optimized fast_imageblit for bpp == 32. ppw = 1, bit_mask = 1 folded
+ * into the code, main loop unrolled.
+ */
+
+static inline void fast_imageblit32(const struct fb_image *image,
+ struct fb_info *p, u8 __iomem * dst1,
+ u32 fgcolor, u32 bgcolor)
+{
+ u32 fgx = fgcolor, bgx = bgcolor;
+ u32 spitch = (image->width + 7) / 8;
+ u32 end_mask, eorx;
+ const char *s = image->data, *src;
+ u32 __iomem *dst;
+ const u32 *tab = NULL;
+ int i, j, k;
+
+ tab = cfb_tab32;
+
+ eorx = fgx ^ bgx;
+ k = image->width;
+
+ for (i = image->height; i--;) {
+ dst = (u32 __iomem *) dst1;
+ src = s;
+
+ j = k;
+ while (j >= 8) {
+ u8 bits = *src;
+ end_mask = tab[(bits >> 7) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 6) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 5) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 4) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 3) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 2) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[(bits >> 1) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ end_mask = tab[bits & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ src++;
+ j -= 8;
+ }
+ if (j != 0) {
+ u32 bits = (u32) * src;
+ while (j > 1) {
+ end_mask = tab[(bits >> 7) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst++);
+ bits <<= 1;
+ j--;
+ }
+ end_mask = tab[(bits >> 7) & 1];
+ FB_WRITEL((end_mask & eorx) ^ bgx, dst);
+ }
+ dst1 += p->fix.line_length;
+ s += spitch;
+ }
+}
+
void cfb_imageblit(struct fb_info *p, const struct fb_image *image)
{
u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0;
@@ -294,11 +426,21 @@ void cfb_imageblit(struct fb_info *p, co
bgcolor = image->bg_color;
}
- if (32 % bpp == 0 && !start_index && !pitch_index &&
- ((width & (32/bpp-1)) == 0) &&
- bpp >= 8 && bpp <= 32)
- fast_imageblit(image, p, dst1, fgcolor, bgcolor);
- else
+ if (!start_index && !pitch_index) {
+ if (bpp == 32)
+ fast_imageblit32(image, p, dst1, fgcolor,
+ bgcolor);
+ else if (bpp == 16 && (width & 1) == 0)
+ fast_imageblit16(image, p, dst1, fgcolor,
+ bgcolor);
+ else if (bpp == 8 && (width & 3) == 0)
+ fast_imageblit(image, p, dst1, fgcolor,
+ bgcolor);
+ else
+ slow_imageblit(image, p, dst1, fgcolor,
+ bgcolor,
+ start_index, pitch_index);
+ } else
slow_imageblit(image, p, dst1, fgcolor, bgcolor,
start_index, pitch_index);
} else

View File

@ -0,0 +1,91 @@
From 5e3834b22d4c560ac1354cfff30a6713b6d94e64 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 17:26:38 +0000
Subject: [PATCH 030/121] Allow mac address to be set in smsc95xx
Signed-off-by: popcornmix <popcornmix@gmail.com>
---
drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 56 insertions(+)
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -59,6 +59,7 @@
#define SUSPEND_SUSPEND3 (0x08)
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+#define MAC_ADDR_LEN (6)
struct smsc95xx_priv {
u32 mac_cr;
@@ -74,6 +75,10 @@ static bool turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+static char *macaddr = ":";
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
u32 *data, int in_pm)
{
@@ -763,8 +768,59 @@ static int smsc95xx_ioctl(struct net_dev
return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
+/* Check the macaddr module parameter for a MAC address */
+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac)
+{
+ int i, j, got_num, num;
+ u8 mtbl[MAC_ADDR_LEN];
+
+ if (macaddr[0] == ':')
+ return 0;
+
+ i = 0;
+ j = 0;
+ num = 0;
+ got_num = 0;
+ while (j < MAC_ADDR_LEN) {
+ if (macaddr[i] && macaddr[i] != ':') {
+ got_num++;
+ if ('0' <= macaddr[i] && macaddr[i] <= '9')
+ num = num * 16 + macaddr[i] - '0';
+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F')
+ num = num * 16 + 10 + macaddr[i] - 'A';
+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f')
+ num = num * 16 + 10 + macaddr[i] - 'a';
+ else
+ break;
+ i++;
+ } else if (got_num == 2) {
+ mtbl[j++] = (u8) num;
+ num = 0;
+ got_num = 0;
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ if (j == MAC_ADDR_LEN) {
+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: "
+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2],
+ mtbl[3], mtbl[4], mtbl[5]);
+ for (i = 0; i < MAC_ADDR_LEN; i++)
+ dev_mac[i] = mtbl[i];
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
static void smsc95xx_init_mac_address(struct usbnet *dev)
{
+ /* Check module parameters */
+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr))
+ return;
+
/* try reading mac address from EEPROM */
if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN,
dev->net->dev_addr) == 0) {

View File

@ -0,0 +1,386 @@
From 9c50f6318fdf116e5abaeb05bffa0b65e48ba259 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 8 May 2013 11:46:50 +0100
Subject: [PATCH 031/121] enabling the realtime clock 1-wire chip DS1307 and
1-wire on GPIO4 (as a module)
1-wire: Add support for configuring pin for w1-gpio kernel module
See: https://github.com/raspberrypi/linux/pull/457
Add bitbanging pullups, use them for w1-gpio
Allows parasite power to work, uses module option pullup=1
bcm2708: Ensure 1-wire pullup is disabled by default, and expose as module parameter
Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
w1-gpio: Add gpiopin module parameter and correctly free up gpio pull-up pin, if set
Signed-off-by: Alex J Lennon <ajlennon@dynamicdevices.co.uk>
w1-gpio: Sort out the pullup/parasitic power tangle
---
arch/arm/mach-bcm2708/bcm2708.c | 29 +++++++++++++++++
arch/arm/mach-bcm2709/bcm2709.c | 29 +++++++++++++++++
drivers/w1/masters/w1-gpio.c | 69 +++++++++++++++++++++++++++++++++++++----
drivers/w1/w1.h | 6 ++++
drivers/w1/w1_int.c | 14 +++++++++
drivers/w1/w1_io.c | 18 +++++++++--
include/linux/w1-gpio.h | 1 +
7 files changed, 157 insertions(+), 9 deletions(-)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -36,6 +36,7 @@
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
+#include <linux/w1-gpio.h>
#include <linux/version.h>
#include <linux/clkdev.h>
@@ -77,12 +78,19 @@
*/
#define DMA_MASK_BITS_COMMON 32
+// use GPIO 4 for the one-wire GPIO pin, if enabled
+#define W1_GPIO 4
+// ensure one-wire GPIO pullup is disabled by default
+#define W1_PULLUP -1
+
/* command line parameters */
static unsigned boardrev, serial;
static unsigned uart_clock = UART0_CLOCK;
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
+static unsigned w1_gpio_pin = W1_GPIO;
+static unsigned w1_gpio_pullup = W1_PULLUP;
static bool vc_i2c_override = false;
static unsigned use_dt = 0;
@@ -303,6 +311,20 @@ static struct platform_device bcm2708_dm
.num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources),
};
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+ .pin = W1_GPIO,
+ .ext_pullup_enable_pin = W1_PULLUP,
+ .is_open_drain = 0,
+};
+
+static struct platform_device w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &w1_gpio_pdata,
+};
+#endif
+
static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
static struct platform_device bcm2708_fb_device = {
@@ -729,6 +751,11 @@ void __init bcm2708_init(void)
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+ w1_gpio_pdata.pin = w1_gpio_pin;
+ w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
+ bcm_register_device_dt(&w1_device);
+#endif
bcm_register_device_dt(&bcm2708_fb_device);
bcm_register_device_dt(&bcm2708_usb_device);
@@ -942,5 +969,7 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
+module_param(w1_gpio_pin, uint, 0644);
+module_param(w1_gpio_pullup, uint, 0644);
module_param(vc_i2c_override, bool, 0644);
MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -36,6 +36,7 @@
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
+#include <linux/w1-gpio.h>
#include <linux/version.h>
#include <linux/clkdev.h>
@@ -79,12 +80,19 @@
*/
#define DMA_MASK_BITS_COMMON 32
+// use GPIO 4 for the one-wire GPIO pin, if enabled
+#define W1_GPIO 4
+// ensure one-wire GPIO pullup is disabled by default
+#define W1_PULLUP -1
+
/* command line parameters */
static unsigned boardrev, serial;
static unsigned uart_clock = UART0_CLOCK;
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
+static unsigned w1_gpio_pin = W1_GPIO;
+static unsigned w1_gpio_pullup = W1_PULLUP;
static bool vc_i2c_override = false;
static unsigned use_dt = 0;
@@ -313,6 +321,20 @@ static struct platform_device bcm2708_dm
.num_resources = ARRAY_SIZE(bcm2708_dmaengine_resources),
};
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+ .pin = W1_GPIO,
+ .ext_pullup_enable_pin = W1_PULLUP,
+ .is_open_drain = 0,
+};
+
+static struct platform_device w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &w1_gpio_pdata,
+};
+#endif
+
static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
static struct platform_device bcm2708_fb_device = {
@@ -749,6 +771,11 @@ void __init bcm2709_init(void)
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+ w1_gpio_pdata.pin = w1_gpio_pin;
+ w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
+ bcm_register_device_dt(&w1_device);
+#endif
bcm_register_device_dt(&bcm2708_fb_device);
bcm_register_device_dt(&bcm2708_usb_device);
@@ -1110,5 +1137,7 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
+module_param(w1_gpio_pin, uint, 0644);
+module_param(w1_gpio_pullup, uint, 0644);
module_param(vc_i2c_override, bool, 0644);
MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -23,6 +23,19 @@
#include "../w1.h"
#include "../w1_int.h"
+static int w1_gpio_pullup = 0;
+static int w1_gpio_pullup_orig = 0;
+module_param_named(pullup, w1_gpio_pullup, int, 0);
+MODULE_PARM_DESC(pullup, "Enable parasitic power (power on data) mode");
+static int w1_gpio_pullup_pin = -1;
+static int w1_gpio_pullup_pin_orig = -1;
+module_param_named(extpullup, w1_gpio_pullup_pin, int, 0);
+MODULE_PARM_DESC(extpullup, "GPIO external pullup pin number");
+static int w1_gpio_pin = -1;
+static int w1_gpio_pin_orig = -1;
+module_param_named(gpiopin, w1_gpio_pin, int, 0);
+MODULE_PARM_DESC(gpiopin, "GPIO pin number");
+
static u8 w1_gpio_set_pullup(void *data, int delay)
{
struct w1_gpio_platform_data *pdata = data;
@@ -67,6 +80,16 @@ static u8 w1_gpio_read_bit(void *data)
return gpio_get_value(pdata->pin) ? 1 : 0;
}
+static void w1_gpio_bitbang_pullup(void *data, u8 on)
+{
+ struct w1_gpio_platform_data *pdata = data;
+
+ if (on)
+ gpio_direction_output(pdata->pin, 1);
+ else
+ gpio_direction_input(pdata->pin);
+}
+
#if defined(CONFIG_OF)
static const struct of_device_id w1_gpio_dt_ids[] = {
{ .compatible = "w1-gpio" },
@@ -80,6 +103,7 @@ static int w1_gpio_probe_dt(struct platf
struct w1_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *np = pdev->dev.of_node;
int gpio;
+ u32 value;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -88,6 +112,9 @@ static int w1_gpio_probe_dt(struct platf
if (of_get_property(np, "linux,open-drain", NULL))
pdata->is_open_drain = 1;
+ if (of_property_read_u32(np, "rpi,parasitic-power", &value) == 0)
+ pdata->parasitic_power = (value != 0);
+
gpio = of_get_gpio(np, 0);
if (gpio < 0) {
if (gpio != -EPROBE_DEFER)
@@ -103,7 +130,7 @@ static int w1_gpio_probe_dt(struct platf
if (gpio == -EPROBE_DEFER)
return gpio;
/* ignore other errors as the pullup gpio is optional */
- pdata->ext_pullup_enable_pin = gpio;
+ pdata->ext_pullup_enable_pin = (gpio >= 0) ? gpio : -1;
pdev->dev.platform_data = pdata;
@@ -113,13 +140,15 @@ static int w1_gpio_probe_dt(struct platf
static int w1_gpio_probe(struct platform_device *pdev)
{
struct w1_bus_master *master;
- struct w1_gpio_platform_data *pdata;
+ struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
int err;
- if (of_have_populated_dt()) {
- err = w1_gpio_probe_dt(pdev);
- if (err < 0)
- return err;
+ if(pdata == NULL) {
+ if (of_have_populated_dt()) {
+ err = w1_gpio_probe_dt(pdev);
+ if (err < 0)
+ return err;
+ }
}
pdata = dev_get_platdata(&pdev->dev);
@@ -136,6 +165,22 @@ static int w1_gpio_probe(struct platform
return -ENOMEM;
}
+ w1_gpio_pin_orig = pdata->pin;
+ w1_gpio_pullup_pin_orig = pdata->ext_pullup_enable_pin;
+ w1_gpio_pullup_orig = pdata->parasitic_power;
+
+ if(gpio_is_valid(w1_gpio_pin)) {
+ pdata->pin = w1_gpio_pin;
+ pdata->ext_pullup_enable_pin = -1;
+ pdata->parasitic_power = -1;
+ }
+ pdata->parasitic_power |= w1_gpio_pullup;
+ if(gpio_is_valid(w1_gpio_pullup_pin)) {
+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin;
+ }
+
+ dev_info(&pdev->dev, "gpio pin %d, external pullup pin %d, parasitic power %d\n", pdata->pin, pdata->ext_pullup_enable_pin, pdata->parasitic_power);
+
err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
if (err) {
dev_err(&pdev->dev, "gpio_request (pin) failed\n");
@@ -165,6 +210,14 @@ static int w1_gpio_probe(struct platform
master->set_pullup = w1_gpio_set_pullup;
}
+ if (pdata->parasitic_power) {
+ if (pdata->is_open_drain)
+ printk(KERN_ERR "w1-gpio 'pullup'(parasitic power) "
+ "option doesn't work with open drain GPIO\n");
+ else
+ master->bitbang_pullup = w1_gpio_bitbang_pullup;
+ }
+
err = w1_add_master_device(master);
if (err) {
dev_err(&pdev->dev, "w1_add_master device failed\n");
@@ -195,6 +248,10 @@ static int w1_gpio_remove(struct platfor
w1_remove_master_device(master);
+ pdata->pin = w1_gpio_pin_orig;
+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_pin_orig;
+ pdata->parasitic_power = w1_gpio_pullup_orig;
+
return 0;
}
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -171,6 +171,12 @@ struct w1_bus_master
u8 (*set_pullup)(void *, int);
+ /**
+ * Turns the pullup on/off in bitbanging mode, takes an on/off argument.
+ * @return -1=Error, 0=completed
+ */
+ void (*bitbang_pullup) (void *, u8);
+
void (*search)(void *, struct w1_master *,
u8, w1_slave_found_callback);
};
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -123,6 +123,20 @@ int w1_add_master_device(struct w1_bus_m
return(-EINVAL);
}
+ /* bitbanging hardware uses bitbang_pullup, other hardware uses set_pullup
+ * and takes care of timing itself */
+ if (!master->write_byte && !master->touch_bit && master->set_pullup) {
+ printk(KERN_ERR "w1_add_master_device: set_pullup requires "
+ "write_byte or touch_bit, disabling\n");
+ master->set_pullup = NULL;
+ }
+
+ if (master->set_pullup && master->bitbang_pullup) {
+ printk(KERN_ERR "w1_add_master_device: set_pullup should not "
+ "be set when bitbang_pullup is used, disabling\n");
+ master->set_pullup = NULL;
+ }
+
/* Lock until the device is added (or not) to w1_masters. */
mutex_lock(&w1_mlock);
/* Search for the first available id (starting at 1). */
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -134,10 +134,22 @@ static void w1_pre_write(struct w1_maste
static void w1_post_write(struct w1_master *dev)
{
if (dev->pullup_duration) {
- if (dev->enable_pullup && dev->bus_master->set_pullup)
- dev->bus_master->set_pullup(dev->bus_master->data, 0);
- else
+ if (dev->enable_pullup) {
+ if (dev->bus_master->set_pullup) {
+ dev->bus_master->set_pullup(dev->
+ bus_master->data,
+ 0);
+ } else if (dev->bus_master->bitbang_pullup) {
+ dev->bus_master->
+ bitbang_pullup(dev->bus_master->data, 1);
msleep(dev->pullup_duration);
+ dev->bus_master->
+ bitbang_pullup(dev->bus_master->data, 0);
+ }
+ } else {
+ msleep(dev->pullup_duration);
+ }
+
dev->pullup_duration = 0;
}
}
--- a/include/linux/w1-gpio.h
+++ b/include/linux/w1-gpio.h
@@ -18,6 +18,7 @@
struct w1_gpio_platform_data {
unsigned int pin;
unsigned int is_open_drain:1;
+ unsigned int parasitic_power:1;
void (*enable_external_pullup)(int enable);
unsigned int ext_pullup_enable_pin;
unsigned int pullup_duration;

View File

@ -0,0 +1,22 @@
From 0c549d69d2a3c2d068d0364dba73a14d16fc5b22 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:54:08 +0100
Subject: [PATCH 032/121] Added Device IDs for August DVB-T 205
---
drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1744,6 +1744,10 @@ static const struct usb_device_id rtl28x
&rtl28xxu_props, "Compro VideoMate U620F", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
&rtl28xxu_props, "MaxMedia HU394-T", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xb803 /*USB_PID_AUGUST_DVBT205*/,
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
+ { DVB_USB_DEVICE(USB_VID_GTEK, 0xa803 /*USB_PID_AUGUST_DVBT205*/,
+ &rtl28xxu_props, "August DVB-T 205", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
&rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,

View File

@ -0,0 +1,53 @@
From 2722779be49b7b76dea3de564e03d9fd0083f094 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 18 Dec 2013 22:16:19 +0000
Subject: [PATCH 033/121] config: Enable CONFIG_MEMCG, but leave it disabled
(due to memory cost). Enable with cgroup_enable=memory.
---
kernel/cgroup.c | 23 +++++++++++++++++++++++
mm/memcontrol.c | 1 +
2 files changed, 24 insertions(+)
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -5395,6 +5395,29 @@ static int __init cgroup_disable(char *s
}
__setup("cgroup_disable=", cgroup_disable);
+static int __init cgroup_enable(char *str)
+{
+ struct cgroup_subsys *ss;
+ char *token;
+ int i;
+
+ while ((token = strsep(&str, ",")) != NULL) {
+ if (!*token)
+ continue;
+
+ for_each_subsys(ss, i) {
+ if (!strcmp(token, ss->name)) {
+ ss->disabled = 0;
+ printk(KERN_INFO "Enabling %s control group"
+ " subsystem\n", ss->name);
+ break;
+ }
+ }
+ }
+ return 1;
+}
+__setup("cgroup_enable=", cgroup_enable);
+
static int __init cgroup_set_legacy_files_on_dfl(char *str)
{
printk("cgroup: using legacy files on the default hierarchy\n");
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -5388,6 +5388,7 @@ struct cgroup_subsys memory_cgrp_subsys
.dfl_cftypes = memory_files,
.legacy_cftypes = mem_cgroup_legacy_files,
.early_init = 0,
+ .disabled = 1,
};
/**

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,120 @@
From c368e010eacbc50e6a5f527fcc8651ea1cdc5f26 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 14:59:51 +0100
Subject: [PATCH 035/121] ASoC: Add support for PCM5102A codec
Some definitions to support the PCM5102A codec
by Texas Instruments.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
sound/soc/codecs/Kconfig | 4 +++
sound/soc/codecs/Makefile | 2 ++
sound/soc/codecs/pcm5102a.c | 63 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+)
create mode 100644 sound/soc/codecs/pcm5102a.c
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -83,6 +83,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
+ select SND_SOC_PCM5102A if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_RT5645 if I2C
@@ -511,6 +512,9 @@ config SND_SOC_RT286
tristate
depends on I2C
+config SND_SOC_PCM5102A
+ tristate
+
config SND_SOC_RT5631
tristate "Realtek ALC5631/RT5631 CODEC"
depends on I2C
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -78,6 +78,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rt286-objs := rt286.o
+snd-soc-pcm5102a-objs := pcm5102a.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
snd-soc-rt5645-objs := rt5645.o
@@ -263,6 +264,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
--- /dev/null
+++ b/sound/soc/codecs/pcm5102a.c
@@ -0,0 +1,63 @@
+/*
+ * Driver for the PCM5102A codec
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver pcm5102a_dai = {
+ .name = "pcm5102a-hifi",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;
+
+static int pcm5102a_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
+ &pcm5102a_dai, 1);
+}
+
+static int pcm5102a_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pcm5102a_codec_driver = {
+ .probe = pcm5102a_probe,
+ .remove = pcm5102a_remove,
+ .driver = {
+ .name = "pcm5102a-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pcm5102a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,87 @@
From 1ae47f91380b552b3bb3adb28f3283be31786064 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 19:04:54 +0100
Subject: [PATCH 036/121] BCM2708: Add I2S support to board file
Adds the required initializations for I2S
to the board file of mach-bcm2708.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
bcm2708-i2s: Enable MMAP support via a DT property and overlay
The i2s driver used to claim to support MMAP, but that feature was disabled
when some problems were found. Add the ability to enable this feature
through Device Tree, using the i2s-mmap overlay.
See: #1004
---
arch/arm/mach-bcm2708/bcm2708.c | 26 ++++++++++++++++++++++++++
sound/soc/bcm/bcm2708-i2s.c | 7 ++++++-
2 files changed, 32 insertions(+), 1 deletion(-)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -616,6 +616,28 @@ static struct platform_device bcm2835_th
.name = "bcm2835_thermal",
};
+#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE)
+static struct resource bcm2708_i2s_resources[] = {
+ {
+ .start = I2S_BASE,
+ .end = I2S_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = PCM_CLOCK_BASE,
+ .end = PCM_CLOCK_BASE + 0x02,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device bcm2708_i2s_device = {
+ .name = "bcm2708-i2s",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_i2s_resources),
+ .resource = bcm2708_i2s_resources,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -780,6 +802,10 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&bcm2835_thermal_device);
+#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE)
+ bcm_register_device_dt(&bcm2708_i2s_device);
+#endif
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/sound/soc/bcm/bcm2708-i2s.c
+++ b/sound/soc/bcm/bcm2708-i2s.c
@@ -874,7 +874,7 @@ static const struct snd_soc_component_dr
.name = "bcm2708-i2s-comp",
};
-static const struct snd_pcm_hardware bcm2708_pcm_hardware = {
+static struct snd_pcm_hardware bcm2708_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_JOINT_DUPLEX,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
@@ -902,6 +902,11 @@ static int bcm2708_i2s_probe(struct plat
struct regmap *regmap[2];
struct resource *mem[2];
+ if (of_property_read_bool(pdev->dev.of_node, "brcm,enable-mmap"))
+ bcm2708_pcm_hardware.info |=
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID;
+
/* Request both ioareas */
for (i = 0; i <= 1; i++) {
void __iomem *base;

View File

@ -0,0 +1,144 @@
From 65a3e3f912faa5d0c0cdb937b23e641d45608236 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 19:19:08 +0100
Subject: [PATCH 037/121] ASoC: Add support for HifiBerry DAC
This adds a machine driver for the HifiBerry DAC.
It is a sound card that can
be stacked onto the Raspberry Pi.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 5 +++
sound/soc/bcm/hifiberry_dac.c | 100 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+)
create mode 100644 sound/soc/bcm/hifiberry_dac.c
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -18,3 +18,10 @@ config SND_BCM2708_SOC_I2S
Say Y or M if you want to add support for codecs attached to
the BCM2708 I2S interface. You will also need
to select the audio interfaces to support below.
+
+config SND_BCM2708_SOC_HIFIBERRY_DAC
+ tristate "Support for HifiBerry DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM5102A
+ help
+ Say Y or M if you want to add support for HifiBerry DAC.
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -7,3 +7,8 @@ obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd
snd-soc-bcm2708-i2s-objs := bcm2708-i2s.o
obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o
+
+# BCM2708 Machine Support
+snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+
+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
--- /dev/null
+++ b/sound/soc/bcm/hifiberry_dac.c
@@ -0,0 +1,100 @@
+/*
+ * ASoC Driver for HifiBerry DAC
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+static int snd_rpi_hifiberry_dac_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return 0;
+}
+
+static int snd_rpi_hifiberry_dac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ unsigned int sample_bits =
+ snd_pcm_format_physical_width(params_format(params));
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_hifiberry_dac_ops = {
+ .hw_params = snd_rpi_hifiberry_dac_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_hifiberry_dac_dai[] = {
+{
+ .name = "HifiBerry DAC",
+ .stream_name = "HifiBerry DAC HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm5102a-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "pcm5102a-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_hifiberry_dac_ops,
+ .init = snd_rpi_hifiberry_dac_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_hifiberry_dac = {
+ .name = "snd_rpi_hifiberry_dac",
+ .dai_link = snd_rpi_hifiberry_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dac_dai),
+};
+
+static int snd_rpi_hifiberry_dac_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_hifiberry_dac.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dac);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_hifiberry_dac_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_hifiberry_dac);
+}
+
+static struct platform_driver snd_rpi_hifiberry_dac_driver = {
+ .driver = {
+ .name = "snd-hifiberry-dac",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_hifiberry_dac_probe,
+ .remove = snd_rpi_hifiberry_dac_remove,
+};
+
+module_platform_driver(snd_rpi_hifiberry_dac_driver);
+
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,48 @@
From 1fee3fa181deb59422ad4f5f08262c8328189370 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 19:21:34 +0100
Subject: [PATCH 038/121] BCM2708: Add HifiBerry DAC to board file
This adds the initalization of the HifiBerry DAC
to the mach-bcm2708 board file.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/mach-bcm2708/bcm2708.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -638,6 +638,20 @@ static struct platform_device bcm2708_i2
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+static struct platform_device snd_hifiberry_dac_device = {
+ .name = "snd-hifiberry-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm5102a_codec_device = {
+ .name = "pcm5102a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -806,6 +820,11 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&bcm2708_i2s_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_dac_device);
+ bcm_register_device_dt(&snd_pcm5102a_codec_device);
+#endif
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];

View File

@ -0,0 +1,281 @@
From c5a634c60f6706ba7ffaec669d6ddae793a7b889 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 6 Dec 2013 20:50:28 +0100
Subject: [PATCH 039/121] ASoC: BCM2708: Add support for RPi-DAC
This adds a machine driver for the RPi-DAC.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/mach-bcm2708/bcm2708.c | 19 ++++++++
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/rpi-dac.c | 97 +++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/Kconfig | 4 ++
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/pcm1794a.c | 62 ++++++++++++++++++++++++++
7 files changed, 193 insertions(+)
create mode 100644 sound/soc/bcm/rpi-dac.c
create mode 100644 sound/soc/codecs/pcm1794a.c
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -652,6 +652,20 @@ static struct platform_device snd_pcm510
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+static struct platform_device snd_rpi_dac_device = {
+ .name = "snd-rpi-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm1794a_codec_device = {
+ .name = "pcm1794a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -825,6 +839,11 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&snd_pcm5102a_codec_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+ bcm_register_device_dt(&snd_rpi_dac_device);
+ bcm_register_device_dt(&snd_pcm1794a_codec_device);
+#endif
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -25,3 +25,10 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
select SND_SOC_PCM5102A
help
Say Y or M if you want to add support for HifiBerry DAC.
+
+config SND_BCM2708_SOC_RPI_DAC
+ tristate "Support for RPi-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM1794A
+ help
+ Say Y or M if you want to add support for RPi-DAC.
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -10,5 +10,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd
# BCM2708 Machine Support
snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+snd-soc-rpi-dac-objs := rpi-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
--- /dev/null
+++ b/sound/soc/bcm/rpi-dac.c
@@ -0,0 +1,97 @@
+/*
+ * ASoC Driver for RPi-DAC.
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+static int snd_rpi_rpi_dac_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return 0;
+}
+
+static int snd_rpi_rpi_dac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_rpi_dac_ops = {
+ .hw_params = snd_rpi_rpi_dac_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {
+{
+ .name = "RPi-DAC",
+ .stream_name = "RPi-DAC HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm1794a-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "pcm1794a-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_rpi_dac_ops,
+ .init = snd_rpi_rpi_dac_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_rpi_dac = {
+ .name = "snd_rpi_rpi_dac",
+ .dai_link = snd_rpi_rpi_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
+};
+
+static int snd_rpi_rpi_dac_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_rpi_dac.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_rpi_dac);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_rpi_dac_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_rpi_dac);
+}
+
+static struct platform_driver snd_rpi_rpi_dac_driver = {
+ .driver = {
+ .name = "snd-rpi-dac",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_rpi_dac_probe,
+ .remove = snd_rpi_rpi_dac_remove,
+};
+
+module_platform_driver(snd_rpi_rpi_dac_driver);
+
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_DESCRIPTION("ASoC Driver for RPi-DAC");
+MODULE_LICENSE("GPL v2");
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -84,6 +84,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM512x_SPI if SPI_MASTER
select SND_SOC_RT286 if I2C
select SND_SOC_PCM5102A if I2C
+ select SND_SOC_PCM1794A if I2C
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_RT5645 if I2C
@@ -512,6 +513,9 @@ config SND_SOC_RT286
tristate
depends on I2C
+config SND_SOC_PCM1794A
+ tristate
+
config SND_SOC_PCM5102A
tristate
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -78,6 +78,7 @@ snd-soc-pcm512x-i2c-objs := pcm512x-i2c.
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rt286-objs := rt286.o
+snd-soc-pcm1794a-objs := pcm1794a.o
snd-soc-pcm5102a-objs := pcm5102a.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
@@ -264,6 +265,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd
obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
+obj-$(CONFIG_SND_SOC_PCM1794A) += snd-soc-pcm1794a.o
obj-$(CONFIG_SND_SOC_PCM5102A) += snd-soc-pcm5102a.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
--- /dev/null
+++ b/sound/soc/codecs/pcm1794a.c
@@ -0,0 +1,62 @@
+/*
+ * Driver for the PCM1794A codec
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver pcm1794a_dai = {
+ .name = "pcm1794a-hifi",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1794a;
+
+static int pcm1794a_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm1794a,
+ &pcm1794a_dai, 1);
+}
+
+static int pcm1794a_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pcm1794a_codec_driver = {
+ .probe = pcm1794a_probe,
+ .remove = pcm1794a_remove,
+ .driver = {
+ .name = "pcm1794a-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pcm1794a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,40 @@
From c739ac8e078de6188449830672c7dd1e5b57af52 Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Wed, 15 Jan 2014 21:41:23 +0100
Subject: [PATCH 040/121] ASoC: wm8804: Implement MCLK configuration options,
add 32bit support WM8804 can run with PLL frequencies of 256xfs and 128xfs
for most sample rates. At 192kHz only 128xfs is supported. The existing
driver selects 128xfs automatically for some lower samples rates. By using an
additional mclk_div divider, it is now possible to control the behaviour.
This allows using 256xfs PLL frequency on all sample rates up to 96kHz. It
should allow lower jitter and better signal quality. The behavior has to be
controlled by the sound card driver, because some sample frequency share the
same setting. e.g. 192kHz and 96kHz use 24.576MHz master clock. The only
difference is the MCLK divider.
This also added support for 32bit data.
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
---
sound/soc/codecs/wm8804.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -304,6 +304,7 @@ static int wm8804_hw_params(struct snd_p
blen = 0x1;
break;
case 24:
+ case 32:
blen = 0x2;
break;
default:
@@ -515,7 +516,7 @@ static const struct snd_soc_dai_ops wm88
};
#define WM8804_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
+ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE)
#define WM8804_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \

View File

@ -0,0 +1,260 @@
From 7cce7a2fdf84a988e7b23caa129dddbcc7613b10 Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Wed, 15 Jan 2014 21:42:08 +0100
Subject: [PATCH 041/121] ASoC: BCM:Add support for HiFiBerry Digi. Driver is
based on the patched WM8804 driver.
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
Add a parameter to turn off SPDIF output if no audio is playing
This patch adds the paramater auto_shutdown_output to the kernel module.
Default behaviour of the module is the same, but when auto_shutdown_output
is set to 1, the SPDIF oputput will shutdown if no stream is playing.
bugfix for 32kHz sample rate, was missing
HiFiBerry Digi: set SPDIF status bits for sample rate
The HiFiBerry Digi driver did not signal the sample rate in the SPDIF status bits.
While this is optional, some DACs and receivers do not accept this signal. This patch
adds the sample rate bits in the SPDIF status block.
---
sound/soc/bcm/Kconfig | 7 ++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/hifiberry_digi.c | 201 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 210 insertions(+)
create mode 100644 sound/soc/bcm/hifiberry_digi.c
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -26,6 +26,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
help
Say Y or M if you want to add support for HifiBerry DAC.
+config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_WM8804
+ help
+ Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
+
config SND_BCM2708_SOC_RPI_DAC
tristate "Support for RPi-DAC"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd
# BCM2708 Machine Support
snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+snd-soc-hifiberry-digi-objs := hifiberry_digi.o
snd-soc-rpi-dac-objs := rpi-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
--- /dev/null
+++ b/sound/soc/bcm/hifiberry_digi.c
@@ -0,0 +1,201 @@
+/*
+ * ASoC Driver for HifiBerry Digi
+ *
+ * Author: Daniel Matuschek <info@crazy-audio.com>
+ * based on the HifiBerry DAC driver by Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8804.h"
+
+static short int auto_shutdown_output = 0;
+module_param(auto_shutdown_output, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(auto_shutdown_output, "Shutdown SP/DIF output if playback is stopped");
+
+
+static int samplerate=44100;
+
+static int snd_rpi_hifiberry_digi_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+
+ /* enable TX output */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
+
+ return 0;
+}
+
+static int snd_rpi_hifiberry_digi_startup(struct snd_pcm_substream *substream) {
+ /* turn on digital output */
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x00);
+ return 0;
+}
+
+static void snd_rpi_hifiberry_digi_shutdown(struct snd_pcm_substream *substream) {
+ /* turn off output */
+ if (auto_shutdown_output) {
+ /* turn off output */
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x3c, 0x3c);
+ }
+}
+
+
+static int snd_rpi_hifiberry_digi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ int sysclk = 27000000; /* This is fixed on this board */
+
+ long mclk_freq=0;
+ int mclk_div=1;
+ int sampling_freq=1;
+
+ int ret;
+
+ samplerate = params_rate(params);
+
+ if (samplerate<=96000) {
+ mclk_freq=samplerate*256;
+ mclk_div=WM8804_MCLKDIV_256FS;
+ } else {
+ mclk_freq=samplerate*128;
+ mclk_div=WM8804_MCLKDIV_128FS;
+ }
+
+ switch (samplerate) {
+ case 32000:
+ sampling_freq=0x03;
+ break;
+ case 44100:
+ sampling_freq=0x00;
+ break;
+ case 48000:
+ sampling_freq=0x02;
+ break;
+ case 88200:
+ sampling_freq=0x08;
+ break;
+ case 96000:
+ sampling_freq=0x0a;
+ break;
+ case 176400:
+ sampling_freq=0x0c;
+ break;
+ case 192000:
+ sampling_freq=0x0e;
+ break;
+ default:
+ dev_err(codec->dev,
+ "Failed to set WM8804 SYSCLK, unsupported samplerate %d\n",
+ samplerate);
+ }
+
+ snd_soc_dai_set_clkdiv(codec_dai, WM8804_MCLK_DIV, mclk_div);
+ snd_soc_dai_set_pll(codec_dai, 0, 0, sysclk, mclk_freq);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8804_TX_CLKSRC_PLL,
+ sysclk, SND_SOC_CLOCK_OUT);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "Failed to set WM8804 SYSCLK: %d\n", ret);
+ return ret;
+ }
+
+ /* Enable TX output */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x4, 0x0);
+
+ /* Power on */
+ snd_soc_update_bits(codec, WM8804_PWRDN, 0x9, 0);
+
+ /* set sampling frequency status bits */
+ snd_soc_update_bits(codec, WM8804_SPDTX4, 0x0f, sampling_freq);
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai,64);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_hifiberry_digi_ops = {
+ .hw_params = snd_rpi_hifiberry_digi_hw_params,
+ .startup = snd_rpi_hifiberry_digi_startup,
+ .shutdown = snd_rpi_hifiberry_digi_shutdown,
+};
+
+static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = {
+{
+ .name = "HifiBerry Digi",
+ .stream_name = "HifiBerry Digi HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "wm8804-spdif",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "wm8804.1-003b",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ .ops = &snd_rpi_hifiberry_digi_ops,
+ .init = snd_rpi_hifiberry_digi_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_hifiberry_digi = {
+ .name = "snd_rpi_hifiberry_digi",
+ .dai_link = snd_rpi_hifiberry_digi_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
+};
+
+static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_hifiberry_digi.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
+}
+
+static struct platform_driver snd_rpi_hifiberry_digi_driver = {
+ .driver = {
+ .name = "snd-hifiberry-digi",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_hifiberry_digi_probe,
+ .remove = snd_rpi_hifiberry_digi_remove,
+};
+
+module_platform_driver(snd_rpi_hifiberry_digi_driver);
+
+MODULE_AUTHOR("Daniel Matuschek <info@crazy-audio.com>");
+MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,47 @@
From 6912c1ddd399d69d7704e9f6445014d40ec21c9b Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Thu, 16 Jan 2014 07:26:08 +0100
Subject: [PATCH 042/121] BCM2708: Added support for HiFiBerry Digi board Board
initalization by I2C
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
---
arch/arm/mach-bcm2708/bcm2708.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -652,6 +652,21 @@ static struct platform_device snd_pcm510
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
+static struct platform_device snd_hifiberry_digi_device = {
+ .name = "snd-hifiberry-digi",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_wm8804_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("wm8804", 0x3b)
+ },
+};
+
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
static struct platform_device snd_rpi_dac_device = {
.name = "snd-rpi-dac",
@@ -839,6 +854,11 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&snd_pcm5102a_codec_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_digi_device);
+ i2c_register_board_info_dt(1, snd_wm8804_i2c_devices, ARRAY_SIZE(snd_wm8804_i2c_devices));
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
bcm_register_device_dt(&snd_rpi_dac_device);
bcm_register_device_dt(&snd_pcm1794a_codec_device);

View File

@ -0,0 +1,22 @@
From c1291a2b3390ab53e3a6ca2325e39d0a01908d87 Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Thu, 16 Jan 2014 07:36:35 +0100
Subject: [PATCH 043/121] ASoC: wm8804: Set idle_bias_off to false Idle bias
has been change to remove warning on driver startup
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
---
sound/soc/codecs/wm8804.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -544,7 +544,7 @@ static struct snd_soc_dai_driver wm8804_
};
static const struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
- .idle_bias_off = true,
+ .idle_bias_off = false,
.dapm_widgets = wm8804_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8804_dapm_widgets),

View File

@ -0,0 +1,201 @@
From 3cefe8f4539e290215418a54ff815913bb658814 Mon Sep 17 00:00:00 2001
From: Gordon Garrity <gordon@iqaudio.com>
Date: Sat, 8 Mar 2014 16:56:57 +0000
Subject: [PATCH 044/121] Add IQaudIO Sound Card support for Raspberry Pi
Set a limit of 0dB on Digital Volume Control
The main volume control in the PCM512x DAC has a range up to
+24dB. This is dangerously loud and can potentially cause massive
clipping in the output stages. Therefore this sets a sensible
limit of 0dB for this control.
---
arch/arm/mach-bcm2708/bcm2708.c | 21 ++++++++
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/iqaudio-dac.c | 117 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 147 insertions(+)
create mode 100644 sound/soc/bcm/iqaudio-dac.c
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -681,6 +681,22 @@ static struct platform_device snd_pcm179
};
#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE)
+static struct platform_device snd_rpi_iqaudio_dac_device = {
+ .name = "snd-rpi-iqaudio-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+// Use the actual device name rather than generic driver name
+static struct i2c_board_info __initdata snd_pcm512x_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("pcm5122", 0x4c)
+ },
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -864,6 +880,11 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&snd_pcm1794a_codec_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE)
+ bcm_register_device_dt(&snd_rpi_iqaudio_dac_device);
+ i2c_register_board_info_dt(1, snd_pcm512x_i2c_devices, ARRAY_SIZE(snd_pcm512x_i2c_devices));
+#endif
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -39,3 +39,10 @@ config SND_BCM2708_SOC_RPI_DAC
select SND_SOC_PCM1794A
help
Say Y or M if you want to add support for RPi-DAC.
+
+config SND_BCM2708_SOC_IQAUDIO_DAC
+ tristate "Support for IQaudIO-DAC"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM512x_I2C
+ help
+ Say Y or M if you want to add support for IQaudIO-DAC.
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -12,7 +12,9 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd
snd-soc-hifiberry-dac-objs := hifiberry_dac.o
snd-soc-hifiberry-digi-objs := hifiberry_digi.o
snd-soc-rpi-dac-objs := rpi-dac.o
+snd-soc-iqaudio-dac-objs := iqaudio-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
--- /dev/null
+++ b/sound/soc/bcm/iqaudio-dac.c
@@ -0,0 +1,117 @@
+/*
+ * ASoC Driver for IQaudIO DAC
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd)
+{
+ int ret;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_codec *codec = rtd->codec;
+
+ ret = snd_soc_limit_volume(codec, "Digital Playback Volume", 207);
+ if (ret < 0)
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
+
+ return 0;
+}
+
+static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai;
+// NOT USED struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ unsigned int sample_bits =
+ snd_pcm_format_physical_width(params_format(params));
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = {
+ .hw_params = snd_rpi_iqaudio_dac_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = {
+{
+ .name = "IQaudIO DAC",
+ .stream_name = "IQaudIO DAC HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm512x-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "pcm512x.1-004c",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_iqaudio_dac_ops,
+ .init = snd_rpi_iqaudio_dac_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_iqaudio_dac = {
+ .name = "IQaudIODAC",
+ .dai_link = snd_rpi_iqaudio_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai),
+};
+
+static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_iqaudio_dac.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
+ if (ret)
+ dev_err(&pdev->dev,
+ "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac);
+}
+
+static const struct of_device_id iqaudio_of_match[] = {
+ { .compatible = "iqaudio,iqaudio-dac", },
+ {},
+};
+
+static struct platform_driver snd_rpi_iqaudio_dac_driver = {
+ .driver = {
+ .name = "snd-rpi-iqaudio-dac",
+ .owner = THIS_MODULE,
+ .of_match_table = iqaudio_of_match,
+ },
+ .probe = snd_rpi_iqaudio_dac_probe,
+ .remove = snd_rpi_iqaudio_dac_remove,
+};
+
+module_platform_driver(snd_rpi_iqaudio_dac_driver);
+
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,27 @@
From 63dc5102ff1e782a18c891169ef614ff83fd16da Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 18 Jun 2014 13:42:01 +0100
Subject: [PATCH 045/121] vmstat: Workaround for issue where dirty page count
goes negative
See:
https://github.com/raspberrypi/linux/issues/617
http://www.spinics.net/lists/linux-mm/msg72236.html
---
include/linux/vmstat.h | 4 ++++
1 file changed, 4 insertions(+)
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -241,7 +241,11 @@ static inline void __inc_zone_state(stru
static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item)
{
atomic_long_dec(&zone->vm_stat[item]);
+ if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&zone->vm_stat[item]) < 0))
+ atomic_long_set(&zone->vm_stat[item], 0);
atomic_long_dec(&vm_stat[item]);
+ if (item == NR_FILE_DIRTY && unlikely(atomic_long_read(&vm_stat[item]) < 0))
+ atomic_long_set(&vm_stat[item], 0);
}
static inline void __inc_zone_page_state(struct page *page,

View File

@ -0,0 +1,36 @@
From 4b7eb6e29aee506fd82e9eea37b951f0a4101f8a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 14 Jul 2014 22:02:09 +0100
Subject: [PATCH 046/121] hid: Reduce default mouse polling interval to 60Hz
Reduces overhead when using X
---
drivers/hid/usbhid/hid-core.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -49,7 +49,7 @@
* Module parameters.
*/
-static unsigned int hid_mousepoll_interval;
+static unsigned int hid_mousepoll_interval = ~0;
module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644);
MODULE_PARM_DESC(mousepoll, "Polling interval of mice");
@@ -1090,8 +1090,12 @@ static int usbhid_start(struct hid_devic
}
/* Change the polling interval of mice. */
- if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
- interval = hid_mousepoll_interval;
+ if (hid->collection->usage == HID_GD_MOUSE) {
+ if (hid_mousepoll_interval == ~0 && interval < 16)
+ interval = 16;
+ else if (hid_mousepoll_interval != ~0 && hid_mousepoll_interval != 0)
+ interval = hid_mousepoll_interval;
+ }
ret = -ENOMEM;
if (usb_endpoint_dir_in(endpoint)) {

View File

@ -0,0 +1,204 @@
From e35b74b6335b49387b09d114966b89549a13f1d5 Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Mon, 4 Aug 2014 10:06:56 +0200
Subject: [PATCH 047/121] Added support for HiFiBerry DAC+
The driver is based on the HiFiBerry DAC driver. However HiFiBerry DAC+ uses
a different codec chip (PCM5122), therefore a new driver is necessary.
---
arch/arm/mach-bcm2708/bcm2708.c | 19 ++++++
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/hifiberry_dacplus.c | 119 ++++++++++++++++++++++++++++++++++++++
4 files changed, 147 insertions(+)
create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -652,6 +652,20 @@ static struct platform_device snd_pcm510
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE)
+static struct platform_device snd_rpi_hifiberry_dacplus_device = {
+ .name = "snd-rpi-hifiberry-dacplus",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_pcm512x_hbdacplus_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("pcm5122", 0x4d)
+ },
+};
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
static struct platform_device snd_hifiberry_digi_device = {
.name = "snd-hifiberry-digi",
@@ -870,6 +884,11 @@ void __init bcm2708_init(void)
bcm_register_device_dt(&snd_pcm5102a_codec_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE)
+ bcm_register_device_dt(&snd_rpi_hifiberry_dacplus_device);
+ i2c_register_board_info_dt(1, snd_pcm512x_hbdacplus_i2c_devices, ARRAY_SIZE(snd_pcm512x_hbdacplus_i2c_devices));
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
bcm_register_device_dt(&snd_hifiberry_digi_device);
i2c_register_board_info_dt(1, snd_wm8804_i2c_devices, ARRAY_SIZE(snd_wm8804_i2c_devices));
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -26,6 +26,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
help
Say Y or M if you want to add support for HifiBerry DAC.
+config SND_BCM2708_SOC_HIFIBERRY_DACPLUS
+ tristate "Support for HifiBerry DAC+"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_PCM512x
+ help
+ Say Y or M if you want to add support for HifiBerry DAC+.
+
config SND_BCM2708_SOC_HIFIBERRY_DIGI
tristate "Support for HifiBerry Digi"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -10,11 +10,13 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd
# BCM2708 Machine Support
snd-soc-hifiberry-dac-objs := hifiberry_dac.o
+snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
snd-soc-hifiberry-digi-objs := hifiberry_digi.o
snd-soc-rpi-dac-objs := rpi-dac.o
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
--- /dev/null
+++ b/sound/soc/bcm/hifiberry_dacplus.c
@@ -0,0 +1,119 @@
+/*
+ * ASoC Driver for HiFiBerry DAC+
+ *
+ * Author: Daniel Matuschek
+ * Copyright 2014
+ * based on code by Florian Meier <florian.meier@koalo.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/pcm512x.h"
+
+static int snd_rpi_hifiberry_dacplus_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ snd_soc_update_bits(codec, PCM512x_GPIO_EN, 0x08, 0x08);
+ snd_soc_update_bits(codec, PCM512x_GPIO_OUTPUT_4, 0xf, 0x02);
+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
+ return 0;
+}
+
+static int snd_rpi_hifiberry_dacplus_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
+}
+
+static int snd_rpi_hifiberry_dacplus_startup(struct snd_pcm_substream *substream) {
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x08);
+ return 0;
+}
+
+static void snd_rpi_hifiberry_dacplus_shutdown(struct snd_pcm_substream *substream) {
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ snd_soc_update_bits(codec, PCM512x_GPIO_CONTROL_1, 0x08,0x00);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_hifiberry_dacplus_ops = {
+ .hw_params = snd_rpi_hifiberry_dacplus_hw_params,
+ .startup = snd_rpi_hifiberry_dacplus_startup,
+ .shutdown = snd_rpi_hifiberry_dacplus_shutdown,
+};
+
+static struct snd_soc_dai_link snd_rpi_hifiberry_dacplus_dai[] = {
+{
+ .name = "HiFiBerry DAC+",
+ .stream_name = "HiFiBerry DAC+ HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm512x-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "pcm512x.1-004d",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_hifiberry_dacplus_ops,
+ .init = snd_rpi_hifiberry_dacplus_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_hifiberry_dacplus = {
+ .name = "snd_rpi_hifiberry_dacplus",
+ .dai_link = snd_rpi_hifiberry_dacplus_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_dacplus_dai),
+};
+
+static int snd_rpi_hifiberry_dacplus_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
+ if (ret)
+ dev_err(&pdev->dev,
+ "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_hifiberry_dacplus_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_hifiberry_dacplus);
+}
+
+static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
+ .driver = {
+ .name = "snd-rpi-hifiberry-dacplus",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_hifiberry_dacplus_probe,
+ .remove = snd_rpi_hifiberry_dacplus_remove,
+};
+
+module_platform_driver(snd_rpi_hifiberry_dacplus_driver);
+
+MODULE_AUTHOR("Daniel Matuschek <daniel@hifiberry.com>");
+MODULE_DESCRIPTION("ASoC Driver for HiFiBerry DAC+");
+MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,852 @@
From ee406533a463686db7d11c7ad0f626578c1edcac Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Mon, 4 Aug 2014 11:09:58 +0200
Subject: [PATCH 048/121] Added driver for HiFiBerry Amp amplifier add-on board
The driver contains a low-level hardware driver for the TAS5713 and the
drivers for the Raspberry Pi I2S subsystem.
TAS5713: return error if initialisation fails
Existing TAS5713 driver logs errors during initialisation, but does not return
an error code. Therefore even if initialisation fails, the driver will still be
loaded, but won't work. This patch fixes this. I2C communication error will now
reported correctly by a non-zero return code.
HiFiBerry Amp: fix device-tree problems
Some code to load the driver based on device-tree-overlays was missing. This is added by this patch.
---
arch/arm/mach-bcm2708/bcm2708.c | 19 +++
sound/soc/bcm/Kconfig | 7 +
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/hifiberry_amp.c | 127 ++++++++++++++
sound/soc/codecs/Kconfig | 4 +
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/tas5713.c | 369 ++++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/tas5713.h | 210 +++++++++++++++++++++++
8 files changed, 740 insertions(+)
create mode 100644 sound/soc/bcm/hifiberry_amp.c
create mode 100644 sound/soc/codecs/tas5713.c
create mode 100644 sound/soc/codecs/tas5713.h
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -681,6 +681,20 @@ static struct i2c_board_info __initdata
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP_MODULE)
+static struct platform_device snd_hifiberry_amp_device = {
+ .name = "snd-hifiberry-amp",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_tas5713_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tas5713", 0x1b)
+ },
+};
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
static struct platform_device snd_rpi_dac_device = {
.name = "snd-rpi-dac",
@@ -894,6 +908,11 @@ void __init bcm2708_init(void)
i2c_register_board_info_dt(1, snd_wm8804_i2c_devices, ARRAY_SIZE(snd_wm8804_i2c_devices));
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_amp_device);
+ i2c_register_board_info_dt(1, snd_tas5713_i2c_devices, ARRAY_SIZE(snd_tas5713_i2c_devices));
+#endif
+
#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
bcm_register_device_dt(&snd_rpi_dac_device);
bcm_register_device_dt(&snd_pcm1794a_codec_device);
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -40,6 +40,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DIGI
help
Say Y or M if you want to add support for HifiBerry Digi S/PDIF output board.
+config SND_BCM2708_SOC_HIFIBERRY_AMP
+ tristate "Support for the HifiBerry Amp"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_TAS5713
+ help
+ Say Y or M if you want to add support for the HifiBerry Amp amplifier board.
+
config SND_BCM2708_SOC_RPI_DAC
tristate "Support for RPi-DAC"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -12,11 +12,13 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd
snd-soc-hifiberry-dac-objs := hifiberry_dac.o
snd-soc-hifiberry-dacplus-objs := hifiberry_dacplus.o
snd-soc-hifiberry-digi-objs := hifiberry_digi.o
+snd-soc-hifiberry-amp-objs := hifiberry_amp.o
snd-soc-rpi-dac-objs := rpi-dac.o
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) += snd-soc-hifiberry-dacplus.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
--- /dev/null
+++ b/sound/soc/bcm/hifiberry_amp.c
@@ -0,0 +1,127 @@
+/*
+ * ASoC Driver for HifiBerry AMP
+ *
+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
+ * Copyright 2014
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+static int snd_rpi_hifiberry_amp_init(struct snd_soc_pcm_runtime *rtd)
+{
+ // ToDo: init of the dsp-registers.
+ return 0;
+}
+
+static int snd_rpi_hifiberry_amp_hw_params( struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params )
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 64);
+}
+
+static struct snd_soc_ops snd_rpi_hifiberry_amp_ops = {
+ .hw_params = snd_rpi_hifiberry_amp_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_hifiberry_amp_dai[] = {
+ {
+ .name = "HifiBerry AMP",
+ .stream_name = "HifiBerry AMP HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "tas5713-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "tas5713.1-001b",
+ .dai_fmt = SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_hifiberry_amp_ops,
+ .init = snd_rpi_hifiberry_amp_init,
+ },
+};
+
+
+static struct snd_soc_card snd_rpi_hifiberry_amp = {
+ .name = "snd_rpi_hifiberry_amp",
+ .dai_link = snd_rpi_hifiberry_amp_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_amp_dai),
+};
+
+static const struct of_device_id snd_rpi_hifiberry_amp_of_match[] = {
+ { .compatible = "hifiberry,hifiberry-amp", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_amp_of_match);
+
+
+static int snd_rpi_hifiberry_amp_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_hifiberry_amp.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_amp_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_amp);
+
+ if (ret != 0) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+ }
+
+ return ret;
+}
+
+
+static int snd_rpi_hifiberry_amp_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_hifiberry_amp);
+}
+
+
+static struct platform_driver snd_rpi_hifiberry_amp_driver = {
+ .driver = {
+ .name = "snd-hifiberry-amp",
+ .owner = THIS_MODULE,
+ .of_match_table = snd_rpi_hifiberry_amp_of_match,
+ },
+ .probe = snd_rpi_hifiberry_amp_probe,
+ .remove = snd_rpi_hifiberry_amp_remove,
+};
+
+
+module_platform_driver(snd_rpi_hifiberry_amp_driver);
+
+
+MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
+MODULE_DESCRIPTION("ASoC driver for HiFiBerry-AMP");
+MODULE_LICENSE("GPL v2");
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -109,6 +109,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
+ select SND_SOC_TAS5713 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TLV320AIC31XX if I2C
select SND_SOC_TLV320AIC32X4 if I2C
@@ -623,6 +624,9 @@ config SND_SOC_TFA9879
tristate "NXP Semiconductors TFA9879 amplifier"
depends on I2C
+config SND_SOC_TAS5713
+ tristate
+
config SND_SOC_TLV320AIC23
tristate
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -109,6 +109,7 @@ snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tas5086-objs := tas5086.o
snd-soc-tfa9879-objs := tfa9879.o
+snd-soc-tas5713-objs := tas5713.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -293,6 +294,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-so
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
+obj-$(CONFIG_SND_SOC_TAS5713) += snd-soc-tas5713.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
--- /dev/null
+++ b/sound/soc/codecs/tas5713.c
@@ -0,0 +1,369 @@
+/*
+ * ASoC Driver for TAS5713
+ *
+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
+ * Copyright 2014
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+
+#include "tas5713.h"
+
+
+static struct i2c_client *i2c;
+
+struct tas5713_priv {
+ struct regmap *regmap;
+ int mclk_div;
+ struct snd_soc_codec *codec;
+};
+
+static struct tas5713_priv *priv_data;
+
+
+
+
+/*
+ * _ _ ___ _ ___ _ _
+ * /_\ | | / __| /_\ / __|___ _ _| |_ _ _ ___| |___
+ * / _ \| |__\__ \/ _ \ | (__/ _ \ ' \ _| '_/ _ \ (_-<
+ * /_/ \_\____|___/_/ \_\ \___\___/_||_\__|_| \___/_/__/
+ *
+ */
+
+static const DECLARE_TLV_DB_SCALE(tas5713_vol_tlv, -10000, 50, 1);
+
+
+static const struct snd_kcontrol_new tas5713_snd_controls[] = {
+ SOC_SINGLE_TLV ("Master" , TAS5713_VOL_MASTER, 0, 248, 1, tas5713_vol_tlv),
+ SOC_DOUBLE_R_TLV("Channels" , TAS5713_VOL_CH1, TAS5713_VOL_CH2, 0, 248, 1, tas5713_vol_tlv)
+};
+
+
+
+
+/*
+ * __ __ _ _ ___ _
+ * | \/ |__ _ __| |_ (_)_ _ ___ | \ _ _(_)_ _____ _ _
+ * | |\/| / _` / _| ' \| | ' \/ -_) | |) | '_| \ V / -_) '_|
+ * |_| |_\__,_\__|_||_|_|_||_\___| |___/|_| |_|\_/\___|_|
+ *
+ */
+
+static int tas5713_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ u16 blen = 0x00;
+
+ struct snd_soc_codec *codec;
+ codec = dai->codec;
+ priv_data->codec = dai->codec;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ blen = 0x03;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ blen = 0x1;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ blen = 0x04;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ blen = 0x05;
+ break;
+ default:
+ dev_err(dai->dev, "Unsupported word length: %u\n",
+ params_format(params));
+ return -EINVAL;
+ }
+
+ // set word length
+ snd_soc_update_bits(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x7, blen);
+
+ return 0;
+}
+
+
+static int tas5713_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
+{
+ unsigned int val = 0;
+
+ struct tas5713_priv *tas5713;
+ struct snd_soc_codec *codec = dai->codec;
+ tas5713 = snd_soc_codec_get_drvdata(codec);
+
+ if (mute) {
+ val = TAS5713_SOFT_MUTE_ALL;
+ }
+
+ return regmap_write(tas5713->regmap, TAS5713_SOFT_MUTE, val);
+}
+
+
+static const struct snd_soc_dai_ops tas5713_dai_ops = {
+ .hw_params = tas5713_hw_params,
+ .mute_stream = tas5713_mute_stream,
+};
+
+
+static struct snd_soc_dai_driver tas5713_dai = {
+ .name = "tas5713-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE ),
+ },
+ .ops = &tas5713_dai_ops,
+};
+
+
+
+
+/*
+ * ___ _ ___ _
+ * / __|___ __| |___ __ | \ _ _(_)_ _____ _ _
+ * | (__/ _ \/ _` / -_) _| | |) | '_| \ V / -_) '_|
+ * \___\___/\__,_\___\__| |___/|_| |_|\_/\___|_|
+ *
+ */
+
+static int tas5713_remove(struct snd_soc_codec *codec)
+{
+ struct tas5713_priv *tas5713;
+
+ tas5713 = snd_soc_codec_get_drvdata(codec);
+
+ return 0;
+}
+
+
+static int tas5713_probe(struct snd_soc_codec *codec)
+{
+ struct tas5713_priv *tas5713;
+ int i, ret;
+
+ i2c = container_of(codec->dev, struct i2c_client, dev);
+
+ tas5713 = snd_soc_codec_get_drvdata(codec);
+
+ // Reset error
+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
+ if (ret < 0) return ret;
+
+ // Trim oscillator
+ ret = snd_soc_write(codec, TAS5713_OSC_TRIM, 0x00);
+ if (ret < 0) return ret;
+ msleep(1000);
+
+ // Reset error
+ ret = snd_soc_write(codec, TAS5713_ERROR_STATUS, 0x00);
+ if (ret < 0) return ret;
+
+ // Clock mode: 44/48kHz, MCLK=64xfs
+ ret = snd_soc_write(codec, TAS5713_CLOCK_CTRL, 0x60);
+ if (ret < 0) return ret;
+
+ // I2S 24bit
+ ret = snd_soc_write(codec, TAS5713_SERIAL_DATA_INTERFACE, 0x05);
+ if (ret < 0) return ret;
+
+ // Unmute
+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
+ if (ret < 0) return ret;
+ ret = snd_soc_write(codec, TAS5713_SOFT_MUTE, 0x00);
+ if (ret < 0) return ret;
+
+ // Set volume to 0db
+ ret = snd_soc_write(codec, TAS5713_VOL_MASTER, 0x00);
+ if (ret < 0) return ret;
+
+ // Now start programming the default initialization sequence
+ for (i = 0; i < ARRAY_SIZE(tas5713_init_sequence); ++i) {
+ ret = i2c_master_send(i2c,
+ tas5713_init_sequence[i].data,
+ tas5713_init_sequence[i].size);
+ if (ret < 0) {
+ printk(KERN_INFO "TAS5713 CODEC PROBE: InitSeq returns: %d\n", ret);
+ }
+ }
+
+ // Unmute
+ ret = snd_soc_write(codec, TAS5713_SYSTEM_CTRL2, 0x00);
+ if (ret < 0) return ret;
+
+ return 0;
+}
+
+
+static struct snd_soc_codec_driver soc_codec_dev_tas5713 = {
+ .probe = tas5713_probe,
+ .remove = tas5713_remove,
+ .controls = tas5713_snd_controls,
+ .num_controls = ARRAY_SIZE(tas5713_snd_controls),
+};
+
+
+
+
+/*
+ * ___ ___ ___ ___ _
+ * |_ _|_ ) __| | \ _ _(_)_ _____ _ _
+ * | | / / (__ | |) | '_| \ V / -_) '_|
+ * |___/___\___| |___/|_| |_|\_/\___|_|
+ *
+ */
+
+static const struct reg_default tas5713_reg_defaults[] = {
+ { 0x07 ,0x80 }, // R7 - VOL_MASTER - -40dB
+ { 0x08 , 30 }, // R8 - VOL_CH1 - 0dB
+ { 0x09 , 30 }, // R9 - VOL_CH2 - 0dB
+ { 0x0A ,0x80 }, // R10 - VOL_HEADPHONE - -40dB
+};
+
+
+static bool tas5713_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TAS5713_DEVICE_ID:
+ case TAS5713_ERROR_STATUS:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
+static const struct of_device_id tas5713_of_match[] = {
+ { .compatible = "ti,tas5713", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, tas5713_of_match);
+
+
+static struct regmap_config tas5713_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = TAS5713_MAX_REGISTER,
+ .volatile_reg = tas5713_reg_volatile,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = tas5713_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(tas5713_reg_defaults),
+};
+
+
+static int tas5713_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ int ret;
+
+ priv_data = devm_kzalloc(&i2c->dev, sizeof *priv_data, GFP_KERNEL);
+ if (!priv_data)
+ return -ENOMEM;
+
+ priv_data->regmap = devm_regmap_init_i2c(i2c, &tas5713_regmap_config);
+ if (IS_ERR(priv_data->regmap)) {
+ ret = PTR_ERR(priv_data->regmap);
+ return ret;
+ }
+
+ i2c_set_clientdata(i2c, priv_data);
+
+ ret = snd_soc_register_codec(&i2c->dev,
+ &soc_codec_dev_tas5713, &tas5713_dai, 1);
+
+ return ret;
+}
+
+
+static int tas5713_i2c_remove(struct i2c_client *i2c)
+{
+ snd_soc_unregister_codec(&i2c->dev);
+ i2c_set_clientdata(i2c, NULL);
+
+ kfree(priv_data);
+
+ return 0;
+}
+
+
+static const struct i2c_device_id tas5713_i2c_id[] = {
+ { "tas5713", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, tas5713_i2c_id);
+
+
+static struct i2c_driver tas5713_i2c_driver = {
+ .driver = {
+ .name = "tas5713",
+ .owner = THIS_MODULE,
+ .of_match_table = tas5713_of_match,
+ },
+ .probe = tas5713_i2c_probe,
+ .remove = tas5713_i2c_remove,
+ .id_table = tas5713_i2c_id
+};
+
+
+static int __init tas5713_modinit(void)
+{
+ int ret = 0;
+
+ ret = i2c_add_driver(&tas5713_i2c_driver);
+ if (ret) {
+ printk(KERN_ERR "Failed to register tas5713 I2C driver: %d\n",
+ ret);
+ }
+
+ return ret;
+}
+module_init(tas5713_modinit);
+
+
+static void __exit tas5713_exit(void)
+{
+ i2c_del_driver(&tas5713_i2c_driver);
+}
+module_exit(tas5713_exit);
+
+
+MODULE_AUTHOR("Sebastian Eickhoff <basti.eickhoff@googlemail.com>");
+MODULE_DESCRIPTION("ASoC driver for TAS5713");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+++ b/sound/soc/codecs/tas5713.h
@@ -0,0 +1,210 @@
+/*
+ * ASoC Driver for TAS5713
+ *
+ * Author: Sebastian Eickhoff <basti.eickhoff@googlemail.com>
+ * Copyright 2014
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef _TAS5713_H
+#define _TAS5713_H
+
+
+// TAS5713 I2C-bus register addresses
+
+#define TAS5713_CLOCK_CTRL 0x00
+#define TAS5713_DEVICE_ID 0x01
+#define TAS5713_ERROR_STATUS 0x02
+#define TAS5713_SYSTEM_CTRL1 0x03
+#define TAS5713_SERIAL_DATA_INTERFACE 0x04
+#define TAS5713_SYSTEM_CTRL2 0x05
+#define TAS5713_SOFT_MUTE 0x06
+#define TAS5713_VOL_MASTER 0x07
+#define TAS5713_VOL_CH1 0x08
+#define TAS5713_VOL_CH2 0x09
+#define TAS5713_VOL_HEADPHONE 0x0A
+#define TAS5713_VOL_CONFIG 0x0E
+#define TAS5713_MODULATION_LIMIT 0x10
+#define TAS5713_IC_DLY_CH1 0x11
+#define TAS5713_IC_DLY_CH2 0x12
+#define TAS5713_IC_DLY_CH3 0x13
+#define TAS5713_IC_DLY_CH4 0x14
+
+#define TAS5713_START_STOP_PERIOD 0x1A
+#define TAS5713_OSC_TRIM 0x1B
+#define TAS5713_BKND_ERR 0x1C
+
+#define TAS5713_INPUT_MUX 0x20
+#define TAS5713_SRC_SELECT_CH4 0x21
+#define TAS5713_PWM_MUX 0x25
+
+#define TAS5713_CH1_BQ0 0x29
+#define TAS5713_CH1_BQ1 0x2A
+#define TAS5713_CH1_BQ2 0x2B
+#define TAS5713_CH1_BQ3 0x2C
+#define TAS5713_CH1_BQ4 0x2D
+#define TAS5713_CH1_BQ5 0x2E
+#define TAS5713_CH1_BQ6 0x2F
+#define TAS5713_CH1_BQ7 0x58
+#define TAS5713_CH1_BQ8 0x59
+
+#define TAS5713_CH2_BQ0 0x30
+#define TAS5713_CH2_BQ1 0x31
+#define TAS5713_CH2_BQ2 0x32
+#define TAS5713_CH2_BQ3 0x33
+#define TAS5713_CH2_BQ4 0x34
+#define TAS5713_CH2_BQ5 0x35
+#define TAS5713_CH2_BQ6 0x36
+#define TAS5713_CH2_BQ7 0x5C
+#define TAS5713_CH2_BQ8 0x5D
+
+#define TAS5713_CH4_BQ0 0x5A
+#define TAS5713_CH4_BQ1 0x5B
+#define TAS5713_CH3_BQ0 0x5E
+#define TAS5713_CH3_BQ1 0x5F
+
+#define TAS5713_DRC1_SOFTENING_FILTER_ALPHA_OMEGA 0x3B
+#define TAS5713_DRC1_ATTACK_RELEASE_RATE 0x3C
+#define TAS5713_DRC2_SOFTENING_FILTER_ALPHA_OMEGA 0x3E
+#define TAS5713_DRC2_ATTACK_RELEASE_RATE 0x3F
+#define TAS5713_DRC1_ATTACK_RELEASE_THRES 0x40
+#define TAS5713_DRC2_ATTACK_RELEASE_THRES 0x43
+#define TAS5713_DRC_CTRL 0x46
+
+#define TAS5713_BANK_SW_CTRL 0x50
+#define TAS5713_CH1_OUTPUT_MIXER 0x51
+#define TAS5713_CH2_OUTPUT_MIXER 0x52
+#define TAS5713_CH1_INPUT_MIXER 0x53
+#define TAS5713_CH2_INPUT_MIXER 0x54
+#define TAS5713_OUTPUT_POST_SCALE 0x56
+#define TAS5713_OUTPUT_PRESCALE 0x57
+
+#define TAS5713_IDF_POST_SCALE 0x62
+
+#define TAS5713_CH1_INLINE_MIXER 0x70
+#define TAS5713_CH1_INLINE_DRC_EN_MIXER 0x71
+#define TAS5713_CH1_R_CHANNEL_MIXER 0x72
+#define TAS5713_CH1_L_CHANNEL_MIXER 0x73
+#define TAS5713_CH2_INLINE_MIXER 0x74
+#define TAS5713_CH2_INLINE_DRC_EN_MIXER 0x75
+#define TAS5713_CH2_L_CHANNEL_MIXER 0x76
+#define TAS5713_CH2_R_CHANNEL_MIXER 0x77
+
+#define TAS5713_UPDATE_DEV_ADDR_KEY 0xF8
+#define TAS5713_UPDATE_DEV_ADDR_REG 0xF9
+
+#define TAS5713_REGISTER_COUNT 0x46
+#define TAS5713_MAX_REGISTER 0xF9
+
+
+// Bitmasks for registers
+#define TAS5713_SOFT_MUTE_ALL 0x07
+
+
+
+struct tas5713_init_command {
+ const int size;
+ const char *const data;
+};
+
+static const struct tas5713_init_command tas5713_init_sequence[] = {
+
+ // Trim oscillator
+ { .size = 2, .data = "\x1B\x00" },
+ // System control register 1 (0x03): block DC
+ { .size = 2, .data = "\x03\x80" },
+ // Mute everything
+ { .size = 2, .data = "\x05\x40" },
+ // Modulation limit register (0x10): 97.7%
+ { .size = 2, .data = "\x10\x02" },
+ // Interchannel delay registers
+ // (0x11, 0x12, 0x13, and 0x14): BD mode
+ { .size = 2, .data = "\x11\xB8" },
+ { .size = 2, .data = "\x12\x60" },
+ { .size = 2, .data = "\x13\xA0" },
+ { .size = 2, .data = "\x14\x48" },
+ // PWM shutdown group register (0x19): no shutdown
+ { .size = 2, .data = "\x19\x00" },
+ // Input multiplexer register (0x20): BD mode
+ { .size = 2, .data = "\x20\x00\x89\x77\x72" },
+ // PWM output mux register (0x25)
+ // Channel 1 --> OUTA, channel 1 neg --> OUTB
+ // Channel 2 --> OUTC, channel 2 neg --> OUTD
+ { .size = 5, .data = "\x25\x01\x02\x13\x45" },
+ // DRC control (0x46): DRC off
+ { .size = 5, .data = "\x46\x00\x00\x00\x00" },
+ // BKND_ERR register (0x1C): 299ms reset period
+ { .size = 2, .data = "\x1C\x07" },
+ // Mute channel 3
+ { .size = 2, .data = "\x0A\xFF" },
+ // Volume configuration register (0x0E): volume slew 512 steps
+ { .size = 2, .data = "\x0E\x90" },
+ // Clock control register (0x00): 44/48kHz, MCLK=64xfs
+ { .size = 2, .data = "\x00\x60" },
+ // Bank switch and eq control (0x50): no bank switching
+ { .size = 5, .data = "\x50\x00\x00\x00\x00" },
+ // Volume registers (0x07, 0x08, 0x09, 0x0A)
+ { .size = 2, .data = "\x07\x20" },
+ { .size = 2, .data = "\x08\x30" },
+ { .size = 2, .data = "\x09\x30" },
+ { .size = 2, .data = "\x0A\xFF" },
+ // 0x72, 0x73, 0x76, 0x77 input mixer:
+ // no intermix between channels
+ { .size = 5, .data = "\x72\x00\x00\x00\x00" },
+ { .size = 5, .data = "\x73\x00\x80\x00\x00" },
+ { .size = 5, .data = "\x76\x00\x00\x00\x00" },
+ { .size = 5, .data = "\x77\x00\x80\x00\x00" },
+ // 0x70, 0x71, 0x74, 0x75 inline DRC mixer:
+ // no inline DRC inmix
+ { .size = 5, .data = "\x70\x00\x80\x00\x00" },
+ { .size = 5, .data = "\x71\x00\x00\x00\x00" },
+ { .size = 5, .data = "\x74\x00\x80\x00\x00" },
+ { .size = 5, .data = "\x75\x00\x00\x00\x00" },
+ // 0x56, 0x57 Output scale
+ { .size = 5, .data = "\x56\x00\x80\x00\x00" },
+ { .size = 5, .data = "\x57\x00\x02\x00\x00" },
+ // 0x3B, 0x3c
+ { .size = 9, .data = "\x3B\x00\x08\x00\x00\x00\x78\x00\x00" },
+ { .size = 9, .data = "\x3C\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
+ { .size = 9, .data = "\x3E\x00\x08\x00\x00\x00\x78\x00\x00" },
+ { .size = 9, .data = "\x3F\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
+ { .size = 9, .data = "\x40\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
+ { .size = 9, .data = "\x43\x00\x00\x01\x00\xFF\xFF\xFF\x00" },
+ // 0x51, 0x52: output mixer
+ { .size = 9, .data = "\x51\x00\x80\x00\x00\x00\x00\x00\x00" },
+ { .size = 9, .data = "\x52\x00\x80\x00\x00\x00\x00\x00\x00" },
+ // PEQ defaults
+ { .size = 21, .data = "\x29\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x2F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x30\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x31\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x32\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x33\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x34\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x35\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x36\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x58\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x59\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5C\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5D\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5E\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5F\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5A\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+ { .size = 21, .data = "\x5B\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" },
+};
+
+
+#endif /* _TAS5713_H */

View File

@ -0,0 +1,25 @@
From b904f76b1090667c9f4741a60da8e60cebc8a91c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 13 Apr 2015 19:14:18 +0100
Subject: [PATCH 049/121] bcm2708: Allow option card devices to be configured
via DT
If the kernel is built with Device Tree support, and if a DT blob
is provided for the kernel at boot time, then the platform devices
for option cards are not created. This avoids both the need to
blacklist unwanted devices, and the need to update the board
support code with each new device.
---
sound/soc/bcm/bcm2835-i2s.c | 1 +
1 file changed, 1 insertion(+)
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -861,6 +861,7 @@ static const struct of_device_id bcm2835
{ .compatible = "brcm,bcm2835-i2s", },
{},
};
+MODULE_DEVICE_TABLE(of, bcm2835_i2s_of_match);
static struct platform_driver bcm2835_i2s_driver = {
.probe = bcm2835_i2s_probe,

View File

@ -0,0 +1,353 @@
From 8b4aab9c9a47544e493ba3479ad0e6397e4ea27a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 13 Apr 2015 18:45:39 +0100
Subject: [PATCH 050/121] Adding Device Tree support for some RPi audio cards
---
arch/arm/mach-bcm2709/bcm2709.c | 143 ++++++++++++++++++++++++++++++++++++++
sound/soc/bcm/hifiberry_dac.c | 22 ++++++
sound/soc/bcm/hifiberry_dacplus.c | 22 ++++++
sound/soc/bcm/hifiberry_digi.c | 22 ++++++
sound/soc/bcm/iqaudio-dac.c | 16 +++++
sound/soc/codecs/pcm5102a.c | 7 ++
6 files changed, 232 insertions(+)
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -636,6 +636,115 @@ static struct platform_device bcm2835_th
.name = "bcm2835_thermal",
};
+#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE)
+static struct resource bcm2708_i2s_resources[] = {
+ {
+ .start = I2S_BASE,
+ .end = I2S_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = PCM_CLOCK_BASE,
+ .end = PCM_CLOCK_BASE + 0x02,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device bcm2708_i2s_device = {
+ .name = "bcm2708-i2s",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_i2s_resources),
+ .resource = bcm2708_i2s_resources,
+};
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+static struct platform_device snd_hifiberry_dac_device = {
+ .name = "snd-hifiberry-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm5102a_codec_device = {
+ .name = "pcm5102a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE)
+static struct platform_device snd_rpi_hifiberry_dacplus_device = {
+ .name = "snd-rpi-hifiberry-dacplus",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_pcm512x_hbdacplus_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("pcm5122", 0x4d)
+ },
+};
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
+static struct platform_device snd_hifiberry_digi_device = {
+ .name = "snd-hifiberry-digi",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_wm8804_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("wm8804", 0x3b)
+ },
+};
+
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP_MODULE)
+static struct platform_device snd_hifiberry_amp_device = {
+ .name = "snd-hifiberry-amp",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct i2c_board_info __initdata snd_tas5713_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tas5713", 0x1b)
+ },
+};
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+static struct platform_device snd_rpi_dac_device = {
+ .name = "snd-rpi-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm1794a_codec_device = {
+ .name = "pcm1794a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
+
+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE)
+static struct platform_device snd_rpi_iqaudio_dac_device = {
+ .name = "snd-rpi-iqaudio-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+// Use the actual device name rather than generic driver name
+static struct i2c_board_info __initdata snd_pcm512x_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("pcm5122", 0x4c)
+ },
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -800,6 +909,40 @@ void __init bcm2709_init(void)
bcm_register_device_dt(&bcm2835_thermal_device);
+#if defined(CONFIG_SND_BCM2708_SOC_I2S) || defined(CONFIG_SND_BCM2708_SOC_I2S_MODULE)
+ bcm_register_device_dt(&bcm2708_i2s_device);
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_dac_device);
+ bcm_register_device_dt(&snd_pcm5102a_codec_device);
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DACPLUS_MODULE)
+ bcm_register_device_dt(&snd_rpi_hifiberry_dacplus_device);
+ i2c_register_board_info_dt(1, snd_pcm512x_hbdacplus_i2c_devices, ARRAY_SIZE(snd_pcm512x_hbdacplus_i2c_devices));
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_digi_device);
+ i2c_register_board_info_dt(1, snd_wm8804_i2c_devices, ARRAY_SIZE(snd_wm8804_i2c_devices));
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP_MODULE)
+ bcm_register_device_dt(&snd_hifiberry_amp_device);
+ i2c_register_board_info_dt(1, snd_tas5713_i2c_devices, ARRAY_SIZE(snd_tas5713_i2c_devices));
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+ bcm_register_device_dt(&snd_rpi_dac_device);
+ bcm_register_device_dt(&snd_pcm1794a_codec_device);
+#endif
+
+#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE)
+ bcm_register_device_dt(&snd_rpi_iqaudio_dac_device);
+ i2c_register_board_info_dt(1, snd_pcm512x_i2c_devices, ARRAY_SIZE(snd_pcm512x_i2c_devices));
+#endif
+
if (!use_dt) {
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
--- a/sound/soc/bcm/hifiberry_dac.c
+++ b/sound/soc/bcm/hifiberry_dac.c
@@ -72,6 +72,21 @@ static int snd_rpi_hifiberry_dac_probe(s
int ret = 0;
snd_rpi_hifiberry_dac.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dac_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
ret = snd_soc_register_card(&snd_rpi_hifiberry_dac);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
@@ -84,10 +99,17 @@ static int snd_rpi_hifiberry_dac_remove(
return snd_soc_unregister_card(&snd_rpi_hifiberry_dac);
}
+static const struct of_device_id snd_rpi_hifiberry_dac_of_match[] = {
+ { .compatible = "hifiberry,hifiberry-dac", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dac_of_match);
+
static struct platform_driver snd_rpi_hifiberry_dac_driver = {
.driver = {
.name = "snd-hifiberry-dac",
.owner = THIS_MODULE,
+ .of_match_table = snd_rpi_hifiberry_dac_of_match,
},
.probe = snd_rpi_hifiberry_dac_probe,
.remove = snd_rpi_hifiberry_dac_remove,
--- a/sound/soc/bcm/hifiberry_dacplus.c
+++ b/sound/soc/bcm/hifiberry_dacplus.c
@@ -90,6 +90,21 @@ static int snd_rpi_hifiberry_dacplus_pro
int ret = 0;
snd_rpi_hifiberry_dacplus.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_dacplus_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
ret = snd_soc_register_card(&snd_rpi_hifiberry_dacplus);
if (ret)
dev_err(&pdev->dev,
@@ -103,10 +118,17 @@ static int snd_rpi_hifiberry_dacplus_rem
return snd_soc_unregister_card(&snd_rpi_hifiberry_dacplus);
}
+static const struct of_device_id snd_rpi_hifiberry_dacplus_of_match[] = {
+ { .compatible = "hifiberry,hifiberry-dacplus", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_dacplus_of_match);
+
static struct platform_driver snd_rpi_hifiberry_dacplus_driver = {
.driver = {
.name = "snd-rpi-hifiberry-dacplus",
.owner = THIS_MODULE,
+ .of_match_table = snd_rpi_hifiberry_dacplus_of_match,
},
.probe = snd_rpi_hifiberry_dacplus_probe,
.remove = snd_rpi_hifiberry_dacplus_remove,
--- a/sound/soc/bcm/hifiberry_digi.c
+++ b/sound/soc/bcm/hifiberry_digi.c
@@ -173,6 +173,21 @@ static int snd_rpi_hifiberry_digi_probe(
int ret = 0;
snd_rpi_hifiberry_digi.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_hifiberry_digi_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
@@ -185,10 +200,17 @@ static int snd_rpi_hifiberry_digi_remove
return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
}
+static const struct of_device_id snd_rpi_hifiberry_digi_of_match[] = {
+ { .compatible = "hifiberry,hifiberry-digi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_hifiberry_digi_of_match);
+
static struct platform_driver snd_rpi_hifiberry_digi_driver = {
.driver = {
.name = "snd-hifiberry-digi",
.owner = THIS_MODULE,
+ .of_match_table = snd_rpi_hifiberry_digi_of_match,
},
.probe = snd_rpi_hifiberry_digi_probe,
.remove = snd_rpi_hifiberry_digi_remove,
--- a/sound/soc/bcm/iqaudio-dac.c
+++ b/sound/soc/bcm/iqaudio-dac.c
@@ -82,6 +82,21 @@ static int snd_rpi_iqaudio_dac_probe(str
int ret = 0;
snd_rpi_iqaudio_dac.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_iqaudio_dac_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
ret = snd_soc_register_card(&snd_rpi_iqaudio_dac);
if (ret)
dev_err(&pdev->dev,
@@ -99,6 +114,7 @@ static const struct of_device_id iqaudio
{ .compatible = "iqaudio,iqaudio-dac", },
{},
};
+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
static struct platform_driver snd_rpi_iqaudio_dac_driver = {
.driver = {
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -47,12 +47,19 @@ static int pcm5102a_remove(struct platfo
return 0;
}
+static const struct of_device_id pcm5102a_of_match[] = {
+ { .compatible = "ti,pcm5102a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm5102a_of_match);
+
static struct platform_driver pcm5102a_codec_driver = {
.probe = pcm5102a_probe,
.remove = pcm5102a_remove,
.driver = {
.name = "pcm5102a-codec",
.owner = THIS_MODULE,
+ .of_match_table = pcm5102a_of_match,
},
};

View File

@ -0,0 +1,134 @@
From bc32dfd7d696d4e3c381344064aabc38961b7f46 Mon Sep 17 00:00:00 2001
From: Timo Kokkonen <tjko@iki.fi>
Date: Wed, 29 Oct 2014 23:30:30 -0700
Subject: [PATCH 051/121] Added support to reserve/enable a GPIO pin to be used
from pps-gpio module (LinuxPPS). Enable PPS modules in default config for
RPi.
---
arch/arm/mach-bcm2708/bcm2708.c | 27 +++++++++++++++++++++++++++
arch/arm/mach-bcm2709/bcm2709.c | 27 +++++++++++++++++++++++++++
2 files changed, 54 insertions(+)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -37,6 +37,7 @@
#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
#include <linux/w1-gpio.h>
+#include <linux/pps-gpio.h>
#include <linux/version.h>
#include <linux/clkdev.h>
@@ -92,6 +93,7 @@ static unsigned reboot_part = 0;
static unsigned w1_gpio_pin = W1_GPIO;
static unsigned w1_gpio_pullup = W1_PULLUP;
static bool vc_i2c_override = false;
+static int pps_gpio_pin = -1;
static unsigned use_dt = 0;
@@ -325,6 +327,19 @@ static struct platform_device w1_device
};
#endif
+static struct pps_gpio_platform_data pps_gpio_info = {
+ .assert_falling_edge = false,
+ .capture_clear = false,
+ .gpio_pin = -1,
+ .gpio_label = "PPS",
+};
+
+static struct platform_device pps_gpio_device = {
+ .name = "pps-gpio",
+ .id = PLATFORM_DEVID_NONE,
+ .dev.platform_data = &pps_gpio_info,
+};
+
static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
static struct platform_device bcm2708_fb_device = {
@@ -860,6 +875,16 @@ void __init bcm2708_init(void)
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
+
+#if defined(CONFIG_PPS_CLIENT_GPIO) || defined(CONFIG_PPS_CLIENT_GPIO_MODULE)
+ if (!use_dt && (pps_gpio_pin >= 0)) {
+ pr_info("bcm2708: GPIO %d setup as pps-gpio device\n", pps_gpio_pin);
+ pps_gpio_info.gpio_pin = pps_gpio_pin;
+ pps_gpio_device.id = pps_gpio_pin;
+ bcm_register_device(&pps_gpio_device);
+ }
+#endif
+
#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
w1_gpio_pdata.pin = w1_gpio_pin;
w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
@@ -1116,3 +1141,5 @@ module_param(w1_gpio_pin, uint, 0644);
module_param(w1_gpio_pullup, uint, 0644);
module_param(vc_i2c_override, bool, 0644);
MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
+module_param(pps_gpio_pin, int, 0644);
+MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS");
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -37,6 +37,7 @@
#include <linux/spi/spi.h>
#include <linux/gpio/machine.h>
#include <linux/w1-gpio.h>
+#include <linux/pps-gpio.h>
#include <linux/version.h>
#include <linux/clkdev.h>
@@ -94,6 +95,7 @@ static unsigned reboot_part = 0;
static unsigned w1_gpio_pin = W1_GPIO;
static unsigned w1_gpio_pullup = W1_PULLUP;
static bool vc_i2c_override = false;
+static int pps_gpio_pin = -1;
static unsigned use_dt = 0;
@@ -335,6 +337,19 @@ static struct platform_device w1_device
};
#endif
+static struct pps_gpio_platform_data pps_gpio_info = {
+ .assert_falling_edge = false,
+ .capture_clear = false,
+ .gpio_pin = -1,
+ .gpio_label = "PPS",
+};
+
+static struct platform_device pps_gpio_device = {
+ .name = "pps-gpio",
+ .id = PLATFORM_DEVID_NONE,
+ .dev.platform_data = &pps_gpio_info,
+};
+
static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
static struct platform_device bcm2708_fb_device = {
@@ -880,6 +895,16 @@ void __init bcm2709_init(void)
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
#endif
+
+#if defined(CONFIG_PPS_CLIENT_GPIO) || defined(CONFIG_PPS_CLIENT_GPIO_MODULE)
+ if (!use_dt && (pps_gpio_pin >= 0)) {
+ pr_info("bcm2709: GPIO %d setup as pps-gpio device\n", pps_gpio_pin);
+ pps_gpio_info.gpio_pin = pps_gpio_pin;
+ pps_gpio_device.id = pps_gpio_pin;
+ bcm_register_device(&pps_gpio_device);
+ }
+#endif
+
#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
w1_gpio_pdata.pin = w1_gpio_pin;
w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
@@ -1284,3 +1309,5 @@ module_param(w1_gpio_pin, uint, 0644);
module_param(w1_gpio_pullup, uint, 0644);
module_param(vc_i2c_override, bool, 0644);
MODULE_PARM_DESC(vc_i2c_override, "Allow the use of VC's I2C peripheral.");
+module_param(pps_gpio_pin, int, 0644);
+MODULE_PARM_DESC(pps_gpio_pin, "Set GPIO pin to reserve for PPS");

View File

@ -0,0 +1,27 @@
From 5b706049d22fc0593a14a1d94ebf7f9bf54feeea Mon Sep 17 00:00:00 2001
From: Ryan Coe <bluemrp9@gmail.com>
Date: Sat, 31 Jan 2015 18:25:49 -0700
Subject: [PATCH 052/121] Update ds1307 driver for device-tree support
Signed-off-by: Ryan Coe <bluemrp9@gmail.com>
---
drivers/rtc/rtc-ds1307.c | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -1242,6 +1242,14 @@ static int ds1307_remove(struct i2c_clie
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id ds1307_of_match[] = {
+ { .compatible = "maxim,ds1307" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds1307_of_match);
+#endif
+
static struct i2c_driver ds1307_driver = {
.driver = {
.name = "rtc-ds1307",

View File

@ -0,0 +1,106 @@
From 1578dbee8e10fed1be0f64820fe511dc4b7a720e Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 6 Feb 2015 13:50:57 +0000
Subject: [PATCH 053/121] BCM270x_DT: Add pwr_led, and the required "input"
trigger
The "input" trigger makes the associated GPIO an input. This is to support
the Raspberry Pi PWR LED, which is driven by external hardware in normal use.
N.B. pwr_led is not available on Model A or B boards.
---
drivers/leds/trigger/Kconfig | 7 ++++
drivers/leds/trigger/Makefile | 1 +
drivers/leds/trigger/ledtrig-input.c | 65 ++++++++++++++++++++++++++++++++++++
3 files changed, 73 insertions(+)
create mode 100644 drivers/leds/trigger/ledtrig-input.c
--- a/drivers/leds/trigger/Kconfig
+++ b/drivers/leds/trigger/Kconfig
@@ -126,4 +126,11 @@ config LEDS_TRIGGER_USBDEV
This allows LEDs to be controlled by the presence/activity of
an USB device. If unsure, say N.
+config LEDS_TRIGGER_INPUT
+ tristate "LED Input Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows the GPIOs assigned to be LEDs to be initialised to inputs.
+ If unsure, say Y.
+
endif # LEDS_TRIGGERS
--- a/drivers/leds/trigger/Makefile
+++ b/drivers/leds/trigger/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_LEDS_TRIGGER_CPU) += ledtr
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
+obj-$(CONFIG_LEDS_TRIGGER_INPUT) += ledtrig-input.o
--- /dev/null
+++ b/drivers/leds/trigger/ledtrig-input.c
@@ -0,0 +1,65 @@
+/*
+ * Set LED GPIO to Input "Trigger"
+ *
+ * Copyright 2015 Phil Elwell <phil@raspberrypi.org>
+ *
+ * Based on Nick Forbes's ledtrig-default-on.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include "../leds.h"
+
+/* This is a hack to get at the private 'gpio' member */
+
+struct gpio_led_data {
+ struct led_classdev cdev;
+ unsigned gpio;
+};
+
+static void input_trig_activate(struct led_classdev *led_cdev)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+ if (gpio_is_valid(led_dat->gpio))
+ gpio_direction_input(led_dat->gpio);
+}
+
+static void input_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct gpio_led_data *led_dat =
+ container_of(led_cdev, struct gpio_led_data, cdev);
+ if (gpio_is_valid(led_dat->gpio))
+ gpio_direction_output(led_dat->gpio, 0);
+}
+
+static struct led_trigger input_led_trigger = {
+ .name = "input",
+ .activate = input_trig_activate,
+ .deactivate = input_trig_deactivate,
+};
+
+static int __init input_trig_init(void)
+{
+ return led_trigger_register(&input_led_trigger);
+}
+
+static void __exit input_trig_exit(void)
+{
+ led_trigger_unregister(&input_led_trigger);
+}
+
+module_init(input_trig_init);
+module_exit(input_trig_exit);
+
+MODULE_AUTHOR("Phil Elwell <phil@raspberrypi.org>");
+MODULE_DESCRIPTION("Set LED GPIO to Input \"trigger\"");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,222 @@
From a926a1d2720eef63b580a4510a9aec4540836d40 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 20 Jun 2014 17:19:27 +0100
Subject: [PATCH 054/121] bcm2709: Simplify and strip down IRQ handler
---
arch/arm/include/asm/entry-macro-multi.S | 2 +
arch/arm/mach-bcm2709/include/mach/entry-macro.S | 173 +++++++++++------------
2 files changed, 87 insertions(+), 88 deletions(-)
--- a/arch/arm/include/asm/entry-macro-multi.S
+++ b/arch/arm/include/asm/entry-macro-multi.S
@@ -1,5 +1,6 @@
#include <asm/assembler.h>
+#ifndef CONFIG_ARCH_BCM2709
/*
* Interrupt handling. Preserves r7, r8, r9
*/
@@ -28,6 +29,7 @@
#endif
9997:
.endm
+#endif
.macro arch_irq_handler, symbol_name
.align 5
--- a/arch/arm/mach-bcm2709/include/mach/entry-macro.S
+++ b/arch/arm/mach-bcm2709/include/mach/entry-macro.S
@@ -22,102 +22,99 @@
#include <mach/hardware.h>
#include <mach/irqs.h>
- .macro disable_fiq
- .endm
+ .macro arch_ret_to_user, tmp1, tmp2
+ .endm
- .macro get_irqnr_preamble, base, tmp
- ldr \base, =IO_ADDRESS(ARMCTRL_IC_BASE)
- .endm
-
- .macro arch_ret_to_user, tmp1, tmp2
- .endm
-
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- /* get core number */
- mrc p15, 0, \tmp, c0, c0, 5
- ubfx \tmp, \tmp, #0, #2
-
- /* get core's local interrupt controller */
- ldr \irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0) @ local interrupt source
- add \irqstat, \irqstat, \tmp, lsl #2
- ldr \tmp, [\irqstat]
- /* ignore gpu interrupt */
- bic \tmp, #0x100
- /* ignore mailbox interrupts */
- bics \tmp, #0xf0
- beq 1005f
-
- @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
- @ N.B. CLZ is an ARM5 instruction.
- mov \irqnr, #(ARM_IRQ_LOCAL_BASE + 31)
- sub \irqstat, \tmp, #1
- eor \irqstat, \irqstat, \tmp
- clz \tmp, \irqstat
- sub \irqnr, \tmp
- b 1020f
-1005:
- /* get core number */
- mrc p15, 0, \tmp, c0, c0, 5
- ubfx \tmp, \tmp, #0, #2
-
- cmp \tmp, #1
- beq 1020f
- cmp \tmp, #2
- beq 1020f
- cmp \tmp, #3
- beq 1020f
-
- /* get masked status */
- ldr \irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)]
- mov \irqnr, #(ARM_IRQ0_BASE + 31)
- and \tmp, \irqstat, #0x300 @ save bits 8 and 9
- /* clear bits 8 and 9, and test */
- bics \irqstat, \irqstat, #0x300
- bne 1010f
-
- tst \tmp, #0x100
- ldrne \irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)]
- movne \irqnr, #(ARM_IRQ1_BASE + 31)
- @ Mask out the interrupts also present in PEND0 - see SW-5809
- bicne \irqstat, #((1<<7) | (1<<9) | (1<<10))
- bicne \irqstat, #((1<<18) | (1<<19))
- bne 1010f
-
- tst \tmp, #0x200
- ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)]
- movne \irqnr, #(ARM_IRQ2_BASE + 31)
- @ Mask out the interrupts also present in PEND0 - see SW-5809
- bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25))
- bicne \irqstat, #((1<<30))
- beq 1020f
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ /* get core number */
+ mrc p15, 0, \base, c0, c0, 5
+ ubfx \base, \base, #0, #2
+
+ /* get core's local interrupt controller */
+ ldr \irqstat, = __io_address(ARM_LOCAL_IRQ_PENDING0) @ local interrupt source
+ add \irqstat, \irqstat, \base, lsl #2
+ ldr \tmp, [\irqstat]
+#ifdef CONFIG_SMP
+ /* test for mailbox0 (IPI) interrupt */
+ tst \tmp, #0x10
+ beq 1030f
+
+ /* get core's mailbox interrupt control */
+ ldr \irqstat, = __io_address(ARM_LOCAL_MAILBOX0_CLR0) @ mbox_clr
+ add \irqstat, \irqstat, \base, lsl #4
+ ldr \tmp, [\irqstat]
+ clz \tmp, \tmp
+ rsb \irqnr, \tmp, #31
+ mov \tmp, #1
+ lsl \tmp, \irqnr
+ str \tmp, [\irqstat] @ clear interrupt source
+ dsb
+ mov r1, sp
+ adr lr, BSYM(1b)
+ b do_IPI
+#endif
+1030:
+ /* check gpu interrupt */
+ tst \tmp, #0x100
+ beq 1040f
+
+ ldr \base, =IO_ADDRESS(ARMCTRL_IC_BASE)
+ /* get masked status */
+ ldr \irqstat, [\base, #(ARM_IRQ_PEND0 - ARMCTRL_IC_BASE)]
+ mov \irqnr, #(ARM_IRQ0_BASE + 31)
+ and \tmp, \irqstat, #0x300 @ save bits 8 and 9
+ /* clear bits 8 and 9, and test */
+ bics \irqstat, \irqstat, #0x300
+ bne 1010f
+
+ tst \tmp, #0x100
+ ldrne \irqstat, [\base, #(ARM_IRQ_PEND1 - ARMCTRL_IC_BASE)]
+ movne \irqnr, #(ARM_IRQ1_BASE + 31)
+ @ Mask out the interrupts also present in PEND0 - see SW-5809
+ bicne \irqstat, #((1<<7) | (1<<9) | (1<<10))
+ bicne \irqstat, #((1<<18) | (1<<19))
+ bne 1010f
+
+ tst \tmp, #0x200
+ ldrne \irqstat, [\base, #(ARM_IRQ_PEND2 - ARMCTRL_IC_BASE)]
+ movne \irqnr, #(ARM_IRQ2_BASE + 31)
+ @ Mask out the interrupts also present in PEND0 - see SW-5809
+ bicne \irqstat, #((1<<21) | (1<<22) | (1<<23) | (1<<24) | (1<<25))
+ bicne \irqstat, #((1<<30))
+ beq 1020f
1010:
- @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
- @ N.B. CLZ is an ARM5 instruction.
- sub \tmp, \irqstat, #1
- eor \irqstat, \irqstat, \tmp
- clz \tmp, \irqstat
- sub \irqnr, \tmp
+ @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
+ sub \tmp, \irqstat, #1
+ eor \irqstat, \irqstat, \tmp
+ clz \tmp, \irqstat
+ sub \irqnr, \tmp
+ b 1050f
+1040:
+ cmp \tmp, #0
+ beq 1020f
+
+ /* handle local (e.g. timer) interrupts */
+ @ For non-zero x, LSB(x) = 31 - CLZ(x^(x-1))
+ mov \irqnr, #(ARM_IRQ_LOCAL_BASE + 31)
+ sub \irqstat, \tmp, #1
+ eor \irqstat, \irqstat, \tmp
+ clz \tmp, \irqstat
+ sub \irqnr, \tmp
+1050:
+ mov r1, sp
+ @
+ @ routine called with r0 = irq number, r1 = struct pt_regs *
+ @
+ adr lr, BSYM(1b)
+ b asm_do_IRQ
1020: @ EQ will be set if no irqs pending
+ .endm
- .endm
-
- .macro test_for_ipi, irqnr, irqstat, base, tmp
- /* get core number */
- mrc p15, 0, \tmp, c0, c0, 5
- ubfx \tmp, \tmp, #0, #2
- /* get core's mailbox interrupt control */
- ldr \irqstat, = __io_address(ARM_LOCAL_MAILBOX0_CLR0) @ mbox_clr
- add \irqstat, \irqstat, \tmp, lsl #4
- ldr \tmp, [\irqstat]
- cmp \tmp, #0
- beq 1030f
- clz \tmp, \tmp
- rsb \irqnr, \tmp, #31
- mov \tmp, #1
- lsl \tmp, \irqnr
- str \tmp, [\irqstat] @ clear interrupt source
- dsb
-1030: @ EQ will be set if no irqs pending
- .endm
+/*
+ * Interrupt handling. Preserves r7, r8, r9
+ */
+ .macro arch_irq_handler_default
+1: get_irqnr_and_base r0, r2, r6, lr
+ .endm

View File

@ -0,0 +1,83 @@
From 39cf4677b7c38fac3da503b75d5cd7efc64dd19a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 12 Feb 2015 11:17:53 +0000
Subject: [PATCH 055/121] Fix LED "input" trigger implementation for 3.19
---
drivers/leds/leds-gpio.c | 10 +++++++++-
drivers/leds/trigger/ledtrig-input.c | 19 ++++---------------
include/linux/leds.h | 3 +++
3 files changed, 16 insertions(+), 16 deletions(-)
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -41,6 +41,13 @@ static void gpio_led_work(struct work_st
led_dat->platform_gpio_blink_set(led_dat->gpiod,
led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
+ } else if (led_dat->cdev.flags & SET_GPIO_INPUT) {
+ gpiod_direction_input(led_dat->gpiod);
+ led_dat->cdev.flags &= ~SET_GPIO_INPUT;
+ }
+ else if (led_dat->cdev.flags & SET_GPIO_OUTPUT) {
+ gpiod_direction_output(led_dat->gpiod, led_dat->new_level);
+ led_dat->cdev.flags &= ~SET_GPIO_OUTPUT;
} else
gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
@@ -61,7 +68,8 @@ static void gpio_led_set(struct led_clas
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
*/
- if (led_dat->can_sleep) {
+ if (led_dat->can_sleep ||
+ (led_dat->cdev.flags & (SET_GPIO_INPUT | SET_GPIO_OUTPUT) )) {
led_dat->new_level = level;
schedule_work(&led_dat->work);
} else {
--- a/drivers/leds/trigger/ledtrig-input.c
+++ b/drivers/leds/trigger/ledtrig-input.c
@@ -18,27 +18,16 @@
#include <linux/gpio.h>
#include "../leds.h"
-/* This is a hack to get at the private 'gpio' member */
-
-struct gpio_led_data {
- struct led_classdev cdev;
- unsigned gpio;
-};
-
static void input_trig_activate(struct led_classdev *led_cdev)
{
- struct gpio_led_data *led_dat =
- container_of(led_cdev, struct gpio_led_data, cdev);
- if (gpio_is_valid(led_dat->gpio))
- gpio_direction_input(led_dat->gpio);
+ led_cdev->flags |= SET_GPIO_INPUT;
+ led_set_brightness_async(led_cdev, 0);
}
static void input_trig_deactivate(struct led_classdev *led_cdev)
{
- struct gpio_led_data *led_dat =
- container_of(led_cdev, struct gpio_led_data, cdev);
- if (gpio_is_valid(led_dat->gpio))
- gpio_direction_output(led_dat->gpio, 0);
+ led_cdev->flags |= SET_GPIO_OUTPUT;
+ led_set_brightness_async(led_cdev, 0);
}
static struct led_trigger input_led_trigger = {
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -47,6 +47,9 @@ struct led_classdev {
#define SET_BRIGHTNESS_ASYNC (1 << 21)
#define SET_BRIGHTNESS_SYNC (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
+ /* Additions for Raspberry Pi PWR LED */
+#define SET_GPIO_INPUT (1 << 30)
+#define SET_GPIO_OUTPUT (1 << 31)
/* Set LED brightness level */
/* Must not sleep, use a workqueue if needed */

View File

@ -0,0 +1,22 @@
From d6f122c984a90914b054c16def454ee77a002bad Mon Sep 17 00:00:00 2001
From: notro <notro@tronnes.org>
Date: Thu, 10 Jul 2014 13:59:47 +0200
Subject: [PATCH 056/121] pinctrl-bcm2835: Set base to 0 give expected gpio
numbering
Signed-off-by: Noralf Tronnes <notro@tronnes.org>
---
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -382,7 +382,7 @@ static struct gpio_chip bcm2835_gpio_chi
.get = bcm2835_gpio_get,
.set = bcm2835_gpio_set,
.to_irq = bcm2835_gpio_to_irq,
- .base = -1,
+ .base = 0,
.ngpio = BCM2835_NUM_GPIOS,
.can_sleep = false,
};

View File

@ -0,0 +1,28 @@
From 0bb455e4eca847aa74560f58bfd7daa13e9fb496 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 4 Feb 2015 10:02:24 +0000
Subject: [PATCH 057/121] pinctrl-bcm2835: bcm2835_gpio_direction_output must
set the value
---
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -355,7 +355,14 @@ static int bcm2835_gpio_get(struct gpio_
static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
- return pinctrl_gpio_direction_output(chip->base + offset);
+ struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
+ int ret;
+
+ ret = pinctrl_gpio_direction_output(chip->base + offset);
+ if (ret >= 0)
+ bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
+
+ return ret;
}
static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)

View File

@ -0,0 +1,146 @@
From 1ee5ccaeae81a9acd296d4d3eaba9fa1807b9e17 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 24 Feb 2015 13:40:50 +0000
Subject: [PATCH 058/121] pinctrl-bcm2835: Fix interrupt handling for GPIOs
28-31 and 46-53
Contrary to the documentation, the BCM2835 GPIO controller actually has
four interrupt lines - one each for the three IRQ groups and one common. Rather
confusingly, the GPIO interrupt groups don't correspond directly with the GPIO
control banks. Instead, GPIOs 0-27 generate IRQ GPIO0, 28-45 GPIO1 and
46-53 GPIO2.
Awkwardly, the GPIOS for IRQ GPIO1 straddle two 32-entry GPIO banks, so it is
cleaner to split out a function to process the interrupts for a single GPIO
bank.
This bug has only just been observed because GPIOs above 27 can only be
accessed on an old Raspberry Pi with the optional P5 header fitted, where
the pins are often used for I2S instead.
---
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 51 ++++++++++++++++++++++++++---------
1 file changed, 39 insertions(+), 12 deletions(-)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -47,6 +47,7 @@
#define MODULE_NAME "pinctrl-bcm2835"
#define BCM2835_NUM_GPIOS 54
#define BCM2835_NUM_BANKS 2
+#define BCM2835_NUM_IRQS 3
#define BCM2835_PIN_BITMAP_SZ \
DIV_ROUND_UP(BCM2835_NUM_GPIOS, sizeof(unsigned long) * 8)
@@ -88,13 +89,13 @@ enum bcm2835_pinconf_pull {
struct bcm2835_gpio_irqdata {
struct bcm2835_pinctrl *pc;
- int bank;
+ int irqgroup;
};
struct bcm2835_pinctrl {
struct device *dev;
void __iomem *base;
- int irq[BCM2835_NUM_BANKS];
+ int irq[BCM2835_NUM_IRQS];
/* note: locking assumes each bank will have its own unsigned long */
unsigned long enabled_irq_map[BCM2835_NUM_BANKS];
@@ -105,7 +106,7 @@ struct bcm2835_pinctrl {
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range gpio_range;
- struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_BANKS];
+ struct bcm2835_gpio_irqdata irq_data[BCM2835_NUM_IRQS];
spinlock_t irq_lock[BCM2835_NUM_BANKS];
};
@@ -394,17 +395,16 @@ static struct gpio_chip bcm2835_gpio_chi
.can_sleep = false,
};
-static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
+static int bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
+ unsigned int bank, u32 mask)
{
- struct bcm2835_gpio_irqdata *irqdata = dev_id;
- struct bcm2835_pinctrl *pc = irqdata->pc;
- int bank = irqdata->bank;
unsigned long events;
unsigned offset;
unsigned gpio;
unsigned int type;
events = bcm2835_gpio_rd(pc, GPEDS0 + bank * 4);
+ events &= mask;
events &= pc->enabled_irq_map[bank];
for_each_set_bit(offset, &events, 32) {
gpio = (32 * bank) + offset;
@@ -412,7 +412,30 @@ static irqreturn_t bcm2835_gpio_irq_hand
generic_handle_irq(irq_linear_revmap(pc->irq_domain, gpio));
}
- return events ? IRQ_HANDLED : IRQ_NONE;
+
+ return (events != 0);
+}
+
+static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id)
+{
+ struct bcm2835_gpio_irqdata *irqdata = dev_id;
+ struct bcm2835_pinctrl *pc = irqdata->pc;
+ int handled = 0;
+
+ switch (irqdata->irqgroup) {
+ case 0: /* IRQ0 covers GPIOs 0-27 */
+ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0x0fffffff);
+ break;
+ case 1: /* IRQ1 covers GPIOs 28-45 */
+ handled = bcm2835_gpio_irq_handle_bank(pc, 0, 0xf0000000) |
+ bcm2835_gpio_irq_handle_bank(pc, 1, 0x00003fff);
+ break;
+ case 2: /* IRQ2 covers GPIOs 46-53 */
+ handled = bcm2835_gpio_irq_handle_bank(pc, 1, 0x003fc000);
+ break;
+ }
+
+ return handled ? IRQ_HANDLED : IRQ_NONE;
}
static inline void __bcm2835_gpio_irq_config(struct bcm2835_pinctrl *pc,
@@ -1000,8 +1023,6 @@ static int bcm2835_pinctrl_probe(struct
for (i = 0; i < BCM2835_NUM_BANKS; i++) {
unsigned long events;
unsigned offset;
- int len;
- char *name;
/* clear event detection flags */
bcm2835_gpio_wr(pc, GPREN0 + i * 4, 0);
@@ -1016,10 +1037,15 @@ static int bcm2835_pinctrl_probe(struct
for_each_set_bit(offset, &events, 32)
bcm2835_gpio_wr(pc, GPEDS0 + i * 4, BIT(offset));
+ spin_lock_init(&pc->irq_lock[i]);
+ }
+
+ for (i = 0; i < BCM2835_NUM_IRQS; i++) {
+ int len;
+ char *name;
pc->irq[i] = irq_of_parse_and_map(np, i);
pc->irq_data[i].pc = pc;
- pc->irq_data[i].bank = i;
- spin_lock_init(&pc->irq_lock[i]);
+ pc->irq_data[i].irqgroup = i;
len = strlen(dev_name(pc->dev)) + 16;
name = devm_kzalloc(pc->dev, len, GFP_KERNEL);
@@ -1077,6 +1103,7 @@ static struct platform_driver bcm2835_pi
.remove = bcm2835_pinctrl_remove,
.driver = {
.name = MODULE_NAME,
+ .owner = THIS_MODULE,
.of_match_table = bcm2835_pinctrl_match,
},
};

View File

@ -0,0 +1,27 @@
From 7e2506a80d3a218bab8db21c947187c92d29812c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 26 Feb 2015 09:58:22 +0000
Subject: [PATCH 059/121] pinctrl-bcm2835: Only request the interrupts listed
in the DTB
Although the GPIO controller can generate three interrupts (four counting
the common one), the device tree files currently only specify two. In the
absence of the third, simply don't register that interrupt (as opposed to
registering 0), which has the effect of making it impossible to generate
interrupts for GPIOs 46-53 which, since they share pins with the SD card
interface, is unlikely to be a problem.
---
drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -1044,6 +1044,8 @@ static int bcm2835_pinctrl_probe(struct
int len;
char *name;
pc->irq[i] = irq_of_parse_and_map(np, i);
+ if (pc->irq[i] == 0)
+ break;
pc->irq_data[i].pc = pc;
pc->irq_data[i].irqgroup = i;

View File

@ -0,0 +1,34 @@
From 69c25727685034a06c041fee3938afba0b84e582 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 27 Feb 2015 15:10:24 +0000
Subject: [PATCH 060/121] enc28j60: Add device tree compatible string and an
overlay
---
drivers/net/ethernet/microchip/enc28j60.c | 11 +++++++++++
1 file changed, 11 insertions(+)
--- a/drivers/net/ethernet/microchip/enc28j60.c
+++ b/drivers/net/ethernet/microchip/enc28j60.c
@@ -1630,10 +1630,21 @@ static int enc28j60_remove(struct spi_de
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id enc28j60_of_match[] = {
+ { .compatible = "microchip,enc28j60", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, enc28j60_of_match);
+#endif
+
static struct spi_driver enc28j60_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = enc28j60_of_match,
+#endif
},
.probe = enc28j60_probe,
.remove = enc28j60_remove,

View File

@ -0,0 +1,210 @@
From 9ea362cfd9b8e0b2a8896a713b8b82c0c5834a68 Mon Sep 17 00:00:00 2001
From: Waldemar Brodkorb <wbrodkorb@conet.de>
Date: Wed, 25 Mar 2015 09:26:17 +0100
Subject: [PATCH 061/121] Add driver for rpi-proto
Forward port of 3.10.x driver from https://github.com/koalo
We are using a custom board and would like to use rpi 3.18.x
kernel. Patch works fine for our embedded system.
URL to the audio chip:
http://www.mikroe.com/add-on-boards/audio-voice/audio-codec-proto/
Playback tested with devicetree enabled.
Signed-off-by: Waldemar Brodkorb <wbrodkorb@conet.de>
---
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/rpi-proto.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+)
create mode 100644 sound/soc/bcm/rpi-proto.c
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -54,6 +54,13 @@ config SND_BCM2708_SOC_RPI_DAC
help
Say Y or M if you want to add support for RPi-DAC.
+config SND_BCM2708_SOC_RPI_PROTO
+ tristate "Support for Rpi-PROTO"
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
+ select SND_SOC_WM8731
+ help
+ Say Y or M if you want to add support for Audio Codec Board PROTO (WM8731).
+
config SND_BCM2708_SOC_IQAUDIO_DAC
tristate "Support for IQaudIO-DAC"
depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -14,6 +14,7 @@ snd-soc-hifiberry-dacplus-objs := hifibe
snd-soc-hifiberry-digi-objs := hifiberry_digi.o
snd-soc-hifiberry-amp-objs := hifiberry_amp.o
snd-soc-rpi-dac-objs := rpi-dac.o
+snd-soc-rpi-proto-objs := rpi-proto.o
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o
@@ -21,4 +22,5 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_D
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o
obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_AMP) += snd-soc-hifiberry-amp.o
obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o
+obj-$(CONFIG_SND_BCM2708_SOC_RPI_PROTO) += snd-soc-rpi-proto.o
obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o
--- /dev/null
+++ b/sound/soc/bcm/rpi-proto.c
@@ -0,0 +1,153 @@
+/*
+ * ASoC driver for PROTO AudioCODEC (with a WM8731)
+ * connected to a Raspberry Pi
+ *
+ * Author: Florian Meier, <koalo@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8731.h"
+
+static const unsigned int wm8731_rates_12288000[] = {
+ 8000, 32000, 48000, 96000,
+};
+
+static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = {
+ .list = wm8731_rates_12288000,
+ .count = ARRAY_SIZE(wm8731_rates_12288000),
+};
+
+static int snd_rpi_proto_startup(struct snd_pcm_substream *substream)
+{
+ /* Setup constraints, because there is a 12.288 MHz XTAL on the board */
+ snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &wm8731_constraints_12288000);
+ return 0;
+}
+
+static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int sysclk = 12288000; /* This is fixed on this board */
+
+ /* Set proto bclk */
+ int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2);
+ if (ret < 0){
+ dev_err(codec->dev,
+ "Failed to set BCLK ratio %d\n", ret);
+ return ret;
+ }
+
+ /* Set proto sysclk */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
+ sysclk, SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(codec->dev,
+ "Failed to set WM8731 SYSCLK: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_proto_ops = {
+ .startup = snd_rpi_proto_startup,
+ .hw_params = snd_rpi_proto_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_proto_dai[] = {
+{
+ .name = "WM8731",
+ .stream_name = "WM8731 HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "wm8731-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "wm8731.1-001a",
+ .dai_fmt = SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBM_CFM,
+ .ops = &snd_rpi_proto_ops,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_proto = {
+ .name = "snd_rpi_proto",
+ .dai_link = snd_rpi_proto_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_proto_dai),
+};
+
+static int snd_rpi_proto_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_proto.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_proto_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node,
+ "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
+ ret = snd_soc_register_card(&snd_rpi_proto);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "snd_soc_register_card() failed: %d\n", ret);
+ }
+
+ return ret;
+}
+
+
+static int snd_rpi_proto_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_proto);
+}
+
+static const struct of_device_id snd_rpi_proto_of_match[] = {
+ { .compatible = "rpi,rpi-proto", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_proto_of_match);
+
+static struct platform_driver snd_rpi_proto_driver = {
+ .driver = {
+ .name = "snd-rpi-proto",
+ .owner = THIS_MODULE,
+ .of_match_table = snd_rpi_proto_of_match,
+ },
+ .probe = snd_rpi_proto_probe,
+ .remove = snd_rpi_proto_remove,
+};
+
+module_platform_driver(snd_rpi_proto_driver);
+
+MODULE_AUTHOR("Florian Meier");
+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)");
+MODULE_LICENSE("GPL");

View File

@ -0,0 +1,73 @@
From db5f1ae7154cf08397ba74b67af282f246a17ddf Mon Sep 17 00:00:00 2001
From: Clive Messer <clive.m.messer@gmail.com>
Date: Thu, 2 Apr 2015 12:22:55 +0100
Subject: [PATCH 062/121] Add Device Tree support for RPi-DAC.
---
sound/soc/bcm/rpi-dac.c | 21 +++++++++++++++++++++
sound/soc/codecs/pcm1794a.c | 7 +++++++
2 files changed, 28 insertions(+)
--- a/sound/soc/bcm/rpi-dac.c
+++ b/sound/soc/bcm/rpi-dac.c
@@ -69,6 +69,20 @@ static int snd_rpi_rpi_dac_probe(struct
int ret = 0;
snd_rpi_rpi_dac.dev = &pdev->dev;
+
+ if (pdev->dev.of_node) {
+ struct device_node *i2s_node;
+ struct snd_soc_dai_link *dai = &snd_rpi_rpi_dac_dai[0];
+ i2s_node = of_parse_phandle(pdev->dev.of_node, "i2s-controller", 0);
+
+ if (i2s_node) {
+ dai->cpu_dai_name = NULL;
+ dai->cpu_of_node = i2s_node;
+ dai->platform_name = NULL;
+ dai->platform_of_node = i2s_node;
+ }
+ }
+
ret = snd_soc_register_card(&snd_rpi_rpi_dac);
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
@@ -81,10 +95,17 @@ static int snd_rpi_rpi_dac_remove(struct
return snd_soc_unregister_card(&snd_rpi_rpi_dac);
}
+static const struct of_device_id snd_rpi_rpi_dac_of_match[] = {
+ { .compatible = "rpi,rpi-dac", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_rpi_rpi_dac_of_match);
+
static struct platform_driver snd_rpi_rpi_dac_driver = {
.driver = {
.name = "snd-rpi-dac",
.owner = THIS_MODULE,
+ .of_match_table = snd_rpi_rpi_dac_of_match,
},
.probe = snd_rpi_rpi_dac_probe,
.remove = snd_rpi_rpi_dac_remove,
--- a/sound/soc/codecs/pcm1794a.c
+++ b/sound/soc/codecs/pcm1794a.c
@@ -46,12 +46,19 @@ static int pcm1794a_remove(struct platfo
return 0;
}
+static const struct of_device_id pcm1794a_of_match[] = {
+ { .compatible = "ti,pcm1794a", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, pcm1794a_of_match);
+
static struct platform_driver pcm1794a_codec_driver = {
.probe = pcm1794a_probe,
.remove = pcm1794a_remove,
.driver = {
.name = "pcm1794a-codec",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pcm1794a_of_match),
},
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
From 4fc03ec1bfe73a125775bb06937a246be639dc55 Mon Sep 17 00:00:00 2001
From: Steve Glendinning <steve.glendinning@smsc.com>
Date: Thu, 19 Feb 2015 18:47:12 +0000
Subject: [PATCH 064/121] smsx95xx: fix crimes against truesize
smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings.
This patch stops smsc95xx from changing truesize.
Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com>
---
drivers/net/usb/smsc95xx.c | 2 --
1 file changed, 2 deletions(-)
mode change 100644 => 100755 drivers/net/usb/smsc95xx.c
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1841,7 +1841,6 @@ static int smsc95xx_rx_fixup(struct usbn
if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(skb);
skb_trim(skb, skb->len - 4); /* remove fcs */
- skb->truesize = size + sizeof(struct sk_buff);
return 1;
}
@@ -1859,7 +1858,6 @@ static int smsc95xx_rx_fixup(struct usbn
if (dev->net->features & NETIF_F_RXCSUM)
smsc95xx_rx_csum_offload(ax_skb);
skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */
- ax_skb->truesize = size + sizeof(struct sk_buff);
usbnet_skb_return(dev, ax_skb);
}

View File

@ -0,0 +1,20 @@
From 9131a29e8e039bdc5055dad93d41f11a111a13b9 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 17 Apr 2015 16:58:45 +0100
Subject: [PATCH 065/121] smsc95xx: Disable turbo mode by default
---
drivers/net/usb/smsc95xx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -71,7 +71,7 @@ struct smsc95xx_priv {
u8 suspend_flags;
};
-static bool turbo_mode = true;
+static bool turbo_mode = false;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");

View File

@ -0,0 +1,75 @@
From 510eb2621d1b1b74618236a324538c19c9106ece Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 17 Apr 2015 19:30:22 +0100
Subject: [PATCH 066/121] Add blk_pos parameter to mmc multi_io_quirk callback
---
drivers/mmc/card/block.c | 1 +
drivers/mmc/host/omap_hsmmc.c | 4 +++-
drivers/mmc/host/sh_mobile_sdhi.c | 4 +++-
drivers/mmc/host/tmio_mmc_pio.c | 4 +++-
include/linux/mmc/host.h | 4 +++-
5 files changed, 13 insertions(+), 4 deletions(-)
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1413,6 +1413,7 @@ static void mmc_blk_rw_rq_prep(struct mm
brq->data.blocks = card->host->ops->multi_io_quirk(card,
(rq_data_dir(req) == READ) ?
MMC_DATA_READ : MMC_DATA_WRITE,
+ blk_rq_pos(req),
brq->data.blocks);
}
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -1749,7 +1749,9 @@ static void omap_hsmmc_conf_bus_power(st
}
static int omap_hsmmc_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
+ unsigned int direction,
+ u32 blk_pos,
+ int blk_size)
{
/* This controller can't do multiblock reads due to hw bugs */
if (direction == MMC_DATA_READ)
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -170,7 +170,9 @@ static int sh_mobile_sdhi_write16_hook(s
}
static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
+ unsigned int direction,
+ u32 blk_pos,
+ int blk_size)
{
/*
* In Renesas controllers, when performing a
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -1001,7 +1001,9 @@ static int tmio_mmc_get_ro(struct mmc_ho
}
static int tmio_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
+ unsigned int direction,
+ u32 blk_pos,
+ int blk_size)
{
struct tmio_mmc_host *host = mmc_priv(card->host);
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -140,7 +140,9 @@ struct mmc_host_ops {
* I/O. Returns the number of supported blocks for the request.
*/
int (*multi_io_quirk)(struct mmc_card *card,
- unsigned int direction, int blk_size);
+ unsigned int direction,
+ u32 blk_pos,
+ int blk_size);
};
struct mmc_card;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,39 @@
From 984698645ff73ed2100b4bfea99ed035139ac721 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Fri, 1 May 2015 23:00:15 +0200
Subject: [PATCH 068/121] BCM270x_DT: Add mailbox bcm2708-vcio
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Add bcm2708-vcio to Device Tree and don't add the
platform device when booting in DT mode.
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm2708/bcm2708.c | 2 +-
arch/arm/mach-bcm2709/bcm2709.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -870,7 +870,7 @@ void __init bcm2708_init(void)
bcm2708_dt_init();
bcm_register_device_dt(&bcm2708_dmaengine_device);
- bcm_register_device(&bcm2708_vcio_device);
+ bcm_register_device_dt(&bcm2708_vcio_device);
bcm_register_device_dt(&bcm2708_vchiq_device);
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -890,7 +890,7 @@ void __init bcm2709_init(void)
bcm2709_dt_init();
bcm_register_device_dt(&bcm2708_dmaengine_device);
- bcm_register_device(&bcm2708_vcio_device);
+ bcm_register_device_dt(&bcm2708_vcio_device);
bcm_register_device_dt(&bcm2708_vchiq_device);
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device_dt(&bcm2708_gpio_device);

View File

@ -0,0 +1,310 @@
From 156ce0fa550bbcb8e63eb60d11ac05cc28c14775 Mon Sep 17 00:00:00 2001
From: Gordon Hollingworth <gordon@raspberrypi.org>
Date: Tue, 12 May 2015 14:47:56 +0100
Subject: [PATCH 069/121] rpi-ft5406: Add touchscreen driver for pi LCD display
---
drivers/input/touchscreen/Kconfig | 7 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/rpi-ft5406.c | 258 ++++++++++++++++++++++++++
include/linux/platform_data/mailbox-bcm2708.h | 1 +
4 files changed, 267 insertions(+)
create mode 100644 drivers/input/touchscreen/rpi-ft5406.c
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -583,6 +583,13 @@ config TOUCHSCREEN_EDT_FT5X06
To compile this driver as a module, choose M here: the
module will be called edt-ft5x06.
+config TOUCHSCREEN_RPI_FT5406
+ tristate "Raspberry Pi FT5406 driver"
+ depends on ARCH_BCM2708 || ARCH_BCM2709
+ help
+ Say Y here to enable the Raspberry Pi memory based FT5406 device
+
+
config TOUCHSCREEN_MIGOR
tristate "Renesas MIGO-R touchscreen"
depends on SH_MIGOR && I2C
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da90
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
obj-$(CONFIG_TOUCHSCREEN_DYNAPRO) += dynapro.o
obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o
+obj-$(CONFIG_TOUCHSCREEN_RPI_FT5406) += rpi-ft5406.o
obj-$(CONFIG_TOUCHSCREEN_HAMPSHIRE) += hampshire.o
obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o
obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o
--- /dev/null
+++ b/drivers/input/touchscreen/rpi-ft5406.c
@@ -0,0 +1,258 @@
+/*
+ * Driver for memory based ft5406 touchscreen
+ *
+ * Copyright (C) 2015 Raspberry Pi
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/input/mt.h>
+#include <linux/kthread.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <linux/platform_data/mailbox-bcm2708.h>
+
+#define MAXIMUM_SUPPORTED_POINTS 10
+struct ft5406_regs {
+ uint8_t device_mode;
+ uint8_t gesture_id;
+ uint8_t num_points;
+ struct ft5406_touch {
+ uint8_t xh;
+ uint8_t xl;
+ uint8_t yh;
+ uint8_t yl;
+ uint8_t res1;
+ uint8_t res2;
+ } point[MAXIMUM_SUPPORTED_POINTS];
+};
+
+#define SCREEN_WIDTH 800
+#define SCREEN_HEIGHT 480
+
+struct ft5406 {
+ struct platform_device * pdev;
+ struct input_dev * input_dev;
+ void __iomem * ts_base;
+ struct ft5406_regs * regs;
+ struct task_struct * thread;
+};
+
+
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the message id */
+ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
+ uint32_t data_size; /* amount of data being sent or received */
+ uint32_t val; /* data buffer */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+/* Thread to poll for touchscreen events
+ *
+ * This thread polls the memory based register copy of the ft5406 registers
+ * using the number of points register to know whether the copy has been
+ * updated (we write 99 to the memory copy, the GPU will write between
+ * 0 - 10 points)
+ */
+static int ft5406_thread(void *arg)
+{
+ struct ft5406 *ts = (struct ft5406 *) arg;
+ struct ft5406_regs regs;
+ int known_ids = 0;
+
+ while(!kthread_should_stop())
+ {
+ // 60fps polling
+ msleep(17);
+ memcpy_fromio(&regs, ts->regs, sizeof(*ts->regs));
+ writel(99, &ts->regs->num_points);
+ // Do not output if theres no new information (num_points is 99)
+ // or we have no touch points and don't need to release any
+ if(!(regs.num_points == 99 || (regs.num_points == 0 && known_ids == 0)))
+ {
+ int i;
+ int modified_ids = 0, released_ids;
+ for(i = 0; i < regs.num_points; i++)
+ {
+ int x = (((int) regs.point[i].xh & 0xf) << 8) + regs.point[i].xl;
+ int y = (((int) regs.point[i].yh & 0xf) << 8) + regs.point[i].yl;
+ int touchid = (regs.point[i].yh >> 4) & 0xf;
+
+ modified_ids |= 1 << touchid;
+
+ if(!((1 << touchid) & known_ids))
+ dev_dbg(&ts->pdev->dev, "x = %d, y = %d, touchid = %d\n", x, y, touchid);
+
+ input_mt_slot(ts->input_dev, touchid);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
+
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+
+ }
+
+ released_ids = known_ids & ~modified_ids;
+ for(i = 0; released_ids && i < MAXIMUM_SUPPORTED_POINTS; i++)
+ {
+ if(released_ids & (1<<i))
+ {
+ dev_dbg(&ts->pdev->dev, "Released %d, known = %x modified = %x\n", i, known_ids, modified_ids);
+ input_mt_slot(ts->input_dev, i);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+ modified_ids &= ~(1 << i);
+ }
+ }
+ known_ids = modified_ids;
+
+ input_mt_report_pointer_emulation(ts->input_dev, true);
+ input_sync(ts->input_dev);
+ }
+
+ }
+
+ return 0;
+}
+
+static int ft5406_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct input_dev * input_dev = input_allocate_device();
+ struct vc_msg request;
+ struct ft5406 * ts;
+
+ dev_info(&pdev->dev, "Probing device\n");
+
+ ts = kzalloc(sizeof(struct ft5406), GFP_KERNEL);
+
+ if (!ts || !input_dev) {
+ ret = -ENOMEM;
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ return ret;
+ }
+ ts->input_dev = input_dev;
+ platform_set_drvdata(pdev, ts);
+ ts->pdev = pdev;
+
+ input_dev->name = "FT5406 memory based driver";
+
+ __set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(EV_SYN, input_dev->evbit);
+ __set_bit(EV_ABS, input_dev->evbit);
+
+ input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
+ SCREEN_WIDTH, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
+ SCREEN_HEIGHT, 0, 0);
+
+ input_mt_init_slots(input_dev, MAXIMUM_SUPPORTED_POINTS, INPUT_MT_DIRECT);
+
+ input_set_drvdata(input_dev, ts);
+
+ ret = input_register_device(input_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "could not register input device, %d\n",
+ ret);
+ return ret;
+ }
+
+ memset(&request, 0, sizeof request);
+
+ request.msg_size = sizeof request;
+ request.request_code = VCMSG_PROCESS_REQUEST;
+ request.tag.tag_id = VCMSG_GET_TOUCHBUF;
+ request.tag.buffer_size = 4;
+ request.tag.data_size = 4;
+
+ bcm_mailbox_property(&request, sizeof(request));
+
+ if(request.request_code == VCMSG_REQUEST_SUCCESSFUL)
+ {
+ dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", request.tag.val);
+ }
+ else
+ {
+ input_unregister_device(input_dev);
+ kzfree(ts);
+ return -1;
+ }
+
+ // mmap the physical memory
+ request.tag.val &= ~0xc0000000;
+ ts->ts_base = ioremap(request.tag.val, sizeof(*ts->regs));
+ if(ts->ts_base == NULL)
+ {
+ dev_err(&pdev->dev, "Failed to map physical address\n");
+ input_unregister_device(input_dev);
+ kzfree(ts);
+ return -1;
+ }
+
+ ts->regs = (struct ft5406_regs *) ts->ts_base;
+
+ // create thread to poll the touch events
+ ts->thread = kthread_run(ft5406_thread, ts, "ft5406");
+ if(ts->thread == NULL)
+ {
+ dev_err(&pdev->dev, "Failed to create kernel thread");
+ iounmap(ts->ts_base);
+ input_unregister_device(input_dev);
+ kzfree(ts);
+ }
+
+ return 0;
+}
+
+static int ft5406_remove(struct platform_device *pdev)
+{
+ struct ft5406 *ts = (struct ft5406 *) platform_get_drvdata(pdev);
+
+ dev_info(&pdev->dev, "Removing rpi-ft5406\n");
+
+ kthread_stop(ts->thread);
+ iounmap(ts->ts_base);
+ input_unregister_device(ts->input_dev);
+ kzfree(ts);
+
+ return 0;
+}
+
+static const struct of_device_id ft5406_match[] = {
+ { .compatible = "rpi,rpi-ft5406", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ft5406_match);
+
+static struct platform_driver ft5406_driver = {
+ .driver = {
+ .name = "rpi-ft5406",
+ .owner = THIS_MODULE,
+ .of_match_table = ft5406_match,
+ },
+ .probe = ft5406_probe,
+ .remove = ft5406_remove,
+};
+
+module_platform_driver(ft5406_driver);
+
+MODULE_AUTHOR("Gordon Hollingworth");
+MODULE_DESCRIPTION("Touchscreen driver for memory based FT5406");
+MODULE_LICENSE("GPL");
--- a/include/linux/platform_data/mailbox-bcm2708.h
+++ b/include/linux/platform_data/mailbox-bcm2708.h
@@ -115,6 +115,7 @@ enum {
VCMSG_SET_TRANSFORM = 0x0004800d,
VCMSG_TST_VSYNC = 0x0004400e,
VCMSG_SET_VSYNC = 0x0004800e,
+ VCMSG_GET_TOUCHBUF = 0x0004000f,
VCMSG_SET_CURSOR_INFO = 0x00008010,
VCMSG_SET_CURSOR_STATE = 0x00008011,
};

View File

@ -0,0 +1,52 @@
From 92f76fcdda43617a0f3461741bba9e6d328684da Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 27 May 2015 17:22:15 +0100
Subject: [PATCH 071/121] bcm2835-audio: Create the platform device if the DT
node is disabled
For backwards compatibility, allow the built-in ALSA driver to be enabled
either by loading the module from /etc/modules or by enabling the "/audio"
node in DT.
---
arch/arm/mach-bcm2708/bcm2708.c | 10 ++++++++--
arch/arm/mach-bcm2709/bcm2709.c | 10 ++++++++--
2 files changed, 16 insertions(+), 4 deletions(-)
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -898,8 +898,14 @@ void __init bcm2708_init(void)
#endif
bcm2708_init_led();
bcm2708_init_uart1();
- for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
- bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+
+ /* Only create the platform devices for the ALSA driver in the
+ absence of an enabled "audio" DT node */
+ if (!use_dt ||
+ !of_device_is_available(of_find_node_by_path("/audio"))) {
+ for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
+ bcm_register_device(&bcm2708_alsa_devices[i]);
+ }
bcm_register_device_dt(&bcm2708_spi_device);
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -918,8 +918,14 @@ void __init bcm2709_init(void)
#endif
bcm2709_init_led();
bcm2709_init_uart1();
- for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
- bcm_register_device_dt(&bcm2708_alsa_devices[i]);
+
+ /* Only create the platform devices for the ALSA driver in the
+ absence of an enabled "audio" DT node */
+ if (!use_dt ||
+ !of_device_is_available(of_find_node_by_path("/audio"))) {
+ for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
+ bcm_register_device(&bcm2708_alsa_devices[i]);
+ }
bcm_register_device_dt(&bcm2708_spi_device);

View File

@ -0,0 +1,59 @@
From e64ab6c66db34627b7765099e815a8c2d4957296 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
Date: Wed, 3 Jun 2015 12:26:13 +0200
Subject: [PATCH 072/121] ARM: bcm2835: Set Serial number and Revision
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The VideoCore bootloader passes in Serial number and
Revision number through Device Tree. Make these available to
userspace through /proc/cpuinfo.
Mainline status:
There is a commit in linux-next that standardize passing the serial
number through Device Tree (string: /serial-number):
ARM: 8355/1: arch: Show the serial number from devicetree in cpuinfo
There was an attempt to do the same with the revision number, but it
didn't get in:
[PATCH v2 1/2] arm: devtree: Set system_rev from DT revision
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
---
arch/arm/mach-bcm/board_bcm2835.c | 9 +++++++++
1 file changed, 9 insertions(+)
--- a/arch/arm/mach-bcm/board_bcm2835.c
+++ b/arch/arm/mach-bcm/board_bcm2835.c
@@ -18,6 +18,7 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/clk/bcm2835.h>
+#include <asm/system_info.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -107,6 +108,9 @@ static void __init bcm2835_map_io(void)
static void __init bcm2835_init(void)
{
+ struct device_node *np = of_find_node_by_path("/system");
+ u32 val;
+ u64 val64;
int ret;
bcm2835_setup_restart();
@@ -121,6 +125,11 @@ static void __init bcm2835_init(void)
pr_err("of_platform_populate failed: %d\n", ret);
BUG();
}
+
+ if (!of_property_read_u32(np, "linux,revision", &val))
+ system_rev = val;
+ if (!of_property_read_u64(np, "linux,serial", &val64))
+ system_serial_low = val64;
}
static const char * const bcm2835_compat[] = {

View File

@ -0,0 +1,69 @@
From 8a609b1977da490cd177740e61169444383fd8c4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 16 Jun 2015 17:47:27 +0100
Subject: [PATCH 073/121] platform: Add force_core command line setting to boot
from a different core number
---
arch/arm/mach-bcm2709/armctrl.c | 17 ++++++++++++++++-
arch/arm/mach-bcm2709/bcm2709.c | 2 ++
2 files changed, 18 insertions(+), 1 deletion(-)
--- a/arch/arm/mach-bcm2709/armctrl.c
+++ b/arch/arm/mach-bcm2709/armctrl.c
@@ -45,6 +45,8 @@ static unsigned int remap_irqs[(INTERRUP
INTERRUPT_VC_ARASANSDIO
};
+extern unsigned force_core;
+
static void armctrl_mask_irq(struct irq_data *d)
{
static const unsigned int disables[4] = {
@@ -92,7 +94,13 @@ static void armctrl_unmask_irq(struct ir
int i;
if (d->irq >= FIQ_START) {
unsigned int data;
- if (num_online_cpus() > 1) {
+ if (force_core) {
+ data = readl(__io_address(ARM_LOCAL_GPU_INT_ROUTING));
+ data &= ~0xc;
+ data |= ((force_core-1) << 2);
+ writel(data, __io_address(ARM_LOCAL_GPU_INT_ROUTING));
+ }
+ else if (num_online_cpus() > 1) {
data = readl(__io_address(ARM_LOCAL_GPU_INT_ROUTING));
data &= ~0xc;
data |= (1 << 2);
@@ -119,6 +127,13 @@ static void armctrl_unmask_irq(struct ir
}
#endif
} else if (d->irq >= ARM_IRQ1_BASE && d->irq < ARM_IRQ_LOCAL_BASE) {
+ if (force_core) {
+ unsigned int data;
+ data = readl(__io_address(ARM_LOCAL_GPU_INT_ROUTING));
+ data &= ~0x3;
+ data |= ((force_core-1) << 0);
+ writel(data, __io_address(ARM_LOCAL_GPU_INT_ROUTING));
+ }
unsigned int data = (unsigned int)irq_get_chip_data(d->irq);
writel(1 << (data & 0x1f), __io_address(enables[(data >> 5) & 0x3]));
} else if (d->irq == INTERRUPT_ARM_LOCAL_PMU_FAST) {
--- a/arch/arm/mach-bcm2709/bcm2709.c
+++ b/arch/arm/mach-bcm2709/bcm2709.c
@@ -96,6 +96,7 @@ static unsigned w1_gpio_pin = W1_GPIO;
static unsigned w1_gpio_pullup = W1_PULLUP;
static bool vc_i2c_override = false;
static int pps_gpio_pin = -1;
+unsigned force_core;
static unsigned use_dt = 0;
@@ -1305,6 +1306,7 @@ MACHINE_START(BCM2708, "BCM2709")
.dt_compat = bcm2709_compat,
MACHINE_END
+module_param(force_core, uint, 0644);
module_param(boardrev, uint, 0644);
module_param(serial, uint, 0644);
module_param(uart_clock, uint, 0644);

View File

@ -0,0 +1,19 @@
From 2efab5a48bc519a3901b62da297ee5523c91ee58 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 18 Jun 2015 17:46:17 +0100
Subject: [PATCH 074/121] mach-bcm270x: Enable the building of pinctrl-bcm2835
---
drivers/pinctrl/Makefile | 1 +
1 file changed, 1 insertion(+)
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-t
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
+obj-$(CONFIG_ARCH_BCM2708)$(CONFIG_ARCH_BCM2709) += bcm/
obj-$(CONFIG_ARCH_BCM) += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-y += freescale/

View File

@ -0,0 +1,24 @@
From 436bd2ba164863768b90c2456a943dcfed3b053c Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 19 Jun 2015 16:41:39 +0100
Subject: [PATCH 075/121] BCM270X_DT: Document the i2s-mmap overlay
---
arch/arm/boot/dts/overlays/README | 6 ++++++
1 file changed, 6 insertions(+)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -260,6 +260,12 @@ Params: ds1307 Select
pcf8563 Select the PCF8563 device
+Name: i2s-mmap
+Info: Enables mmap support in the bcm2708-i2s driver
+Load: dtoverlay=i2s-mmap
+Params: <None>
+
+
Name: iqaudio-dac
Info: Configures the IQaudio DAC audio card
Load: dtoverlay=iqaudio-dac

View File

@ -0,0 +1,426 @@
From 48297e4045a1d8a3b2a0edbe6cf371a34c5eb3be Mon Sep 17 00:00:00 2001
From: Eric Anholt <eric@anholt.net>
Date: Thu, 4 Jun 2015 13:11:46 -0700
Subject: [PATCH 077/121] ARM: bcm2835: Add the Raspberry Pi firmware driver
This gives us a function for making mailbox property channel requests
of the firmware, which is most notable in that it will let us get and
set clock rates.
Signed-off-by: Eric Anholt <eric@anholt.net>
---
drivers/firmware/Kconfig | 7 +
drivers/firmware/Makefile | 1 +
drivers/firmware/raspberrypi.c | 260 +++++++++++++++++++++++++++++
include/soc/bcm2835/raspberrypi-firmware.h | 115 +++++++++++++
4 files changed, 383 insertions(+)
create mode 100644 drivers/firmware/raspberrypi.c
create mode 100644 include/soc/bcm2835/raspberrypi-firmware.h
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -136,6 +136,13 @@ config QCOM_SCM
bool
depends on ARM || ARM64
+config RASPBERRYPI_FIRMWARE
+ tristate "Raspberry Pi Firmware Driver"
+ depends on BCM2835_MBOX
+ help
+ This option enables support for communicating with the firmware on the
+ Raspberry Pi.
+
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-$(CONFIG_EFI) += efi/
--- /dev/null
+++ b/drivers/firmware/raspberrypi.c
@@ -0,0 +1,260 @@
+/*
+ * Defines interfaces for interacting wtih the Raspberry Pi firmware's
+ * property channel.
+ *
+ * Copyright © 2015 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
+#define MBOX_CHAN(msg) ((msg) & 0xf)
+#define MBOX_DATA28(msg) ((msg) & ~0xf)
+#define MBOX_CHAN_PROPERTY 8
+
+struct rpi_firmware {
+ struct mbox_client cl;
+ struct mbox_chan *chan; /* The property channel. */
+ struct completion c;
+ u32 enabled;
+};
+
+static DEFINE_MUTEX(transaction_lock);
+
+static void response_callback(struct mbox_client *cl, void *msg)
+{
+ struct rpi_firmware *fw = container_of(cl, struct rpi_firmware, cl);
+ complete(&fw->c);
+}
+
+/*
+ * Sends a request to the firmware through the BCM2835 mailbox driver,
+ * and synchronously waits for the reply.
+ */
+static int
+rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
+{
+ u32 message = MBOX_MSG(chan, data);
+ int ret;
+
+ WARN_ON(data & 0xf);
+
+ mutex_lock(&transaction_lock);
+ reinit_completion(&fw->c);
+ ret = mbox_send_message(fw->chan, &message);
+ if (ret >= 0) {
+ wait_for_completion(&fw->c);
+ ret = 0;
+ } else {
+ dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
+ }
+ mutex_unlock(&transaction_lock);
+
+ return ret;
+}
+
+/**
+ * rpi_firmware_property_list - Submit firmware property list
+ * @fw: Pointer to firmware structure from rpi_firmware_get().
+ * @data: Buffer holding tags.
+ * @tag_size: Size of tags buffer.
+ *
+ * Submits a set of concatenated tags to the VPU firmware through the
+ * mailbox property interface.
+ *
+ * The buffer header and the ending tag are added by this function and
+ * don't need to be supplied, just the actual tags for your operation.
+ * See struct rpi_firmware_property_tag_header for the per-tag
+ * structure.
+ */
+int rpi_firmware_property_list(struct rpi_firmware *fw,
+ void *data, size_t tag_size)
+{
+ size_t size = tag_size + 12;
+ u32 *buf;
+ dma_addr_t bus_addr;
+ int ret;
+
+ /* Packets are processed a dword at a time. */
+ if (size & 3)
+ return -EINVAL;
+
+ buf = dma_alloc_coherent(fw->cl.dev, PAGE_ALIGN(size), &bus_addr,
+ GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ /* The firmware will error out without parsing in this case. */
+ WARN_ON(size >= 1024 * 1024);
+
+ buf[0] = size;
+ buf[1] = RPI_FIRMWARE_STATUS_REQUEST;
+ memcpy(&buf[2], data, tag_size);
+ buf[size / 4 - 1] = RPI_FIRMWARE_PROPERTY_END;
+ wmb();
+
+ ret = rpi_firmware_transaction(fw, MBOX_CHAN_PROPERTY, bus_addr);
+
+ rmb();
+ memcpy(data, &buf[2], tag_size);
+ if (ret == 0 && buf[1] != RPI_FIRMWARE_STATUS_SUCCESS) {
+ /*
+ * The tag name here might not be the one causing the
+ * error, if there were multiple tags in the request.
+ * But single-tag is the most common, so go with it.
+ */
+ dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n",
+ buf[2], buf[1]);
+ ret = -EINVAL;
+ }
+
+ dma_free_coherent(fw->cl.dev, PAGE_ALIGN(size), buf, bus_addr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_property_list);
+
+/**
+ * rpi_firmware_property - Submit single firmware property
+ * @fw: Pointer to firmware structure from rpi_firmware_get().
+ * @tag: One of enum_mbox_property_tag.
+ * @tag_data: Tag data buffer.
+ * @buf_size: Buffer size.
+ *
+ * Submits a single tag to the VPU firmware through the mailbox
+ * property interface.
+ *
+ * This is a convenience wrapper around
+ * rpi_firmware_property_list() to avoid some of the
+ * boilerplate in property calls.
+ */
+int rpi_firmware_property(struct rpi_firmware *fw,
+ u32 tag, void *tag_data, size_t buf_size)
+{
+ /* Single tags are very small (generally 8 bytes), so the
+ * stack should be safe.
+ */
+ u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)];
+ struct rpi_firmware_property_tag_header *header =
+ (struct rpi_firmware_property_tag_header *)data;
+ int ret;
+
+ header->tag = tag;
+ header->buf_size = buf_size;
+ header->req_resp_size = 0;
+ memcpy(data + sizeof(struct rpi_firmware_property_tag_header),
+ tag_data, buf_size);
+
+ ret = rpi_firmware_property_list(fw, &data, sizeof(data));
+ memcpy(tag_data,
+ data + sizeof(struct rpi_firmware_property_tag_header),
+ buf_size);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_property);
+
+static void
+rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
+{
+ u32 packet;
+ int ret = rpi_firmware_property(fw,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION,
+ &packet, sizeof(packet));
+
+ if (ret == 0) {
+ struct tm tm;
+
+ time_to_tm(packet, 0, &tm);
+
+ dev_info(fw->cl.dev,
+ "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min);
+ }
+}
+
+static int rpi_firmware_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *fw;
+
+ fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
+
+ fw->cl.dev = dev;
+ fw->cl.rx_callback = response_callback;
+ fw->cl.tx_block = true;
+
+ fw->chan = mbox_request_channel(&fw->cl, 0);
+ if (IS_ERR(fw->chan)) {
+ int ret = PTR_ERR(fw->chan);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get mbox channel: %d\n", ret);
+ return ret;
+ }
+
+ init_completion(&fw->c);
+
+ platform_set_drvdata(pdev, fw);
+
+ rpi_firmware_print_firmware_revision(fw);
+
+ return 0;
+}
+
+static int rpi_firmware_remove(struct platform_device *pdev)
+{
+ struct rpi_firmware *fw = platform_get_drvdata(pdev);
+
+ mbox_free_channel(fw->chan);
+
+ return 0;
+}
+
+/**
+ * rpi_firmware_get - Get pointer to rpi_firmware structure.
+ * @firmware_node: Pointer to the firmware Device Tree node.
+ *
+ * Returns NULL is the firmware device is not ready.
+ */
+struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
+{
+ struct platform_device *pdev = of_find_device_by_node(firmware_node);
+
+ if (!pdev)
+ return NULL;
+
+ return platform_get_drvdata(pdev);
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_get);
+
+static const struct of_device_id rpi_firmware_of_match[] = {
+ { .compatible = "raspberrypi,bcm2835-firmware", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_firmware_of_match);
+
+static struct platform_driver rpi_firmware_driver = {
+ .driver = {
+ .name = "raspberrypi-firmware",
+ .of_match_table = rpi_firmware_of_match,
+ },
+ .probe = rpi_firmware_probe,
+ .remove = rpi_firmware_remove,
+};
+module_platform_driver(rpi_firmware_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("Raspberry Pi firmware driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2015 Broadcom
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/of_device.h>
+
+struct rpi_firmware;
+
+enum rpi_firmware_property_status {
+ RPI_FIRMWARE_STATUS_REQUEST = 0,
+ RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000,
+ RPI_FIRMWARE_STATUS_ERROR = 0x80000001,
+};
+
+/**
+ * struct rpi_firmware_property_tag_header - Firmware property tag header
+ * @tag: One of enum_mbox_property_tag.
+ * @buf_size: The number of bytes in the value buffer following this
+ * struct.
+ * @req_resp_size: On submit, the length of the request (though it doesn't
+ * appear to be currently used by the firmware). On return,
+ * the length of the response (always 4 byte aligned), with
+ * the low bit set.
+ */
+struct rpi_firmware_property_tag_header {
+ u32 tag;
+ u32 buf_size;
+ u32 req_resp_size;
+};
+
+enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_PROPERTY_END = 0,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
+
+ RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
+ RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
+
+ RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001,
+ RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002,
+ RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003,
+ RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004,
+ RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005,
+ RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006,
+ RPI_FIRMWARE_GET_CLOCKS = 0x00010007,
+ RPI_FIRMWARE_GET_POWER_STATE = 0x00020001,
+ RPI_FIRMWARE_GET_TIMING = 0x00020002,
+ RPI_FIRMWARE_SET_POWER_STATE = 0x00028001,
+ RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001,
+ RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002,
+ RPI_FIRMWARE_GET_VOLTAGE = 0x00030003,
+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004,
+ RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005,
+ RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006,
+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007,
+ RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
+ RPI_FIRMWARE_GET_TURBO = 0x00030009,
+ RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
+ RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
+ RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
+ RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
+ RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f,
+ RPI_FIRMWARE_EXECUTE_CODE = 0x00030010,
+ RPI_FIRMWARE_EXECUTE_QPU = 0x00030011,
+ RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
+ RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
+ RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
+ RPI_FIRMWARE_SET_TURBO = 0x00038009,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
+ RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+};
+
+int rpi_firmware_property(struct rpi_firmware *fw,
+ u32 tag, void *data, size_t len);
+int rpi_firmware_property_list(struct rpi_firmware *fw,
+ void *data, size_t tag_size);
+struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node);

View File

@ -0,0 +1,50 @@
From 9762ae8cc9ebb55739cb553f3b2c5bc604aec9e4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sun, 22 Mar 2015 13:33:23 +0000
Subject: [PATCH 078/121] config: Enable ZSMALLOC, ZRAM and PGTABLE_MAPPING
---
arch/arm/configs/bcm2709_defconfig | 4 ++++
arch/arm/configs/bcmrpi_defconfig | 4 ++++
2 files changed, 8 insertions(+)
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -49,6 +49,8 @@ CONFIG_OABI_COMPAT=y
CONFIG_CLEANCACHE=y
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
+CONFIG_ZSMALLOC=m
+CONFIG_PGTABLE_MAPPING=y
CONFIG_UACCESS_WITH_MEMCPY=y
CONFIG_SECCOMP=y
CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -389,6 +391,8 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_ZRAM=m
+CONFIG_ZRAM_LZ4_COMPRESS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -44,6 +44,8 @@ CONFIG_OABI_COMPAT=y
CONFIG_CLEANCACHE=y
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
+CONFIG_ZSMALLOC=m
+CONFIG_PGTABLE_MAPPING=y
CONFIG_UACCESS_WITH_MEMCPY=y
CONFIG_SECCOMP=y
CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -382,6 +384,8 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=5
+CONFIG_ZRAM=m
+CONFIG_ZRAM_LZ4_COMPRESS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_DRBD=m

View File

@ -0,0 +1,78 @@
From dd888666ae9c4f80521f3bbe48edb86b423bb6f6 Mon Sep 17 00:00:00 2001
From: Gordon Hollingworth <gordon@fiveninjas.com>
Date: Mon, 22 Jun 2015 16:27:07 +0100
Subject: [PATCH 079/121] Add rpi-ft5406 overlay Add rpi-ft5406 driver as
module
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 5 +++++
arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts | 16 ++++++++++++++++
arch/arm/configs/bcm2709_defconfig | 1 +
arch/arm/configs/bcmrpi_defconfig | 1 +
5 files changed, 24 insertions(+)
create mode 100644 arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -35,6 +35,7 @@ dtb-$(RPI_DT_OVERLAYS) += pitft28-resist
dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += rpi-dac-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += rpi-display-overlay.dtb
+dtb-$(RPI_DT_OVERLAYS) += rpi-ft5406-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += rpi-proto-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += spi-bcm2708-overlay.dtb
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -396,6 +396,11 @@ Params: speed Display
xohms Touchpanel sensitivity (X-plate resistance)
+Name: rpi-ft5406
+Info: Official Raspberry Pi display touchscreen
+Load: dtoverlay=rpi-ft5406
+Params: <None>
+
Name: rpi-proto
Info: Configures the RPi Proto audio card
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/rpi-ft5406-overlay.dts
@@ -0,0 +1,16 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+ target-path = "/";
+ __overlay__ {
+ rpi_ft5406: rpi_ft5406 {
+ compatible = "rpi,rpi-ft5406";
+ status = "okay";
+ };
+ };
+ };
+};
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -535,6 +535,7 @@ CONFIG_JOYSTICK_XPAD_FF=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_RPI_FT5406=m
CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
CONFIG_TOUCHSCREEN_STMPE=m
CONFIG_INPUT_MISC=y
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -528,6 +528,7 @@ CONFIG_JOYSTICK_XPAD_FF=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
CONFIG_TOUCHSCREEN_EGALAX=m
+CONFIG_TOUCHSCREEN_RPI_FT5406=m
CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
CONFIG_TOUCHSCREEN_STMPE=m
CONFIG_INPUT_MISC=y

View File

@ -0,0 +1,21 @@
From afae7dff11e5ee1d5aaf0d00cf26ea3cf24db2d8 Mon Sep 17 00:00:00 2001
From: Gordon Hollingworth <gordon@fiveninjas.com>
Date: Tue, 23 Jun 2015 09:53:40 +0100
Subject: [PATCH 080/121] Fix driver detection failure Check that the buffer
response is non-zero meaning the touchscreen was detected
---
drivers/input/touchscreen/rpi-ft5406.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/input/touchscreen/rpi-ft5406.c
+++ b/drivers/input/touchscreen/rpi-ft5406.c
@@ -184,7 +184,7 @@ static int ft5406_probe(struct platform_
bcm_mailbox_property(&request, sizeof(request));
- if(request.request_code == VCMSG_REQUEST_SUCCESSFUL)
+ if(request.request_code == VCMSG_REQUEST_SUCCESSFUL && request.tag.val != 0)
{
dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", request.tag.val);
}

View File

@ -0,0 +1,46 @@
From 9e053b2e623361aa3a3bbfa298e7b8d33adf7abc Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 23 Jun 2015 13:24:01 +0100
Subject: [PATCH 081/121] config: Enable 8250 serial port
---
arch/arm/configs/bcm2709_defconfig | 7 +++++++
arch/arm/configs/bcmrpi_defconfig | 7 +++++++
2 files changed, 14 insertions(+)
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -557,8 +557,15 @@ CONFIG_GAMEPORT_L4=m
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_TTY_PRINTK=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_BCM2835=m
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -550,8 +550,15 @@ CONFIG_GAMEPORT_L4=m
CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=1
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_TTY_PRINTK=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_BCM2835=m

View File

@ -0,0 +1,32 @@
From 60300e1082cd46b3ae2732854776ee549e217387 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 23 Jun 2015 14:10:58 +0100
Subject: [PATCH 082/121] config: Enable POWER_RESET_GPIO
---
arch/arm/configs/bcm2709_defconfig | 2 ++
arch/arm/configs/bcmrpi_defconfig | 2 ++
2 files changed, 4 insertions(+)
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -606,6 +606,8 @@ CONFIG_W1_SLAVE_DS2781=m
CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_BQ27000=m
CONFIG_BATTERY_DS2760=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
# CONFIG_HWMON is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_BCM2835=y
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -599,6 +599,8 @@ CONFIG_W1_SLAVE_DS2781=m
CONFIG_W1_SLAVE_DS28E04=m
CONFIG_W1_SLAVE_BQ27000=m
CONFIG_BATTERY_DS2760=m
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
# CONFIG_HWMON is not set
CONFIG_THERMAL=y
CONFIG_THERMAL_BCM2835=y

View File

@ -0,0 +1,45 @@
From 79796a03fa8311ea9030817db27690f24f72214c Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 26 Jun 2015 17:37:38 +0100
Subject: [PATCH 083/121] bcm2708-vcio: Remove restriction of only a single
instance being open
We need more than one process to be able to use mailbox interface (e.g. HW cursor in fbturbo and hello_fft).
Locking should be handled on each mailbox access
---
drivers/mailbox/bcm2708-vcio.c | 14 --------------
1 file changed, 14 deletions(-)
--- a/drivers/mailbox/bcm2708-vcio.c
+++ b/drivers/mailbox/bcm2708-vcio.c
@@ -242,20 +242,9 @@ EXPORT_SYMBOL_GPL(bcm_mailbox_property);
/* Platform Device for Mailbox */
-/*
- * Is the device open right now? Used to prevent
- * concurent access into the same device
- */
-static bool device_is_open;
-
/* This is called whenever a process attempts to open the device file */
static int device_open(struct inode *inode, struct file *file)
{
- /* We don't want to talk to two processes at the same time */
- if (device_is_open)
- return -EBUSY;
-
- device_is_open = true;
try_module_get(THIS_MODULE);
return 0;
@@ -263,9 +252,6 @@ static int device_open(struct inode *ino
static int device_release(struct inode *inode, struct file *file)
{
- /* We're now ready for our next caller */
- device_is_open = false;
-
module_put(THIS_MODULE);
return 0;

View File

@ -0,0 +1,141 @@
From 6bda1bf0de21592f772c2d65b3e66ddf89d50bdf Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 26 Jun 2015 08:39:19 +0100
Subject: [PATCH 084/121] BCM270X_DT: Create a "core" clock, use it for SPI and
sdhost
---
arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 +
arch/arm/boot/dts/bcm2708_common.dtsi | 6 +++---
arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
arch/arm/boot/dts/overlays/sdhost-overlay.dts | 28 ++-------------------------
6 files changed, 9 insertions(+), 29 deletions(-)
--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
@@ -124,6 +124,7 @@
i2c1 = <&i2c1>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
act_led_activelow = <&act_led>,"gpios:8";
--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
@@ -118,6 +118,7 @@
i2c1 = <&i2c1>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
act_led_activelow = <&act_led>,"gpios:8";
--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
@@ -14,5 +14,6 @@
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ core_freq = <&clk_core>,"clock-frequency:0";
};
};
--- a/arch/arm/boot/dts/bcm2708_common.dtsi
+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
@@ -110,7 +110,7 @@
compatible = "brcm,bcm2835-spi";
reg = <0x7e204000 0x1000>;
interrupts = <2 22>;
- clocks = <&clk_spi>;
+ clocks = <&clk_core>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -203,11 +203,11 @@
clock-frequency = <250000000>;
};
- clk_spi: clock@2 {
+ clk_core: clock@2 {
compatible = "fixed-clock";
reg = <2>;
#clock-cells = <0>;
- clock-output-names = "spi";
+ clock-output-names = "core";
clock-frequency = <250000000>;
};
--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
@@ -124,6 +124,7 @@
i2c1 = <&i2c1>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
act_led_activelow = <&act_led>,"gpios:8";
--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
@@ -16,7 +16,7 @@
pinctrl-names = "default";
pinctrl-0 = <&sdhost_pins>;
interrupts = <2 24>;
- clocks = <&clk_sdhost>;
+ clocks = <&clk_core>;
dmas = <&dma 13>,
<&dma 13>;
dma-names = "tx", "rx";
@@ -29,22 +29,6 @@
};
fragment@1 {
- target = <&clocks>;
- __overlay__ {
- #address-cells = <1>;
- #size-cells = <0>;
-
- clk_sdhost: sdhost {
- compatible = "fixed-clock";
- reg = <0>;
- #clock-cells = <0>;
- clock-output-names = "sdhost";
- clock-frequency = <250000000>;
- };
- };
- };
-
- fragment@2 {
target = <&gpio>;
__overlay__ {
sdhost_pins: sdhost_pins {
@@ -54,7 +38,7 @@
};
};
- fragment@3 {
+ fragment@2 {
target = <&mmc>;
__overlay__ {
/* Find a way to disable the other driver */
@@ -63,18 +47,10 @@
};
};
- fragment@4 {
- target-path = "/__overrides__";
- __overlay__ {
- sdhost_freq = <&clk_sdhost>,"clock-frequency:0";
- };
- };
-
__overrides__ {
overclock_50 = <&sdhost>,"brcm,overclock-50:0";
force_pio = <&sdhost>,"brcm,force-pio?";
pio_limit = <&sdhost>,"brcm,pio-limit:0";
debug = <&sdhost>,"brcm,debug?";
- sdhost_freq = <&clk_sdhost>,"clock-frequency:0";
};
};

View File

@ -0,0 +1,51 @@
From d4a0abb7a644365a9f21204a5e3f530a8112d5e8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 24 Jun 2015 09:24:31 +0100
Subject: [PATCH 085/121] BCM270X_DT: Add MCP7941X to i2c-rtc overlay
---
arch/arm/boot/dts/overlays/README | 3 +++
arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts | 6 ++++++
2 files changed, 9 insertions(+)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -253,6 +253,8 @@ Params: ds1307 Select
ds3231 Select the DS3231 device
+ mcp7941x Select the MCP7941x device
+
pcf2127 Select the PCF2127 device
pcf8523 Select the PCF8523 device
@@ -396,6 +398,7 @@ Params: speed Display
xohms Touchpanel sensitivity (X-plate resistance)
+
Name: rpi-ft5406
Info: Official Raspberry Pi display touchscreen
Load: dtoverlay=rpi-ft5406
--- a/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
+++ b/arch/arm/boot/dts/overlays/i2c-rtc-overlay.dts
@@ -17,6 +17,11 @@
reg = <0x68>;
status = "disable";
};
+ mcp7941x: mcp7941x@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+ status = "disable";
+ };
ds3231: ds3231@68 {
compatible = "maxim,ds3231";
reg = <0x68>;
@@ -42,6 +47,7 @@
__overrides__ {
ds1307 = <&ds1307>,"status";
ds3231 = <&ds3231>,"status";
+ mcp7941x = <&mcp7941x>,"status";
pcf2127 = <&pcf2127>,"status";
pcf8523 = <&pcf8523>,"status";
pcf8563 = <&pcf8563>,"status";

View File

@ -0,0 +1,26 @@
From 54695dcb27d8e4c37e8dd9620e85257b8abb89d8 Mon Sep 17 00:00:00 2001
From: P33M <P33M@github.com>
Date: Wed, 24 Jun 2015 11:23:06 +0100
Subject: [PATCH 086/121] dts/overlays: document DHT11 overlay
---
arch/arm/boot/dts/overlays/README | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -173,6 +173,14 @@ Load: dtoverlay=bmp085_i2c-sensor
Params: <None>
+Name: dht11
+Info: Overlay for the DHT11/DHT21/DHT22 humidity/temperature sensors
+ Also sometimes found with the part number(s) AM230x.
+Load: dtoverlay=dht11,<param>=<val>
+Params: gpiopin GPIO connected to the sensor's DATA output.
+ (default 4)
+
+
[ The ds1307-rtc overlay has been deleted. See i2c-rtc. ]

View File

@ -0,0 +1,108 @@
From 842fe412d512dabb76d169395086b6337150015a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 25 Jun 2015 12:16:11 +0100
Subject: [PATCH 087/121] gpio-poweroff: Allow it to work on Raspberry Pi
The Raspberry Pi firmware manages the power-down and reboot
process. To do this it installs a pm_power_off handler, causing
the gpio-poweroff module to abort the probe function.
This patch introduces a "force" DT property that overrides that
behaviour, and also adds a DT overlay to enable and control it.
Note that running in an active-low configuration (DT parameter
"active_low") requires a custom dt-blob.bin and probably won't
allow a reboot without switching off, so an external inversion
of the trigger signal may be preferable.
---
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 13 +++++++++
.../boot/dts/overlays/gpio-poweroff-overlay.dts | 34 ++++++++++++++++++++++
drivers/power/reset/gpio-poweroff.c | 4 ++-
4 files changed, 51 insertions(+), 1 deletion(-)
create mode 100644 arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -16,6 +16,7 @@ dtb-$(RPI_DT_OVERLAYS) += ads7846-overla
dtb-$(RPI_DT_OVERLAYS) += bmp085_i2c-sensor-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += dht11-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += enc28j60-overlay.dtb
+dtb-$(RPI_DT_OVERLAYS) += gpio-poweroff-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += hifiberry-amp-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += hifiberry-dac-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += hifiberry-dacplus-overlay.dtb
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -192,6 +192,19 @@ Params: int_pin GPIO us
speed SPI bus speed (default 12000000)
+Name: gpio-poweroff
+Info: Drives a GPIO high or low on reboot
+Load: gpio-poweroff,<param>=<val>
+Params: gpiopin GPIO for signalling (default 26)
+
+ active_low Set if the power control device requires a
+ high->low transition to trigger a power-down.
+ Note that this will require the support of a
+ custom dt-blob.bin to prevent a power-down
+ during the boot process, and that a reboot
+ will also cause the pin to go low.
+
+
Name: hifiberry-amp
Info: Configures the HifiBerry Amp and Amp+ audio cards
Load: dtoverlay=hifiberry-amp
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/gpio-poweroff-overlay.dts
@@ -0,0 +1,34 @@
+// Definitions for gpio-poweroff module
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+ target-path = "/";
+ __overlay__ {
+ power_ctrl: power_ctrl {
+ compatible = "gpio-poweroff";
+ gpios = <&gpio 26 0>;
+ force;
+ };
+ };
+ };
+
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+ power_ctrl_pins: power_ctrl_pins {
+ brcm,pins = <26>;
+ brcm,function = <1>; // out
+ };
+ };
+ };
+
+ __overrides__ {
+ gpiopin = <&power_ctrl>,"gpios:4",
+ <&power_ctrl_pins>,"brcm,pins:0";
+ active_low = <&power_ctrl>,"gpios:8";
+ };
+};
--- a/drivers/power/reset/gpio-poweroff.c
+++ b/drivers/power/reset/gpio-poweroff.c
@@ -48,9 +48,11 @@ static void gpio_poweroff_do_poweroff(vo
static int gpio_poweroff_probe(struct platform_device *pdev)
{
bool input = false;
+ bool force = false;
/* If a pm_power_off function has already been added, leave it alone */
- if (pm_power_off != NULL) {
+ force = of_property_read_bool(pdev->dev.of_node, "force");
+ if (!force && (pm_power_off != NULL)) {
dev_err(&pdev->dev,
"%s: pm_power_off function already registered",
__func__);

View File

@ -0,0 +1,90 @@
From 311119b99b34e88df249d706c69bdcffcd8dafb5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 17 Jun 2015 17:10:40 +0100
Subject: [PATCH 088/121] BCM270x_DT: Default Compute Module i2c, i2s and spi
support
---
arch/arm/boot/dts/bcm2708-rpi-cm.dts | 67 ++++++++++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)
--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
@@ -10,10 +10,77 @@
status = "okay";
};
+&gpio {
+ spi0_pins: spi0_pins {
+ brcm,pins = <7 8 9 10 11>;
+ brcm,function = <4>; /* alt0 */
+ };
+
+ i2c0_pins: i2c0 {
+ brcm,pins = <0 1>;
+ brcm,function = <4>;
+ };
+
+ i2c1_pins: i2c1 {
+ brcm,pins = <2 3>;
+ brcm,function = <4>;
+ };
+
+ i2s_pins: i2s {
+ brcm,pins = <18 19 20 21>;
+ brcm,function = <4>; /* alt0 */
+ };
+};
+
+&spi0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins>;
+
+ spidev@0{
+ compatible = "spidev";
+ reg = <0>; /* CE0 */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ spi-max-frequency = <500000>;
+ };
+
+ spidev@1{
+ compatible = "spidev";
+ reg = <1>; /* CE1 */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ spi-max-frequency = <500000>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <100000>;
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+ clock-frequency = <100000>;
+};
+
+&i2s {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s_pins>;
+};
+
/ {
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ i2s = <&i2s>,"status";
+ spi = <&spi0>,"status";
+ i2c0 = <&i2c0>,"status";
+ i2c1 = <&i2c1>,"status";
+ i2c0_baudrate = <&i2c0>,"clock-frequency:0";
+ i2c1_baudrate = <&i2c1>,"clock-frequency:0";
core_freq = <&clk_core>,"clock-frequency:0";
};
};

View File

@ -0,0 +1,234 @@
From bd6dabc8c7f6cdaba821ff3246034cd704f6364d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 22 Jun 2015 14:21:55 +0100
Subject: [PATCH 089/121] BCM270X_DT: Sort nodes by bus address, and
consolidate aliases
---
arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 19 ----------
arch/arm/boot/dts/bcm2708-rpi-b.dts | 19 ----------
arch/arm/boot/dts/bcm2708-rpi-cm.dtsi | 21 -----------
arch/arm/boot/dts/bcm2708_common.dtsi | 63 +++++++++++++++++++++++---------
arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 19 ----------
5 files changed, 46 insertions(+), 95 deletions(-)
--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
@@ -5,25 +5,6 @@
/ {
compatible = "brcm,bcm2708";
model = "Raspberry Pi Model B+";
-
- aliases {
- soc = &soc;
- spi0 = &spi0;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2s = &i2s;
- gpio = &gpio;
- intc = &intc;
- leds = &leds;
- audio = &audio;
- sound = &sound;
- uart0 = &uart0;
- uart1 = &uart1;
- clocks = &clocks;
- };
-
- sound: sound {
- };
};
&gpio {
--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
@@ -5,25 +5,6 @@
/ {
compatible = "brcm,bcm2708";
model = "Raspberry Pi Model B";
-
- aliases {
- soc = &soc;
- spi0 = &spi0;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2s = &i2s;
- gpio = &gpio;
- intc = &intc;
- leds = &leds;
- audio = &audio;
- sound = &sound;
- uart0 = &uart0;
- uart1 = &uart1;
- clocks = &clocks;
- };
-
- sound: sound {
- };
};
&gpio {
--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dtsi
@@ -1,26 +1,5 @@
/include/ "bcm2708.dtsi"
-/ {
- aliases {
- soc = &soc;
- spi0 = &spi0;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2s = &i2s;
- gpio = &gpio;
- intc = &intc;
- leds = &leds;
- audio = &audio;
- sound = &sound;
- uart0 = &uart0;
- uart1 = &uart1;
- clocks = &clocks;
- };
-
- sound: sound {
- };
-};
-
&leds {
act_led: act {
label = "led0";
--- a/arch/arm/boot/dts/bcm2708_common.dtsi
+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
@@ -3,6 +3,31 @@
/ {
interrupt-parent = <&intc>;
+ aliases {
+ audio = &audio;
+ sound = &sound;
+ soc = &soc;
+ dma = &dma;
+ intc = &intc;
+ watchdog = &watchdog;
+ random = &random;
+ mailbox = &mailbox;
+ gpio = &gpio;
+ uart0 = &uart0;
+ i2s = &i2s;
+ spi0 = &spi0;
+ i2c0 = &i2c0;
+ uart1 = &uart1;
+ mmc = &mmc;
+ i2c1 = &i2c1;
+ usb = &usb;
+ leds = &leds;
+ fb = &fb;
+ vchiq = &vchiq;
+ thermal = &thermal;
+ clocks = &clocks;
+ };
+
/* Onboard audio */
audio: audio {
compatible = "brcm,bcm2835-audio";
@@ -10,6 +35,10 @@
status = "disabled";
};
+ /* External sound card */
+ sound: sound {
+ };
+
soc: soc {
compatible = "simple-bus";
#address-cells = <1>;
@@ -43,6 +72,12 @@
#interrupt-cells = <2>;
};
+ mailbox: mailbox@7e00b800 {
+ compatible = "brcm,bcm2708-vcio";
+ reg = <0x7e00b880 0x40>;
+ interrupts = <0 1>;
+ };
+
watchdog: watchdog@7e100000 {
compatible = "brcm,bcm2835-pm-wdt";
reg = <0x7e100000 0x28>;
@@ -55,12 +90,6 @@
status = "disabled";
};
- mailbox: mailbox@7e00b800 {
- compatible = "brcm,bcm2708-vcio";
- reg = <0x7e00b880 0x40>;
- interrupts = <0 1>;
- };
-
gpio: gpio {
compatible = "brcm,bcm2835-gpio";
reg = <0x7e200000 0xb4>;
@@ -73,17 +102,6 @@
#interrupt-cells = <2>;
};
- mmc: mmc@7e300000 {
- compatible = "brcm,bcm2835-mmc";
- reg = <0x7e300000 0x100>;
- interrupts = <2 30>;
- clocks = <&clk_mmc>;
- dmas = <&dma 11>,
- <&dma 11>;
- dma-names = "tx", "rx";
- status = "disabled";
- };
-
uart0: uart@7e201000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x7e201000 0x1000>;
@@ -144,6 +162,17 @@
status = "disabled";
};
+ mmc: mmc@7e300000 {
+ compatible = "brcm,bcm2835-mmc";
+ reg = <0x7e300000 0x100>;
+ interrupts = <2 30>;
+ clocks = <&clk_mmc>;
+ dmas = <&dma 11>,
+ <&dma 11>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
i2c1: i2c@7e804000 {
compatible = "brcm,bcm2708-i2c";
reg = <0x7e804000 0x1000>;
--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
@@ -5,25 +5,6 @@
/ {
compatible = "brcm,bcm2709";
model = "Raspberry Pi 2 Model B";
-
- aliases {
- soc = &soc;
- spi0 = &spi0;
- i2c0 = &i2c0;
- i2c1 = &i2c1;
- i2s = &i2s;
- gpio = &gpio;
- intc = &intc;
- leds = &leds;
- audio = &audio;
- sound = &sound;
- uart0 = &uart0;
- uart1 = &uart1;
- clocks = &clocks;
- };
-
- sound: sound {
- };
};
&gpio {

View File

@ -0,0 +1,163 @@
From f40ed032e6f0892778bac7d33d45593c0483628b Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 22 Jun 2015 14:23:03 +0100
Subject: [PATCH 090/121] i2c-bcm2708/BCM270X_DT: Add support for I2C2
The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
use of this bus can break an attached display - use with caution.
It is recommended to disable accesses by VideoCore by setting
hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
The interface is disabled by default - enable using the
i2c2_iknowwhatimdoing DT parameter.
---
arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 6 ++++++
arch/arm/boot/dts/bcm2708-rpi-b.dts | 6 ++++++
arch/arm/boot/dts/bcm2708-rpi-cm.dts | 6 ++++++
arch/arm/boot/dts/bcm2708_common.dtsi | 14 ++++++++++++++
arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 6 ++++++
drivers/i2c/busses/i2c-bcm2708.c | 5 ++++-
6 files changed, 42 insertions(+), 1 deletion(-)
--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
@@ -75,6 +75,10 @@
clock-frequency = <100000>;
};
+&i2c2 {
+ clock-frequency = <100000>;
+};
+
&i2s {
#sound-dai-cells = <0>;
pinctrl-names = "default";
@@ -103,8 +107,10 @@
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
i2c1 = <&i2c1>,"status";
+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
@@ -75,6 +75,10 @@
clock-frequency = <100000>;
};
+&i2c2 {
+ clock-frequency = <100000>;
+};
+
&i2s {
#sound-dai-cells = <0>;
pinctrl-names = "default";
@@ -97,8 +101,10 @@
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
i2c1 = <&i2c1>,"status";
+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
@@ -65,6 +65,10 @@
clock-frequency = <100000>;
};
+&i2c2 {
+ clock-frequency = <100000>;
+};
+
&i2s {
#sound-dai-cells = <0>;
pinctrl-names = "default";
@@ -79,8 +83,10 @@
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
i2c1 = <&i2c1>,"status";
+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
core_freq = <&clk_core>,"clock-frequency:0";
};
};
--- a/arch/arm/boot/dts/bcm2708_common.dtsi
+++ b/arch/arm/boot/dts/bcm2708_common.dtsi
@@ -20,6 +20,7 @@
uart1 = &uart1;
mmc = &mmc;
i2c1 = &i2c1;
+ i2c2 = &i2c2;
usb = &usb;
leds = &leds;
fb = &fb;
@@ -179,6 +180,19 @@
interrupts = <2 21>;
clocks = <&clk_i2c>;
#address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@7e805000 {
+ // Beware - this is shared with the HDMI module.
+ // Careless use may break (really) your display.
+ // Caveat emptor.
+ compatible = "brcm,bcm2708-i2c";
+ reg = <0x7e805000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clk_i2c>;
+ #address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
@@ -75,6 +75,10 @@
clock-frequency = <100000>;
};
+&i2c2 {
+ clock-frequency = <100000>;
+};
+
&i2s {
#sound-dai-cells = <0>;
pinctrl-names = "default";
@@ -103,8 +107,10 @@
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
i2c1 = <&i2c1>,"status";
+ i2c2_iknowwhatimdoing = <&i2c2>,"status";
i2c0_baudrate = <&i2c0>,"clock-frequency:0";
i2c1_baudrate = <&i2c1>,"clock-frequency:0";
+ i2c2_baudrate = <&i2c2>,"clock-frequency:0";
core_freq = <&clk_core>,"clock-frequency:0";
act_led_gpio = <&act_led>,"gpios:4";
--- a/drivers/i2c/busses/i2c-bcm2708.c
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -407,8 +407,11 @@ static int bcm2708_i2c_probe(struct plat
case 1:
adap->class = I2C_CLASS_DDC;
break;
+ case 2:
+ adap->class = I2C_CLASS_DDC;
+ break;
default:
- dev_err(&pdev->dev, "can only bind to BSC 0 or 1\n");
+ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\n");
err = -ENXIO;
goto out_free_bi;
}

View File

@ -0,0 +1,26 @@
From 9451939c7a95b4f81886a2bf89f953be1833189d Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 29 Jun 2015 12:14:02 +0100
Subject: [PATCH 091/121] BCM270X_DT: Correct the lirc-rpi overlay
documentation
The polarity of the "sense" parameter was inverted with respect to reality.
See: https://github.com/raspberrypi/linux/issues/1038
---
arch/arm/boot/dts/overlays/README | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -313,8 +313,8 @@ Params: gpio_out_pin GPIO fo
(default "down")
sense Override the IR receive auto-detection logic:
- "1" = force active high
- "0" = force active low
+ "0" = force active-high
+ "1" = force active-low
"-1" = use auto-detection
(default "-1")

View File

@ -0,0 +1,292 @@
From d645d31525be338b1baa22916217f3ac0c3705f9 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Thu, 25 Jun 2015 08:47:09 +0100
Subject: [PATCH 092/121] bcm2835-sdhost: Further improve overclock back-off
---
drivers/mmc/host/bcm2835-sdhost.c | 144 +++++++++++++++++++++-----------------
1 file changed, 78 insertions(+), 66 deletions(-)
--- a/drivers/mmc/host/bcm2835-sdhost.c
+++ b/drivers/mmc/host/bcm2835-sdhost.c
@@ -161,8 +161,6 @@ struct bcm2835_host {
unsigned int use_busy:1; /* Wait for busy interrupt */
- unsigned int reduce_overclock:1; /* ...at the next opportunity */
-
unsigned int debug:1; /* Enable debug output */
u32 thread_isr;
@@ -466,36 +464,25 @@ static void bcm2835_sdhost_dma_complete(
spin_unlock_irqrestore(&host->lock, flags);
}
-static bool data_transfer_wait(struct bcm2835_host *host, const char *caller)
+static bool data_transfer_wait(struct bcm2835_host *host)
{
unsigned long timeout = 1000000;
- u32 hsts;
while (timeout)
{
- hsts = bcm2835_sdhost_read(host, SDHSTS);
- if (hsts & (SDHSTS_TRANSFER_ERROR_MASK |
- SDHSTS_DATA_FLAG)) {
- bcm2835_sdhost_write(host, SDHSTS_TRANSFER_ERROR_MASK,
- SDHSTS);
+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+ if (sdhsts & SDHSTS_DATA_FLAG) {
+ bcm2835_sdhost_write(host, SDHSTS_DATA_FLAG, SDHSTS);
break;
}
timeout--;
}
-
- if (hsts & (SDHSTS_CRC16_ERROR |
- SDHSTS_CRC7_ERROR |
- SDHSTS_FIFO_ERROR)) {
- pr_err("%s: data error in %s - HSTS %x\n",
- mmc_hostname(host->mmc), caller, hsts);
- host->data->error = -EILSEQ;
- return false;
- } else if ((timeout == 0) ||
- (hsts & (SDHSTS_CMD_TIME_OUT |
- SDHSTS_REW_TIME_OUT))) {
- pr_err("%s: timeout in %s - HSTS %x\n",
- mmc_hostname(host->mmc), caller, hsts);
- host->data->error = -ETIMEDOUT;
- return false;
+ if (timeout == 0) {
+ pr_err("%s: Data %s timeout\n",
+ mmc_hostname(host->mmc),
+ (host->data->flags & MMC_DATA_READ) ? "read" : "write");
+ bcm2835_sdhost_dumpregs(host);
+ host->data->error = -ETIMEDOUT;
+ return false;
}
return true;
}
@@ -523,7 +510,7 @@ static void bcm2835_sdhost_read_block_pi
buf = (u32 *)host->sg_miter.addr;
while (len) {
- if (!data_transfer_wait(host, "read_block_pio"))
+ if (!data_transfer_wait(host))
break;
*(buf++) = bcm2835_sdhost_read(host, SDDATA);
@@ -562,7 +549,7 @@ static void bcm2835_sdhost_write_block_p
buf = host->sg_miter.addr;
while (len) {
- if (!data_transfer_wait(host, "write_block_pio"))
+ if (!data_transfer_wait(host))
break;
bcm2835_sdhost_write(host, *(buf++), SDDATA);
@@ -581,13 +568,33 @@ static void bcm2835_sdhost_write_block_p
static void bcm2835_sdhost_transfer_pio(struct bcm2835_host *host)
{
+ u32 sdhsts;
+ bool is_read;
BUG_ON(!host->data);
- if (host->data->flags & MMC_DATA_READ) {
+ is_read = (host->data->flags & MMC_DATA_READ) != 0;
+ if (is_read)
bcm2835_sdhost_read_block_pio(host);
- } else {
+ else
bcm2835_sdhost_write_block_pio(host);
+ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+ if (sdhsts & (SDHSTS_CRC16_ERROR |
+ SDHSTS_CRC7_ERROR |
+ SDHSTS_FIFO_ERROR)) {
+ pr_err("%s: %s transfer error - HSTS %x\n",
+ mmc_hostname(host->mmc),
+ is_read ? "read" : "write",
+ sdhsts);
+ host->data->error = -EILSEQ;
+ } else if ((sdhsts & (SDHSTS_CMD_TIME_OUT |
+ SDHSTS_REW_TIME_OUT))) {
+ pr_err("%s: %s timeout error - HSTS %x\n",
+ mmc_hostname(host->mmc),
+ is_read ? "read" : "write",
+ sdhsts);
+ host->data->error = -ETIMEDOUT;
+ } else if (!is_read && !host->data->error) {
/* Start a timer in case a transfer error occurs because
there is no error interrupt */
mod_timer(&host->pio_timer, jiffies + host->pio_timeout);
@@ -701,8 +708,9 @@ static void bcm2835_sdhost_prepare_data(
void bcm2835_sdhost_send_command(struct bcm2835_host *host, struct mmc_command *cmd)
{
- u32 sdcmd;
+ u32 sdcmd, sdhsts;
unsigned long timeout;
+ int delay;
WARN_ON(host->cmd);
@@ -719,8 +727,8 @@ void bcm2835_sdhost_send_command(struct
mmc_hostname(host->mmc),
cmd->opcode, cmd->arg, cmd->flags);
- /* Wait max 10 ms */
- timeout = 1000;
+ /* Wait max 100 ms */
+ timeout = 10000;
while (bcm2835_sdhost_read(host, SDCMD) & SDCMD_NEW_FLAG) {
if (timeout == 0) {
@@ -735,8 +743,9 @@ void bcm2835_sdhost_send_command(struct
udelay(10);
}
- if ((1000-timeout)/100 > 1 && (1000-timeout)/100 > host->max_delay) {
- host->max_delay = (1000-timeout)/100;
+ delay = (10000 - timeout)/100;
+ if (delay > host->max_delay) {
+ host->max_delay = delay;
pr_warning("%s: controller hung for %d ms\n",
mmc_hostname(host->mmc),
host->max_delay);
@@ -751,6 +760,11 @@ void bcm2835_sdhost_send_command(struct
host->cmd = cmd;
+ /* Clear any error flags */
+ sdhsts = bcm2835_sdhost_read(host, SDHSTS);
+ if (sdhsts & SDHSTS_ERROR_MASK)
+ bcm2835_sdhost_write(host, sdhsts, SDHSTS);
+
bcm2835_sdhost_prepare_data(host, cmd);
bcm2835_sdhost_write(host, cmd->arg, SDARG);
@@ -876,7 +890,7 @@ static void bcm2835_sdhost_transfer_comp
static void bcm2835_sdhost_finish_command(struct bcm2835_host *host)
{
u32 sdcmd;
- int timeout = 1000;
+ unsigned long timeout;
#ifdef DEBUG
struct timeval before, after;
int timediff = 0;
@@ -889,6 +903,8 @@ static void bcm2835_sdhost_finish_comman
#ifdef DEBUG
do_gettimeofday(&before);
#endif
+ /* Wait max 100 ms */
+ timeout = 10000;
for (sdcmd = bcm2835_sdhost_read(host, SDCMD);
(sdcmd & SDCMD_NEW_FLAG) && timeout;
timeout--) {
@@ -1049,9 +1065,9 @@ static void bcm2835_sdhost_pio_timeout(u
spin_lock_irqsave(&host->lock, flags);
if (host->data) {
- u32 hsts = bcm2835_sdhost_read(host, SDHSTS);
+ u32 sdhsts = bcm2835_sdhost_read(host, SDHSTS);
- if (hsts & SDHSTS_REW_TIME_OUT) {
+ if (sdhsts & SDHSTS_REW_TIME_OUT) {
pr_err("%s: transfer timeout\n",
mmc_hostname(host->mmc));
if (host->debug)
@@ -1380,19 +1396,10 @@ void bcm2835_sdhost_set_clock(struct bcm
if (host->debug)
pr_info("%s: set_clock(%d)\n", mmc_hostname(host->mmc), clock);
- if ((clock == 0) && host->reduce_overclock) {
- /* This is a reset following data corruption - reduce any
- overclock */
- host->reduce_overclock = 0;
- if (host->overclock_50 > 50) {
- pr_warn("%s: reducing overclock due to errors\n",
- mmc_hostname(host->mmc));
- host->overclock_50--;
- }
- }
-
- if (host->overclock_50 && (clock == 50*MHZ))
+ if ((host->overclock_50 > 50) &&
+ (clock == 50*MHZ)) {
clock = host->overclock_50 * MHZ + (MHZ - 1);
+ }
/* The SDCDIV register has 11 bits, and holds (div - 2).
But in data mode the max is 50MHz wihout a minimum, and only the
@@ -1450,11 +1457,12 @@ void bcm2835_sdhost_set_clock(struct bcm
host->overclock = clock;
}
}
- else if ((clock == 50 * MHZ) && host->overclock)
+ else if (host->overclock)
{
- pr_warn("%s: cancelling overclock\n",
- mmc_hostname(host->mmc));
host->overclock = 0;
+ if (clock == 50 * MHZ)
+ pr_warn("%s: cancelling overclock\n",
+ mmc_hostname(host->mmc));
}
host->cdiv = div;
@@ -1492,6 +1500,14 @@ static void bcm2835_sdhost_request(struc
cmd->opcode, cmd->arg, cmd->flags);
}
+ /* Reset the error statuses in case this is a retry */
+ if (mrq->cmd)
+ mrq->cmd->error = 0;
+ if (mrq->data)
+ mrq->data->error = 0;
+ if (mrq->stop)
+ mrq->stop->error = 0;
+
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
pr_err("%s: unsupported block size (%d bytes)\n",
mmc_hostname(mmc), mrq->data->blksz);
@@ -1613,21 +1629,16 @@ static void bcm2835_sdhost_tasklet_finis
/* Drop the overclock after any data corruption, or after any
error overclocked */
- if (mrq->data && (mrq->data->error == -EILSEQ))
- host->reduce_overclock = 1;
- else if (host->overclock) {
- /* Convert timeout errors while overclocked to data errors,
- because the system recovers better. */
- if (mrq->cmd && mrq->cmd->error) {
- host->reduce_overclock = 1;
- if (mrq->cmd->error == -ETIMEDOUT)
- mrq->cmd->error = -EILSEQ;
- }
-
- if (mrq->data && mrq->data->error) {
- host->reduce_overclock = 1;
- if (mrq->data->error == -ETIMEDOUT)
- mrq->data->error = -EILSEQ;
+ if (host->overclock) {
+ if ((mrq->cmd && mrq->cmd->error) ||
+ (mrq->data && mrq->data->error) ||
+ (mrq->stop && mrq->stop->error)) {
+ host->overclock_50--;
+ pr_warn("%s: reducing overclock due to errors\n",
+ mmc_hostname(host->mmc));
+ bcm2835_sdhost_set_clock(host,50*MHZ);
+ mrq->cmd->error = -EILSEQ;
+ mrq->cmd->retries = 1;
}
}
@@ -1769,6 +1780,7 @@ static int bcm2835_sdhost_probe(struct p
host = mmc_priv(mmc);
host->mmc = mmc;
host->pio_timeout = msecs_to_jiffies(500);
+ host->max_delay = 1; /* Warn if over 1ms */
spin_lock_init(&host->lock);
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@ -0,0 +1,38 @@
From 11667799f99dca096d4d92e63b7823db2a8f8779 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 30 Jun 2015 10:28:59 +0100
Subject: [PATCH 093/121] i2c-bcm2708: Increase timeouts to allow larger
transfers
Use the timeout value provided by the I2C_TIMEOUT ioctl when waiting
for completion. The default timeout is 1 second.
See: https://github.com/raspberrypi/linux/issues/260
---
drivers/i2c/busses/i2c-bcm2708.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
--- a/drivers/i2c/busses/i2c-bcm2708.c
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -67,10 +67,9 @@
#define BSC_S_DONE 0x00000002
#define BSC_S_TA 0x00000001
-#define I2C_TIMEOUT_MS 150
-#define I2C_WAIT_LOOP_COUNT 40
+#define I2C_WAIT_LOOP_COUNT 200
-#define DRV_NAME "bcm2708_i2c"
+#define DRV_NAME "bcm2708_i2c"
static unsigned int baudrate = CONFIG_I2C_BCM2708_BAUDRATE;
module_param(baudrate, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
@@ -305,7 +304,7 @@ static int bcm2708_i2c_master_xfer(struc
goto error_timeout;
}
- ret = wait_for_completion_timeout(&bi->done, msecs_to_jiffies(I2C_TIMEOUT_MS));
+ ret = wait_for_completion_timeout(&bi->done, adap->timeout);
if (ret == 0) {
dev_err(&adap->dev, "transfer timed out\n");
goto error_timeout;

View File

@ -0,0 +1,24 @@
From 04f7264e602d7148822f3a162176190fcc41f71a Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 30 Jun 2015 10:33:52 +0100
Subject: [PATCH 094/121] spi-bcm2708: Increase timeout from 150ms to 1s
See: https://github.com/raspberrypi/linux/issues/260
---
drivers/spi/spi-bcm2708.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/spi/spi-bcm2708.c
+++ b/drivers/spi/spi-bcm2708.c
@@ -70,9 +70,9 @@
#define SPI_CS_CS_10 0x00000002
#define SPI_CS_CS_01 0x00000001
-#define SPI_TIMEOUT_MS 150
+#define SPI_TIMEOUT_MS 1000
-#define DRV_NAME "bcm2708_spi"
+#define DRV_NAME "bcm2708_spi"
struct bcm2708_spi {
spinlock_t lock;

View File

@ -0,0 +1,39 @@
From 2e6c5de15687dadf4c24d880d0cdcb6763aacda5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 15 Jun 2015 09:59:38 +0100
Subject: [PATCH 095/121] bcm2708-spi: Don't use static pin configuration with
DT
Also remove superfluous error checking - the SPI framework ensures the
validity of the chip_select value.
---
drivers/spi/spi-bcm2708.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
--- a/drivers/spi/spi-bcm2708.c
+++ b/drivers/spi/spi-bcm2708.c
@@ -386,14 +386,6 @@ static int bcm2708_spi_setup(struct spi_
if (bs->stopping)
return -ESHUTDOWN;
- if (!(spi->mode & SPI_NO_CS) &&
- (spi->chip_select > spi->master->num_chipselect)) {
- dev_dbg(&spi->dev,
- "setup: invalid chipselect %u (%u defined)\n",
- spi->chip_select, spi->master->num_chipselect);
- return -EINVAL;
- }
-
state = spi->controller_state;
if (!state) {
state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -496,7 +488,8 @@ static int bcm2708_spi_probe(struct plat
return PTR_ERR(clk);
}
- bcm2708_init_pinmode();
+ if (!pdev->dev.of_node)
+ bcm2708_init_pinmode();
master = spi_alloc_master(&pdev->dev, sizeof(*bs));
if (!master) {

View File

@ -0,0 +1,23 @@
From 699c056af380b45856086c0b33a65acc3d2ad3d8 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Mon, 15 Jun 2015 10:10:59 +0100
Subject: [PATCH 096/121] bcm2708-i2s: Don't use static pin configuration with
DT
---
sound/soc/bcm/bcm2708-i2s.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/sound/soc/bcm/bcm2708-i2s.c
+++ b/sound/soc/bcm/bcm2708-i2s.c
@@ -409,8 +409,8 @@ static int bcm2708_i2s_hw_params(struct
if (csreg & (BCM2708_I2S_TXON | BCM2708_I2S_RXON))
return 0;
-
- bcm2708_i2s_setup_gpio();
+ if (!dev->dev->of_node)
+ bcm2708_i2s_setup_gpio();
/*
* Adjust the data length according to the format.

View File

@ -0,0 +1,20 @@
From 6b8e6f74b78fcc225c873ea1b07890352dd77ee5 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 30 Jun 2015 14:12:42 +0100
Subject: [PATCH 097/121] serial: 8250: Don't crash when nr_uarts is 0
---
drivers/tty/serial/8250/8250_core.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -3262,6 +3262,8 @@ static void __init serial8250_isa_init_p
if (nr_uarts > UART_NR)
nr_uarts = UART_NR;
+ if (!nr_uarts)
+ return;
for (i = 0; i < nr_uarts; i++) {
struct uart_8250_port *up = &serial8250_ports[i];

View File

@ -0,0 +1,152 @@
From 5131bc710dd79b98d12c08b2f22477f48fdbd0d3 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Fri, 26 Jun 2015 08:50:11 +0100
Subject: [PATCH 098/121] BCM270X_DT: Add overlay to enable uart1
N.B. The UART1 clock is derived from the core clock. The firmware
will update clock-frequency if core_freq is set, but be aware
that unless force_turbo=1 while overclocking then the baud rate
will vary with ARM activity.
---
arch/arm/boot/dts/bcm2708-rpi-b-plus.dts | 1 +
arch/arm/boot/dts/bcm2708-rpi-b.dts | 1 +
arch/arm/boot/dts/bcm2708-rpi-cm.dts | 1 +
arch/arm/boot/dts/bcm2709-rpi-2-b.dts | 1 +
arch/arm/boot/dts/overlays/Makefile | 1 +
arch/arm/boot/dts/overlays/README | 8 ++++++
arch/arm/boot/dts/overlays/uart1-overlay.dts | 38 ++++++++++++++++++++++++++++
arch/arm/configs/bcm2709_defconfig | 2 +-
arch/arm/configs/bcmrpi_defconfig | 2 +-
9 files changed, 53 insertions(+), 2 deletions(-)
create mode 100644 arch/arm/boot/dts/overlays/uart1-overlay.dts
--- a/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b-plus.dts
@@ -103,6 +103,7 @@
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ uart1_clkrate = <&uart1>,"clock-frequency:0";
i2s = <&i2s>,"status";
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
--- a/arch/arm/boot/dts/bcm2708-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-b.dts
@@ -97,6 +97,7 @@
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ uart1_clkrate = <&uart1>,"clock-frequency:0";
i2s = <&i2s>,"status";
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
--- a/arch/arm/boot/dts/bcm2708-rpi-cm.dts
+++ b/arch/arm/boot/dts/bcm2708-rpi-cm.dts
@@ -79,6 +79,7 @@
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ uart1_clkrate = <&uart1>,"clock-frequency:0";
i2s = <&i2s>,"status";
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
--- a/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
+++ b/arch/arm/boot/dts/bcm2709-rpi-2-b.dts
@@ -103,6 +103,7 @@
__overrides__ {
uart0 = <&uart0>,"status";
uart0_clkrate = <&clk_uart0>,"clock-frequency:0";
+ uart1_clkrate = <&uart1>,"clock-frequency:0";
i2s = <&i2s>,"status";
spi = <&spi0>,"status";
i2c0 = <&i2c0>,"status";
--- a/arch/arm/boot/dts/overlays/Makefile
+++ b/arch/arm/boot/dts/overlays/Makefile
@@ -42,6 +42,7 @@ dtb-$(RPI_DT_OVERLAYS) += sdhost-overlay
dtb-$(RPI_DT_OVERLAYS) += spi-bcm2708-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += spi-bcm2835-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += tinylcd35-overlay.dtb
+dtb-$(RPI_DT_OVERLAYS) += uart1-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += w1-gpio-overlay.dtb
dtb-$(RPI_DT_OVERLAYS) += w1-gpio-pullup-overlay.dtb
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -489,6 +489,14 @@ Params: speed Display
dtoverlay=tinylcd35,touch,touchgpio=3
+Name: uart1
+Info: Enable uart1 in place of uart0
+Load: dtoverlay=uart1,<param>=<val>
+Params: txd1_pin GPIO pin for TXD1 (14, 32 or 40 - default 14)
+
+ rxd1_pin GPIO pin for RXD1 (15, 33 or 41 - default 15)
+
+
Name: w1-gpio
Info: Configures the w1-gpio Onewire interface module.
Use this overlay if you *don't* need a GPIO to drive an external pullup.
--- /dev/null
+++ b/arch/arm/boot/dts/overlays/uart1-overlay.dts
@@ -0,0 +1,38 @@
+/dts-v1/;
+/plugin/;
+
+/{
+ compatible = "brcm,bcm2708";
+
+ fragment@0 {
+ target = <&uart1>;
+ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+ status = "okay";
+ };
+ };
+
+ fragment@1 {
+ target = <&gpio>;
+ __overlay__ {
+ uart1_pins: uart1_pins {
+ brcm,pins = <14 15>;
+ brcm,function = <2>; /* alt5 */
+ brcm,pull = <0 2>;
+ };
+ };
+ };
+
+ fragment@2 {
+ target-path = "/chosen";
+ __overlay__ {
+ bootargs = "8250.nr_uarts=1";
+ };
+ };
+
+ __overrides__ {
+ txd1_pin = <&uart1_pins>,"brcm,pins:0";
+ rxd1_pin = <&uart1_pins>,"brcm,pins:4";
+ };
+};
--- a/arch/arm/configs/bcm2709_defconfig
+++ b/arch/arm/configs/bcm2709_defconfig
@@ -562,7 +562,7 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=1
-CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -555,7 +555,7 @@ CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
# CONFIG_SERIAL_8250_DMA is not set
CONFIG_SERIAL_8250_NR_UARTS=1
-CONFIG_SERIAL_8250_RUNTIME_UARTS=1
+CONFIG_SERIAL_8250_RUNTIME_UARTS=0
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y

View File

@ -0,0 +1,80 @@
From 72d2ba8d7fa2d47c53ed1425501c2dac2aa909b0 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Wed, 24 Jun 2015 14:10:44 +0100
Subject: [PATCH 099/121] spi-bcm2835: Support pin groups other than 7-11
The spi-bcm2835 driver automatically uses GPIO chip-selects due to
some unreliability of the native ones. In doing so it chooses the
same pins as the native chip-selects would use, but the existing
code always uses pins 7 and 8, wherever the SPI function is mapped.
Search the pinctrl group assigned to the driver for pins that
correspond to native chip-selects, and use those for GPIO chip-
selects.
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
---
drivers/spi/spi-bcm2835.c | 45 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 8 deletions(-)
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -359,6 +359,8 @@ static int bcm2835_spi_setup(struct spi_
{
int err;
struct gpio_chip *chip;
+ struct device_node *pins;
+ u32 pingroup_index;
/*
* sanity checking the native-chipselects
*/
@@ -375,15 +377,42 @@ static int bcm2835_spi_setup(struct spi_
"setup: only two native chip-selects are supported\n");
return -EINVAL;
}
- /* now translate native cs to GPIO */
- /* get the gpio chip for the base */
- chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
- if (!chip)
- return 0;
+ /* now translate native cs to GPIO */
+ /* first look for chip select pins in the devices pin groups */
+ for (pingroup_index = 0;
+ (pins = of_parse_phandle(spi->master->dev.of_node,
+ "pinctrl-0",
+ pingroup_index)) != 0;
+ pingroup_index++) {
+ u32 pin;
+ u32 pin_index;
+ for (pin_index = 0;
+ of_property_read_u32_index(pins,
+ "brcm,pins",
+ pin_index,
+ &pin) == 0;
+ pin_index++) {
+ if (((spi->chip_select == 0) &&
+ ((pin == 8) || (pin == 36) || (pin == 46))) ||
+ ((spi->chip_select == 1) &&
+ ((pin == 7) || (pin == 35)))) {
+ spi->cs_gpio = pin;
+ break;
+ }
+ }
+ of_node_put(pins);
+ }
+ /* if that fails, assume GPIOs 7-11 are used */
+ if (!gpio_is_valid(spi->cs_gpio) ) {
+ /* get the gpio chip for the base */
+ chip = gpiochip_find("pinctrl-bcm2835", chip_match_name);
+ if (!chip)
+ return 0;
- /* and calculate the real CS */
- spi->cs_gpio = chip->base + 8 - spi->chip_select;
+ /* and calculate the real CS */
+ spi->cs_gpio = chip->base + 8 - spi->chip_select;
+ }
/* and set up the "mode" and level */
dev_info(&spi->dev, "setting up native-CS%i as GPIO %i\n",

View File

@ -0,0 +1,20 @@
From 4bf9c275c9733d1fcf41f6ee70b40e321b39eac1 Mon Sep 17 00:00:00 2001
From: Phil Elwell <phil@raspberrypi.org>
Date: Tue, 30 Jun 2015 17:37:38 +0100
Subject: [PATCH 100/121] BCM270X_DT: Change pio_limit of sdhost driver to 1
---
arch/arm/boot/dts/overlays/sdhost-overlay.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/arch/arm/boot/dts/overlays/sdhost-overlay.dts
+++ b/arch/arm/boot/dts/overlays/sdhost-overlay.dts
@@ -22,7 +22,7 @@
dma-names = "tx", "rx";
brcm,delay-after-stop = <0>;
brcm,overclock-50 = <0>;
- brcm,pio-limit = <2>;
+ brcm,pio-limit = <1>;
status = "okay";
};
};

Some files were not shown because too many files have changed in this diff Show More