mirror of https://github.com/hak5/openwrt-owl.git
brcm2708: add linux 4.4 support
- random-bcm2708 and spi-bcm2708 have been removed. - sound-soc-bcm2708-i2s has been upstreamed as sound-soc-bcm2835-i2s. Let's keep linux 4.1 for a while, since linux 4.4 appears to have some issues with multicast traffic on RPi ethernet: https://gist.github.com/Noltari/5b1cfdecce5ed4bc08fd Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com> SVN-Revision: 48266owl
parent
cad399c87b
commit
4224b52c3a
|
@ -0,0 +1,355 @@
|
|||
# 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_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_BACKLIGHT_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
# CONFIG_BCM2708_NOL2CACHE is not set
|
||||
CONFIG_BCM2708_VCHIQ=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2835_DEVGPIOMEM is not set
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
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_MMIO=y
|
||||
CONFIG_CLKSRC_OF=y
|
||||
CONFIG_CLKSRC_PROBE=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_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=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 is not set
|
||||
CONFIG_DMA_BCM2835=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_EDAC_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=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_FB_RPISENSE is not set
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIRMWARE_IN_KERNEL=y
|
||||
CONFIG_FIX_EARLYCON_MEM=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=y
|
||||
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_MACH_BCM2708=y
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
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_MULTI_IRQ_HANDLER=y
|
||||
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_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_RATIONAL=y
|
||||
CONFIG_RAW_DRIVER=y
|
||||
# CONFIG_RCU_STALL_COMMON is not set
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_SCHED_HRTICK=y
|
||||
# CONFIG_SCHED_INFO is not set
|
||||
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_FSL=y
|
||||
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_SPARSE_IRQ=y
|
||||
# CONFIG_SQUASHFS is not set
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STAGING is not set
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
# CONFIG_SUNXI_SRAM 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_STEP_WISE=y
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
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
|
|
@ -0,0 +1,387 @@
|
|||
# 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_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_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_BACKLIGHT_CLASS_DEVICE is not set
|
||||
CONFIG_BACKLIGHT_LCD_SUPPORT=y
|
||||
CONFIG_BCM2708_NOL2CACHE=y
|
||||
CONFIG_BCM2708_VCHIQ=y
|
||||
CONFIG_BCM2708_VCMEM=y
|
||||
# CONFIG_BCM2835_DEVGPIOMEM is not set
|
||||
CONFIG_BCM2835_MBOX=y
|
||||
# CONFIG_BCM2835_SMI is not set
|
||||
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_CLKSRC_PROBE=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_CRYPTO_RNG2=y
|
||||
CONFIG_CRYPTO_WORKQUEUE=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 is not set
|
||||
CONFIG_DMA_BCM2835=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_EDAC_ATOMIC_SCRUB=y
|
||||
CONFIG_EDAC_SUPPORT=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_FB_RPISENSE is not set
|
||||
CONFIG_FIQ=y
|
||||
CONFIG_FIRMWARE_IN_KERNEL=y
|
||||
CONFIG_FIX_EARLYCON_MEM=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=y
|
||||
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_LZO_COMPRESS=y
|
||||
CONFIG_LZO_DECOMPRESS=y
|
||||
CONFIG_MACH_BCM2709=y
|
||||
CONFIG_MAC_PARTITION=y
|
||||
CONFIG_MAGIC_SYSRQ=y
|
||||
CONFIG_MAILBOX=y
|
||||
# CONFIG_MAILBOX_TEST is not set
|
||||
CONFIG_MAX_RAW_DEVS=256
|
||||
CONFIG_MEMORY_ISOLATION=y
|
||||
CONFIG_MFD_SYSCON=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_MULTI_IRQ_HANDLER=y
|
||||
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_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_RATIONAL=y
|
||||
CONFIG_RAW_DRIVER=y
|
||||
CONFIG_RCU_STALL_COMMON=y
|
||||
CONFIG_REGMAP=y
|
||||
CONFIG_REGMAP_MMIO=y
|
||||
CONFIG_RFS_ACCEL=y
|
||||
CONFIG_RPS=y
|
||||
CONFIG_RWSEM_SPIN_ON_OWNER=y
|
||||
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
|
||||
CONFIG_SCHED_HRTICK=y
|
||||
# CONFIG_SCHED_INFO is not set
|
||||
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_FSL=y
|
||||
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_SPARSE_IRQ=y
|
||||
# CONFIG_SQUASHFS is not set
|
||||
CONFIG_SRCU=y
|
||||
# CONFIG_STAGING is not set
|
||||
# CONFIG_STRIP_ASM_SYMS is not set
|
||||
# CONFIG_SUNXI_SRAM 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_STEP_WISE=y
|
||||
CONFIG_THERMAL_GOV_STEP_WISE=y
|
||||
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
|
|
@ -36,7 +36,7 @@ define KernelPackage/sound-soc-bcm2708-i2s
|
|||
FILES:= \
|
||||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2708-i2s.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2708-i2s)
|
||||
DEPENDS:=@TARGET_brcm2708 +kmod-regmap +kmod-sound-soc-core
|
||||
DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-regmap +kmod-sound-soc-core
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -46,6 +46,25 @@ endef
|
|||
|
||||
$(eval $(call KernelPackage,sound-soc-bcm2708-i2s))
|
||||
|
||||
define KernelPackage/sound-soc-bcm2835-i2s
|
||||
TITLE:=SoC Audio support for the Broadcom 2835 I2S module
|
||||
KCONFIG:= \
|
||||
CONFIG_SND_BCM2835_SOC_I2S \
|
||||
CONFIG_SND_SOC_DMAENGINE_PCM=y \
|
||||
CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
|
||||
FILES:= \
|
||||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-bcm2835-i2s.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-bcm2835-i2s)
|
||||
DEPENDS:=@TARGET_brcm2708 @LINUX_4_4 +kmod-regmap +kmod-sound-soc-core
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
define KernelPackage/sound-soc-bcm2835-i2s/description
|
||||
This package contains support for codecs attached to the Broadcom 2835 I2S interface
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,sound-soc-bcm2835-i2s))
|
||||
|
||||
define KernelPackage/sound-soc-hifiberry-dac
|
||||
TITLE:=Support for HifiBerry DAC
|
||||
KCONFIG:= \
|
||||
|
@ -55,7 +74,10 @@ define KernelPackage/sound-soc-hifiberry-dac
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dac.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm5102a.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm5102a snd-soc-hifiberry-dac)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -75,7 +97,10 @@ define KernelPackage/sound-soc-hifiberry-dacplus
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-dacplus.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,clk-hifiberry-dacpro snd-soc-pcm512x snd-soc-hifiberry-dacplus)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -94,7 +119,10 @@ define KernelPackage/sound-soc-hifiberry-digi
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-digi.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8804.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8804 snd-soc-hifiberry-digi)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -113,7 +141,10 @@ define KernelPackage/sound-soc-hifiberry-amp
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-hifiberry-amp.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-tas5713.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-tas5713 snd-soc-hifiberry-amp)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -132,7 +163,10 @@ define KernelPackage/sound-soc-rpi-dac
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-dac.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm1794a.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm1794a snd-soc-rpi-dac)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -151,7 +185,10 @@ define KernelPackage/sound-soc-rpi-proto
|
|||
$(LINUX_DIR)/sound/soc/bcm/snd-soc-rpi-proto.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-wm8731.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-wm8731 snd-soc-rpi-proto)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -172,7 +209,10 @@ define KernelPackage/sound-soc-iqaudio-dac
|
|||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-iqaudio-dac)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -195,7 +235,10 @@ define KernelPackage/sound-soc-raspidac3
|
|||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-pcm512x-i2c.ko \
|
||||
$(LINUX_DIR)/sound/soc/codecs/snd-soc-tpa6130a2.ko
|
||||
AUTOLOAD:=$(call AutoLoad,68,snd-soc-pcm512x snd-soc-pcm512x-i2c snd-soc-tpa6130a2 snd-soc-raspidac3)
|
||||
DEPENDS:=kmod-sound-soc-bcm2708-i2s +kmod-i2c-bcm2708
|
||||
DEPENDS:= \
|
||||
LINUX_4_1:kmod-sound-soc-bcm2708-i2s \
|
||||
LINUX_4_4:kmod-sound-soc-bcm2835-i2s \
|
||||
+kmod-i2c-bcm2708
|
||||
$(call AddDepends/sound)
|
||||
endef
|
||||
|
||||
|
@ -212,7 +255,7 @@ define KernelPackage/random-bcm2708
|
|||
KCONFIG:=CONFIG_HW_RANDOM_BCM2708
|
||||
FILES:=$(LINUX_DIR)/drivers/char/hw_random/bcm2708-rng.ko
|
||||
AUTOLOAD:=$(call AutoLoad,11,bcm2708-rng)
|
||||
DEPENDS:=@TARGET_brcm2708 +kmod-random-core
|
||||
DEPENDS:=@TARGET_brcm2708 @LINUX_4_1 +kmod-random-core
|
||||
endef
|
||||
|
||||
define KernelPackage/random-bcm2708/description
|
||||
|
@ -281,7 +324,7 @@ define KernelPackage/spi-bcm2708
|
|||
CONFIG_SPI_MASTER=y
|
||||
FILES:=$(LINUX_DIR)/drivers/spi/spi-bcm2708.ko
|
||||
AUTOLOAD:=$(call AutoLoad,89,spi-bcm2708)
|
||||
DEPENDS:=@TARGET_brcm2708
|
||||
DEPENDS:=@TARGET_brcm2708 @LINUX_4_1
|
||||
endef
|
||||
|
||||
define KernelPackage/spi-bcm2708/description
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
From 8c2c0f30ef9ee0eccd3e56c6aeb110097569d5aa 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 001/127] 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
|
||||
@@ -1785,7 +1785,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;
|
||||
}
|
||||
@@ -1803,7 +1802,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);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
From 96f6fc6f990423f39b73013cd91f00a615315a90 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Fri, 17 Apr 2015 16:58:45 +0100
|
||||
Subject: [PATCH 002/127] 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
|
||||
@@ -70,7 +70,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");
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
From 3ea06ff9ba42a29f37b46ced2fb90ff9e06da445 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 18 Jun 2014 13:42:01 +0100
|
||||
Subject: [PATCH 003/127] 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
|
||||
@@ -219,7 +219,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,
|
|
@ -0,0 +1,50 @@
|
|||
From 6c72a609c205138b739a1484aa1a4ce6dd395c43 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Tiemann <rtie@gmx.de>
|
||||
Date: Mon, 20 Jul 2015 11:01:25 +0200
|
||||
Subject: [PATCH 004/127] BCM2835_DT: Fix I2S register map
|
||||
|
||||
---
|
||||
Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt | 4 ++--
|
||||
Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt | 4 ++--
|
||||
arch/arm/boot/dts/bcm2835.dtsi | 4 ++--
|
||||
3 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
|
||||
+++ b/Documentation/devicetree/bindings/dma/brcm,bcm2835-dma.txt
|
||||
@@ -48,8 +48,8 @@ Example:
|
||||
|
||||
bcm2835_i2s: i2s@7e203000 {
|
||||
compatible = "brcm,bcm2835-i2s";
|
||||
- reg = < 0x7e203000 0x20>,
|
||||
- < 0x7e101098 0x02>;
|
||||
+ reg = < 0x7e203000 0x24>,
|
||||
+ < 0x7e101098 0x08>;
|
||||
|
||||
dmas = <&dma 2>,
|
||||
<&dma 3>;
|
||||
--- a/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
|
||||
+++ b/Documentation/devicetree/bindings/sound/brcm,bcm2835-i2s.txt
|
||||
@@ -16,8 +16,8 @@ Example:
|
||||
|
||||
bcm2835_i2s: i2s@7e203000 {
|
||||
compatible = "brcm,bcm2835-i2s";
|
||||
- reg = <0x7e203000 0x20>,
|
||||
- <0x7e101098 0x02>;
|
||||
+ reg = <0x7e203000 0x24>,
|
||||
+ <0x7e101098 0x08>;
|
||||
|
||||
dmas = <&dma 2>,
|
||||
<&dma 3>;
|
||||
--- a/arch/arm/boot/dts/bcm2835.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm2835.dtsi
|
||||
@@ -120,8 +120,8 @@
|
||||
|
||||
i2s: i2s@7e203000 {
|
||||
compatible = "brcm,bcm2835-i2s";
|
||||
- reg = <0x7e203000 0x20>,
|
||||
- <0x7e101098 0x02>;
|
||||
+ reg = <0x7e203000 0x24>,
|
||||
+ <0x7e101098 0x08>;
|
||||
|
||||
dmas = <&dma 2>,
|
||||
<&dma 3>;
|
|
@ -0,0 +1,31 @@
|
|||
From 38395f1ae1258743c3e0081c86bb4b65ad06dd69 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 4 Dec 2015 17:41:50 +0000
|
||||
Subject: [PATCH 005/127] irq-bcm2836: Prevent spurious interrupts, and trap
|
||||
them early
|
||||
|
||||
The old arch-specific IRQ macros included a dsb to ensure the
|
||||
write to clear the mailbox interrupt completed before returning
|
||||
from the interrupt. The BCM2836 irqchip driver needs the same
|
||||
precaution to avoid spurious interrupts.
|
||||
|
||||
Spurious interrupts are still possible for other reasons,
|
||||
though, so trap them early.
|
||||
---
|
||||
drivers/irqchip/irq-bcm2836.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/irqchip/irq-bcm2836.c
|
||||
+++ b/drivers/irqchip/irq-bcm2836.c
|
||||
@@ -170,9 +170,10 @@ __exception_irq_entry bcm2836_arm_irqchi
|
||||
u32 ipi = ffs(mbox_val) - 1;
|
||||
|
||||
writel(1 << ipi, mailbox0);
|
||||
+ dsb();
|
||||
handle_IPI(ipi, regs);
|
||||
#endif
|
||||
- } else {
|
||||
+ } else if (stat) {
|
||||
u32 hwirq = ffs(stat) - 1;
|
||||
|
||||
handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
|
|
@ -0,0 +1,127 @@
|
|||
From 44b5e890373665231d9a5876966ef3a670b9efd7 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 12 Jun 2015 19:01:05 +0200
|
||||
Subject: [PATCH 006/127] irqchip: bcm2835: Add FIQ support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add a duplicate irq range with an offset on the hwirq's so the
|
||||
driver can detect that enable_fiq() is used.
|
||||
Tested with downstream dwc_otg USB controller driver.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
Reviewed-by: Eric Anholt <eric@anholt.net>
|
||||
Acked-by: Stephen Warren <swarren@wwwdotorg.org>
|
||||
---
|
||||
arch/arm/mach-bcm/Kconfig | 1 +
|
||||
drivers/irqchip/irq-bcm2835.c | 51 ++++++++++++++++++++++++++++++++++++++-----
|
||||
2 files changed, 47 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/arch/arm/mach-bcm/Kconfig
|
||||
+++ b/arch/arm/mach-bcm/Kconfig
|
||||
@@ -128,6 +128,7 @@ config ARCH_BCM2835
|
||||
select ARM_ERRATA_411920
|
||||
select ARM_TIMER_SP804
|
||||
select CLKSRC_OF
|
||||
+ select FIQ
|
||||
select PINCTRL
|
||||
select PINCTRL_BCM2835
|
||||
help
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -55,7 +55,7 @@
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
/* Put the bank and irq (32 bits) into the hwirq */
|
||||
-#define MAKE_HWIRQ(b, n) ((b << 5) | (n))
|
||||
+#define MAKE_HWIRQ(b, n) (((b) << 5) | (n))
|
||||
#define HWIRQ_BANK(i) (i >> 5)
|
||||
#define HWIRQ_BIT(i) BIT(i & 0x1f)
|
||||
|
||||
@@ -71,9 +71,13 @@
|
||||
| SHORTCUT1_MASK | SHORTCUT2_MASK)
|
||||
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
+#define REG_FIQ_ENABLE 0x80
|
||||
+#define REG_FIQ_DISABLE 0
|
||||
|
||||
#define NR_BANKS 3
|
||||
#define IRQS_PER_BANK 32
|
||||
+#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
|
||||
+#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
|
||||
|
||||
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
|
||||
static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 };
|
||||
@@ -98,14 +102,38 @@ static void __exception_irq_entry bcm283
|
||||
struct pt_regs *regs);
|
||||
static void bcm2836_chained_handle_irq(struct irq_desc *desc);
|
||||
|
||||
+static inline unsigned int hwirq_to_fiq(unsigned long hwirq)
|
||||
+{
|
||||
+ hwirq -= NUMBER_IRQS;
|
||||
+ /*
|
||||
+ * The hwirq numbering used in this driver is:
|
||||
+ * BASE (0-7) GPU1 (32-63) GPU2 (64-95).
|
||||
+ * This differ from the one used in the FIQ register:
|
||||
+ * GPU1 (0-31) GPU2 (32-63) BASE (64-71)
|
||||
+ */
|
||||
+ if (hwirq >= 32)
|
||||
+ return hwirq - 32;
|
||||
+
|
||||
+ return hwirq + 64;
|
||||
+}
|
||||
+
|
||||
static void armctrl_mask_irq(struct irq_data *d)
|
||||
{
|
||||
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ if (d->hwirq >= NUMBER_IRQS)
|
||||
+ writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL);
|
||||
+ else
|
||||
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
+ intc.disable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static void armctrl_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ if (d->hwirq >= NUMBER_IRQS)
|
||||
+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
|
||||
+ intc.base + REG_FIQ_CONTROL);
|
||||
+ else
|
||||
+ writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
+ intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
}
|
||||
|
||||
static struct irq_chip armctrl_chip = {
|
||||
@@ -151,8 +179,9 @@ static int __init armctrl_of_init(struct
|
||||
panic("%s: unable to map IC registers\n",
|
||||
node->full_name);
|
||||
|
||||
- intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0),
|
||||
- &armctrl_ops, NULL);
|
||||
+ intc.base = base;
|
||||
+ intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2,
|
||||
+ &armctrl_ops, NULL);
|
||||
if (!intc.domain)
|
||||
panic("%s: unable to create IRQ domain\n", node->full_name);
|
||||
|
||||
@@ -182,6 +211,18 @@ static int __init armctrl_of_init(struct
|
||||
set_handle_irq(bcm2835_handle_irq);
|
||||
}
|
||||
|
||||
+ /* Make a duplicate irq range which is used to enable FIQ */
|
||||
+ for (b = 0; b < NR_BANKS; b++) {
|
||||
+ for (i = 0; i < bank_irqs[b]; i++) {
|
||||
+ irq = irq_create_mapping(intc.domain,
|
||||
+ MAKE_HWIRQ(b, i) + NUMBER_IRQS);
|
||||
+ BUG_ON(irq <= 0);
|
||||
+ irq_set_chip(irq, &armctrl_chip);
|
||||
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
+ }
|
||||
+ }
|
||||
+ init_FIQ(FIQ_START);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
From e3e8c56abfe6a036025f75908b63ae69d8eaed11 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 23 Oct 2015 16:26:55 +0200
|
||||
Subject: [PATCH 007/127] irqchip: irq-bcm2835: Add 2836 FIQ support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/irqchip/irq-bcm2835.c | 42 ++++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 40 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -50,6 +50,8 @@
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/irqdomain.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/regmap.h>
|
||||
|
||||
#include <asm/exception.h>
|
||||
#include <asm/mach/irq.h>
|
||||
@@ -70,6 +72,9 @@
|
||||
#define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \
|
||||
| SHORTCUT1_MASK | SHORTCUT2_MASK)
|
||||
|
||||
+#undef ARM_LOCAL_GPU_INT_ROUTING
|
||||
+#define ARM_LOCAL_GPU_INT_ROUTING 0x0c
|
||||
+
|
||||
#define REG_FIQ_CONTROL 0x0c
|
||||
#define REG_FIQ_ENABLE 0x80
|
||||
#define REG_FIQ_DISABLE 0
|
||||
@@ -95,6 +100,7 @@ struct armctrl_ic {
|
||||
void __iomem *enable[NR_BANKS];
|
||||
void __iomem *disable[NR_BANKS];
|
||||
struct irq_domain *domain;
|
||||
+ struct regmap *local_regmap;
|
||||
};
|
||||
|
||||
static struct armctrl_ic intc __read_mostly;
|
||||
@@ -128,12 +134,35 @@ static void armctrl_mask_irq(struct irq_
|
||||
|
||||
static void armctrl_unmask_irq(struct irq_data *d)
|
||||
{
|
||||
- if (d->hwirq >= NUMBER_IRQS)
|
||||
+ if (d->hwirq >= NUMBER_IRQS) {
|
||||
+ if (num_online_cpus() > 1) {
|
||||
+ unsigned int data;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!intc.local_regmap) {
|
||||
+ pr_err("FIQ is disabled due to missing regmap\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_read(intc.local_regmap,
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING, &data);
|
||||
+ if (ret) {
|
||||
+ pr_err("Failed to read int routing %d\n", ret);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ data &= ~0xc;
|
||||
+ data |= (1 << 2);
|
||||
+ regmap_write(intc.local_regmap,
|
||||
+ ARM_LOCAL_GPU_INT_ROUTING, data);
|
||||
+ }
|
||||
+
|
||||
writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq),
|
||||
intc.base + REG_FIQ_CONTROL);
|
||||
- else
|
||||
+ } else {
|
||||
writel_relaxed(HWIRQ_BIT(d->hwirq),
|
||||
intc.enable[HWIRQ_BANK(d->hwirq)]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static struct irq_chip armctrl_chip = {
|
||||
@@ -211,6 +240,15 @@ static int __init armctrl_of_init(struct
|
||||
set_handle_irq(bcm2835_handle_irq);
|
||||
}
|
||||
|
||||
+ if (is_2836) {
|
||||
+ intc.local_regmap =
|
||||
+ syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local");
|
||||
+ if (IS_ERR(intc.local_regmap)) {
|
||||
+ pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n");
|
||||
+ intc.local_regmap = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* Make a duplicate irq range which is used to enable FIQ */
|
||||
for (b = 0; b < NR_BANKS; b++) {
|
||||
for (i = 0; i < bank_irqs[b]; i++) {
|
|
@ -0,0 +1,20 @@
|
|||
From 4bff078f28e6a2d55d18e06c0a92b0b78b8ea6cb Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 30 Jun 2015 14:12:42 +0100
|
||||
Subject: [PATCH 008/127] 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
|
||||
@@ -509,6 +509,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];
|
|
@ -0,0 +1,22 @@
|
|||
From 91ea61bbf9285586d27442dc3b85ea34805ccf38 Mon Sep 17 00:00:00 2001
|
||||
From: notro <notro@tronnes.org>
|
||||
Date: Thu, 10 Jul 2014 13:59:47 +0200
|
||||
Subject: [PATCH 009/127] 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
|
||||
@@ -373,7 +373,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,
|
||||
};
|
|
@ -0,0 +1,146 @@
|
|||
From 15367f46e17775c4d736ed1cfc318218362c6a4d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 24 Feb 2015 13:40:50 +0000
|
||||
Subject: [PATCH 010/127] 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];
|
||||
};
|
||||
|
||||
@@ -378,17 +379,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;
|
||||
@@ -396,7 +396,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,
|
||||
@@ -985,8 +1008,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);
|
||||
@@ -1001,10 +1022,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);
|
||||
@@ -1062,6 +1088,7 @@ static struct platform_driver bcm2835_pi
|
||||
.remove = bcm2835_pinctrl_remove,
|
||||
.driver = {
|
||||
.name = MODULE_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
.of_match_table = bcm2835_pinctrl_match,
|
||||
},
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
From 167da31b9a7d3111c83993e4d614bb95bbefdcbb Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 26 Feb 2015 09:58:22 +0000
|
||||
Subject: [PATCH 011/127] 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
|
||||
@@ -1029,6 +1029,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;
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
From bc9d2c297e886dfcc340414a61de970942ad7319 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 24 Jun 2015 14:10:44 +0100
|
||||
Subject: [PATCH 012/127] 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
|
||||
@@ -688,6 +688,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
|
||||
*/
|
||||
@@ -704,15 +706,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",
|
|
@ -0,0 +1,58 @@
|
|||
From e04c4837cde13f4782fc5a274599f580d8a29715 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 013/127] 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
|
||||
@@ -17,12 +17,16 @@
|
||||
#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>
|
||||
|
||||
static void __init bcm2835_init(void)
|
||||
{
|
||||
+ struct device_node *np = of_find_node_by_path("/system");
|
||||
+ u32 val;
|
||||
+ u64 val64;
|
||||
int ret;
|
||||
|
||||
bcm2835_init_clocks();
|
||||
@@ -33,6 +37,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[] = {
|
|
@ -0,0 +1,65 @@
|
|||
From c8225021ad8a8e8d2b4560bed644c5552f9f6684 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 16:44:05 +0200
|
||||
Subject: [PATCH 014/127] bcm2835-i2s: get base address for DMA from devicetree
|
||||
|
||||
Code copied from spi-bcm2835. Get physical address from devicetree
|
||||
instead of using hardcoded constant.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 20 ++++++++++++--------
|
||||
1 file changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
+#include <linux/of_address.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
@@ -158,10 +159,6 @@ static const unsigned int bcm2835_clk_fr
|
||||
#define BCM2835_I2S_INT_RXR BIT(1)
|
||||
#define BCM2835_I2S_INT_TXW BIT(0)
|
||||
|
||||
-/* I2S DMA interface */
|
||||
-/* FIXME: Needs IOMMU support */
|
||||
-#define BCM2835_VCMMU_SHIFT (0x7E000000 - 0x20000000)
|
||||
-
|
||||
/* General device struct */
|
||||
struct bcm2835_i2s_dev {
|
||||
struct device *dev;
|
||||
@@ -791,6 +788,15 @@ static int bcm2835_i2s_probe(struct plat
|
||||
int ret;
|
||||
struct regmap *regmap[2];
|
||||
struct resource *mem[2];
|
||||
+ const __be32 *addr;
|
||||
+ dma_addr_t dma_reg_base;
|
||||
+
|
||||
+ addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
|
||||
+ if (!addr) {
|
||||
+ dev_err(&pdev->dev, "could not get DMA-register address\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ dma_reg_base = be32_to_cpup(addr);
|
||||
|
||||
/* Request both ioareas */
|
||||
for (i = 0; i <= 1; i++) {
|
||||
@@ -817,12 +823,10 @@ static int bcm2835_i2s_probe(struct plat
|
||||
|
||||
/* Set the DMA address */
|
||||
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
|
||||
- (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
|
||||
- + BCM2835_VCMMU_SHIFT;
|
||||
+ dma_reg_base + BCM2835_I2S_FIFO_A_REG;
|
||||
|
||||
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
|
||||
- (dma_addr_t)mem[0]->start + BCM2835_I2S_FIFO_A_REG
|
||||
- + BCM2835_VCMMU_SHIFT;
|
||||
+ dma_reg_base + BCM2835_I2S_FIFO_A_REG;
|
||||
|
||||
/* Set the bus width */
|
||||
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
|
|
@ -0,0 +1,79 @@
|
|||
From 328b2e8b8a38fe62431c2ad5ae22cee31740b10d Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:21:16 +0200
|
||||
Subject: [PATCH 015/127] bcm2835-i2s: add 24bit support, update bclk_ratio to
|
||||
more correct values
|
||||
|
||||
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
|
||||
|
||||
RPi commit 62c05a0b5328d9376d39c9e74da10b8a2465c234 ("ASoC: BCM2708:
|
||||
Add 24 bit support")
|
||||
|
||||
This adds 24 bit support to the I2S driver of the BCM2708.
|
||||
Besides enabling the 24 bit flags, it includes two bug fixes:
|
||||
|
||||
MMAP is not supported. Claiming this leads to strange issues
|
||||
when the format of driver and file do not match.
|
||||
|
||||
The datasheet states that the width extension bit should be set
|
||||
for widths greater than 24, but greater or equal would be correct.
|
||||
This follows from the definition of the width field.
|
||||
|
||||
Signed-off-by: Florian Meier <florian.meier@koalo.de>
|
||||
|
||||
RPi commit 3e8c672bc4e92d457aa4654bbb4cfd79a18a2327 ("bcm2708-i2s:
|
||||
Update bclk_ratio to more correct values")
|
||||
|
||||
Discussion about blck_ratio affecting sound quality:
|
||||
https://github.com/raspberrypi/linux/issues/681
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -340,11 +340,15 @@ static int bcm2835_i2s_hw_params(struct
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
data_length = 16;
|
||||
- bclk_ratio = 40;
|
||||
+ bclk_ratio = 50;
|
||||
+ break;
|
||||
+ case SNDRV_PCM_FORMAT_S24_LE:
|
||||
+ data_length = 24;
|
||||
+ bclk_ratio = 50;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
data_length = 32;
|
||||
- bclk_ratio = 80;
|
||||
+ bclk_ratio = 100;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -420,7 +424,7 @@ static int bcm2835_i2s_hw_params(struct
|
||||
/* Setup the frame format */
|
||||
format = BCM2835_I2S_CHEN;
|
||||
|
||||
- if (data_length > 24)
|
||||
+ if (data_length >= 24)
|
||||
format |= BCM2835_I2S_CHWEX;
|
||||
|
||||
format |= BCM2835_I2S_CHWID((data_length-8)&0xf);
|
||||
@@ -711,6 +715,7 @@ static struct snd_soc_dai_driver bcm2835
|
||||
.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
|
||||
},
|
||||
.capture = {
|
||||
@@ -718,6 +723,7 @@ static struct snd_soc_dai_driver bcm2835
|
||||
.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
|
||||
},
|
||||
.ops = &bcm2835_i2s_dai_ops,
|
|
@ -0,0 +1,54 @@
|
|||
From fce554c6331b34458db54722cb06eb517a32b305 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:25:51 +0200
|
||||
Subject: [PATCH 016/127] bcm2835-i2s: setup clock only if CPU is clock master
|
||||
|
||||
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
|
||||
|
||||
RPi commit c14827ecdaa36607f6110f9ce8df96e698672191 ("bcm2708: Allow
|
||||
option card devices to be configured via DT")
|
||||
|
||||
Original work by Zoltan Szenczi, committed to RPi tree by
|
||||
Phil Elwell.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 28 +++++++++++++++++++---------
|
||||
1 file changed, 19 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -411,15 +411,25 @@ static int bcm2835_i2s_hw_params(struct
|
||||
divf = dividend & BCM2835_CLK_DIVF_MASK;
|
||||
}
|
||||
|
||||
- /* Set clock divider */
|
||||
- regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG, BCM2835_CLK_PASSWD
|
||||
- | BCM2835_CLK_DIVI(divi)
|
||||
- | BCM2835_CLK_DIVF(divf));
|
||||
+ /* Clock should only be set up here if CPU is clock master */
|
||||
+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
+ case SND_SOC_DAIFMT_CBS_CFS:
|
||||
+ case SND_SOC_DAIFMT_CBS_CFM:
|
||||
+ /* Set clock divider */
|
||||
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMDIV_REG,
|
||||
+ BCM2835_CLK_PASSWD
|
||||
+ | BCM2835_CLK_DIVI(divi)
|
||||
+ | BCM2835_CLK_DIVF(divf));
|
||||
|
||||
- /* Setup clock, but don't start it yet */
|
||||
- regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG, BCM2835_CLK_PASSWD
|
||||
- | BCM2835_CLK_MASH(mash)
|
||||
- | BCM2835_CLK_SRC(clk_src));
|
||||
+ /* Setup clock, but don't start it yet */
|
||||
+ regmap_write(dev->clk_regmap, BCM2835_CLK_PCMCTL_REG,
|
||||
+ BCM2835_CLK_PASSWD
|
||||
+ | BCM2835_CLK_MASH(mash)
|
||||
+ | BCM2835_CLK_SRC(clk_src));
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
|
||||
/* Setup the frame format */
|
||||
format = BCM2835_I2S_CHEN;
|
|
@ -0,0 +1,36 @@
|
|||
From 45995262bd8d5194e9430d2a826c84ed28c408eb Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:49:51 +0200
|
||||
Subject: [PATCH 017/127] bcm2835-i2s: Eliminate debugfs directory error
|
||||
|
||||
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
|
||||
|
||||
RPi commit fd7d7a3dbe9262d16971ef81c234ed28c6499dd7 ("bcm2708:
|
||||
Eliminate i2s debugfs directory error")
|
||||
|
||||
Qualify the two regmap ranges uses by bcm2708-i2s ('-i2s' and '-clk')
|
||||
to avoid the name clash when registering debugfs entries.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -782,6 +782,7 @@ static const struct regmap_config bcm283
|
||||
.precious_reg = bcm2835_i2s_precious_reg,
|
||||
.volatile_reg = bcm2835_i2s_volatile_reg,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
+ .name = "i2s",
|
||||
},
|
||||
{
|
||||
.reg_bits = 32,
|
||||
@@ -790,6 +791,7 @@ static const struct regmap_config bcm283
|
||||
.max_register = BCM2835_CLK_PCMDIV_REG,
|
||||
.volatile_reg = bcm2835_clk_volatile_reg,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
+ .name = "clk",
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
From b58d4ef09eca4674d1530f0c8e1ca074b269ebea Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:35:20 +0200
|
||||
Subject: [PATCH 018/127] bcm2835-i2s: Register PCM device
|
||||
|
||||
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
|
||||
|
||||
RPi commit ba46b4935a23aa2caac1855ead52a035d4776680 ("ASoC: Add
|
||||
support for BCM2708")
|
||||
|
||||
This driver adds support for digital audio (I2S)
|
||||
for the BCM2708 SoC that is used by the
|
||||
Raspberry Pi. External audio codecs can be
|
||||
connected to the Raspberry Pi via P5 header.
|
||||
|
||||
It relies on cyclic DMA engine support for BCM2708.
|
||||
|
||||
Signed-off-by: Florian Meier <florian.meier@koalo.de>
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 23 ++++++++++++++++++++++-
|
||||
1 file changed, 22 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -799,6 +799,25 @@ static const struct snd_soc_component_dr
|
||||
.name = "bcm2835-i2s-comp",
|
||||
};
|
||||
|
||||
+static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
|
||||
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
+ SNDRV_PCM_INFO_JOINT_DUPLEX,
|
||||
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S24_LE |
|
||||
+ SNDRV_PCM_FMTBIT_S32_LE,
|
||||
+ .period_bytes_min = 32,
|
||||
+ .period_bytes_max = 64 * PAGE_SIZE,
|
||||
+ .periods_min = 2,
|
||||
+ .periods_max = 255,
|
||||
+ .buffer_bytes_max = 128 * PAGE_SIZE,
|
||||
+};
|
||||
+
|
||||
+static const struct snd_dmaengine_pcm_config bcm2835_dmaengine_pcm_config = {
|
||||
+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
|
||||
+ .pcm_hardware = &bcm2835_pcm_hardware,
|
||||
+ .prealloc_buffer_size = 256 * PAGE_SIZE,
|
||||
+};
|
||||
+
|
||||
static int bcm2835_i2s_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835_i2s_dev *dev;
|
||||
@@ -870,7 +889,9 @@ static int bcm2835_i2s_probe(struct plat
|
||||
return ret;
|
||||
}
|
||||
|
||||
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
|
||||
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev,
|
||||
+ &bcm2835_dmaengine_pcm_config,
|
||||
+ SND_DMAENGINE_PCM_FLAG_COMPAT);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Could not register PCM: %d\n", ret);
|
||||
return ret;
|
|
@ -0,0 +1,44 @@
|
|||
From 61f155e164c5dbfa5cec9a099e4aa802c2155423 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:55:21 +0200
|
||||
Subject: [PATCH 019/127] bcm2835-i2s: Enable MMAP support via a DT property
|
||||
|
||||
Code ported from bcm2708-i2s driver in Raspberry Pi tree.
|
||||
|
||||
RPi commit 7ee829fd77a30127db5d0b3c7d79b8718166e568 ("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
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/bcm2835-i2s.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/sound/soc/bcm/bcm2835-i2s.c
|
||||
+++ b/sound/soc/bcm/bcm2835-i2s.c
|
||||
@@ -799,7 +799,7 @@ static const struct snd_soc_component_dr
|
||||
.name = "bcm2835-i2s-comp",
|
||||
};
|
||||
|
||||
-static const struct snd_pcm_hardware bcm2835_pcm_hardware = {
|
||||
+static struct snd_pcm_hardware bcm2835_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_JOINT_DUPLEX,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE |
|
||||
@@ -835,6 +835,11 @@ static int bcm2835_i2s_probe(struct plat
|
||||
}
|
||||
dma_reg_base = be32_to_cpup(addr);
|
||||
|
||||
+ if (of_property_read_bool(pdev->dev.of_node, "brcm,enable-mmap"))
|
||||
+ bcm2835_pcm_hardware.info |=
|
||||
+ SNDRV_PCM_INFO_MMAP |
|
||||
+ SNDRV_PCM_INFO_MMAP_VALID;
|
||||
+
|
||||
/* Request both ioareas */
|
||||
for (i = 0; i <= 1; i++) {
|
||||
void __iomem *base;
|
|
@ -0,0 +1,320 @@
|
|||
From 780a1039ccfd293d583742a4f2326997b15f5aff Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Thu, 9 Apr 2015 12:34:11 +0200
|
||||
Subject: [PATCH 020/127] dmaengine: bcm2835: Add slave dma support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add slave transfer capability to BCM2835 dmaengine driver.
|
||||
This patch is pulled from the bcm2708-dmaengine driver in the
|
||||
Raspberry Pi repo. The work was done by Gellert Weisz.
|
||||
|
||||
Tested using the bcm2835-mmc driver from the same repo.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/dma/bcm2835-dma.c | 206 ++++++++++++++++++++++++++++++++++++++++++----
|
||||
1 file changed, 192 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -1,11 +1,10 @@
|
||||
/*
|
||||
* BCM2835 DMA engine support
|
||||
*
|
||||
- * This driver only supports cyclic DMA transfers
|
||||
- * as needed for the I2S module.
|
||||
- *
|
||||
* Author: Florian Meier <florian.meier@koalo.de>
|
||||
* Copyright 2013
|
||||
+ * Gellert Weisz <gellert@raspberrypi.org>
|
||||
+ * Copyright 2013-2014
|
||||
*
|
||||
* Based on
|
||||
* OMAP DMAengine support by Russell King
|
||||
@@ -95,6 +94,8 @@ struct bcm2835_desc {
|
||||
size_t size;
|
||||
};
|
||||
|
||||
+#define BCM2835_DMA_WAIT_CYCLES 0 /* Slow down DMA transfers: 0-31 */
|
||||
+
|
||||
#define BCM2835_DMA_CS 0x00
|
||||
#define BCM2835_DMA_ADDR 0x04
|
||||
#define BCM2835_DMA_SOURCE_AD 0x0c
|
||||
@@ -111,12 +112,16 @@ struct bcm2835_desc {
|
||||
#define BCM2835_DMA_RESET BIT(31) /* WO, self clearing */
|
||||
|
||||
#define BCM2835_DMA_INT_EN BIT(0)
|
||||
+#define BCM2835_DMA_WAIT_RESP BIT(3)
|
||||
#define BCM2835_DMA_D_INC BIT(4)
|
||||
+#define BCM2835_DMA_D_WIDTH BIT(5)
|
||||
#define BCM2835_DMA_D_DREQ BIT(6)
|
||||
#define BCM2835_DMA_S_INC BIT(8)
|
||||
+#define BCM2835_DMA_S_WIDTH BIT(9)
|
||||
#define BCM2835_DMA_S_DREQ BIT(10)
|
||||
|
||||
#define BCM2835_DMA_PER_MAP(x) ((x) << 16)
|
||||
+#define BCM2835_DMA_WAITS(x) (((x) & 0x1f) << 21)
|
||||
|
||||
#define BCM2835_DMA_DATA_TYPE_S8 1
|
||||
#define BCM2835_DMA_DATA_TYPE_S16 2
|
||||
@@ -130,6 +135,14 @@ struct bcm2835_desc {
|
||||
#define BCM2835_DMA_CHAN(n) ((n) << 8) /* Base address */
|
||||
#define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
|
||||
|
||||
+#define MAX_NORMAL_TRANSFER SZ_1G
|
||||
+/*
|
||||
+ * Max length on a Lite channel is 65535 bytes.
|
||||
+ * DMA handles byte-enables on SDRAM reads and writes even on 128-bit accesses,
|
||||
+ * but byte-enables don't exist on peripheral addresses, so align to 32-bit.
|
||||
+ */
|
||||
+#define MAX_LITE_TRANSFER (SZ_64K - 4)
|
||||
+
|
||||
static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
|
||||
{
|
||||
return container_of(d, struct bcm2835_dmadev, ddev);
|
||||
@@ -226,12 +239,18 @@ static irqreturn_t bcm2835_dma_callback(
|
||||
d = c->desc;
|
||||
|
||||
if (d) {
|
||||
- /* TODO Only works for cyclic DMA */
|
||||
- vchan_cyclic_callback(&d->vd);
|
||||
- }
|
||||
+ if (c->cyclic) {
|
||||
+ vchan_cyclic_callback(&d->vd);
|
||||
|
||||
- /* Keep the DMA engine running */
|
||||
- writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
|
||||
+ /* Keep the DMA engine running */
|
||||
+ writel(BCM2835_DMA_ACTIVE,
|
||||
+ c->chan_base + BCM2835_DMA_CS);
|
||||
+
|
||||
+ } else {
|
||||
+ vchan_cookie_complete(&c->desc->vd);
|
||||
+ bcm2835_dma_start_desc(c);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
spin_unlock_irqrestore(&c->vc.lock, flags);
|
||||
|
||||
@@ -339,8 +358,6 @@ static void bcm2835_dma_issue_pending(st
|
||||
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
|
||||
unsigned long flags;
|
||||
|
||||
- c->cyclic = true; /* Nothing else is implemented */
|
||||
-
|
||||
spin_lock_irqsave(&c->vc.lock, flags);
|
||||
if (vchan_issue_pending(&c->vc) && !c->desc)
|
||||
bcm2835_dma_start_desc(c);
|
||||
@@ -358,7 +375,7 @@ static struct dma_async_tx_descriptor *b
|
||||
struct bcm2835_desc *d;
|
||||
dma_addr_t dev_addr;
|
||||
unsigned int es, sync_type;
|
||||
- unsigned int frame;
|
||||
+ unsigned int frame, max_size;
|
||||
int i;
|
||||
|
||||
/* Grab configuration */
|
||||
@@ -393,7 +410,12 @@ static struct dma_async_tx_descriptor *b
|
||||
|
||||
d->c = c;
|
||||
d->dir = direction;
|
||||
- d->frames = buf_len / period_len;
|
||||
+ if (c->ch >= 8) /* LITE channel */
|
||||
+ max_size = MAX_LITE_TRANSFER;
|
||||
+ else
|
||||
+ max_size = MAX_NORMAL_TRANSFER;
|
||||
+ period_len = min(period_len, max_size);
|
||||
+ d->frames = (buf_len - 1) / (period_len + 1);
|
||||
|
||||
d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
|
||||
if (!d->cb_list) {
|
||||
@@ -441,17 +463,171 @@ static struct dma_async_tx_descriptor *b
|
||||
BCM2835_DMA_PER_MAP(c->dreq);
|
||||
|
||||
/* Length of a frame */
|
||||
- control_block->length = period_len;
|
||||
+ if (frame != d->frames - 1)
|
||||
+ control_block->length = period_len;
|
||||
+ else
|
||||
+ control_block->length = buf_len - (d->frames - 1) *
|
||||
+ period_len;
|
||||
d->size += control_block->length;
|
||||
|
||||
/*
|
||||
* Next block is the next frame.
|
||||
- * This DMA engine driver currently only supports cyclic DMA.
|
||||
+ * This function is called on cyclic DMA transfers.
|
||||
* Therefore, wrap around at number of frames.
|
||||
*/
|
||||
control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr;
|
||||
}
|
||||
|
||||
+ c->cyclic = true;
|
||||
+
|
||||
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
|
||||
+}
|
||||
+
|
||||
+static struct dma_async_tx_descriptor *
|
||||
+bcm2835_dma_prep_slave_sg(struct dma_chan *chan,
|
||||
+ struct scatterlist *sgl,
|
||||
+ unsigned int sg_len,
|
||||
+ enum dma_transfer_direction direction,
|
||||
+ unsigned long flags, void *context)
|
||||
+{
|
||||
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
|
||||
+ enum dma_slave_buswidth dev_width;
|
||||
+ struct bcm2835_desc *d;
|
||||
+ dma_addr_t dev_addr;
|
||||
+ struct scatterlist *sgent;
|
||||
+ unsigned int i, sync_type, split_cnt, max_size;
|
||||
+
|
||||
+ if (!is_slave_direction(direction)) {
|
||||
+ dev_err(chan->device->dev, "direction not supported\n");
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (direction == DMA_DEV_TO_MEM) {
|
||||
+ dev_addr = c->cfg.src_addr;
|
||||
+ dev_width = c->cfg.src_addr_width;
|
||||
+ sync_type = BCM2835_DMA_S_DREQ;
|
||||
+ } else {
|
||||
+ dev_addr = c->cfg.dst_addr;
|
||||
+ dev_width = c->cfg.dst_addr_width;
|
||||
+ sync_type = BCM2835_DMA_D_DREQ;
|
||||
+ }
|
||||
+
|
||||
+ /* Bus width translates to the element size (ES) */
|
||||
+ switch (dev_width) {
|
||||
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(chan->device->dev, "buswidth not supported: %i\n",
|
||||
+ dev_width);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ /* Allocate and setup the descriptor. */
|
||||
+ d = kzalloc(sizeof(*d), GFP_NOWAIT);
|
||||
+ if (!d)
|
||||
+ return NULL;
|
||||
+
|
||||
+ d->dir = direction;
|
||||
+
|
||||
+ if (c->ch >= 8) /* LITE channel */
|
||||
+ max_size = MAX_LITE_TRANSFER;
|
||||
+ else
|
||||
+ max_size = MAX_NORMAL_TRANSFER;
|
||||
+
|
||||
+ /*
|
||||
+ * Store the length of the SG list in d->frames
|
||||
+ * taking care to account for splitting up transfers
|
||||
+ * too large for a LITE channel
|
||||
+ */
|
||||
+ d->frames = 0;
|
||||
+ for_each_sg(sgl, sgent, sg_len, i) {
|
||||
+ unsigned int len = sg_dma_len(sgent);
|
||||
+
|
||||
+ d->frames += len / max_size + 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Allocate memory for control blocks */
|
||||
+ d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
|
||||
+ d->control_block_base = dma_zalloc_coherent(chan->device->dev,
|
||||
+ d->control_block_size, &d->control_block_base_phys,
|
||||
+ GFP_NOWAIT);
|
||||
+ if (!d->control_block_base) {
|
||||
+ kfree(d);
|
||||
+ return NULL;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Iterate over all SG entries, create a control block
|
||||
+ * for each frame and link them together.
|
||||
+ * Count the number of times an SG entry had to be split
|
||||
+ * as a result of using a LITE channel
|
||||
+ */
|
||||
+ split_cnt = 0;
|
||||
+
|
||||
+ for_each_sg(sgl, sgent, sg_len, i) {
|
||||
+ unsigned int j;
|
||||
+ dma_addr_t addr = sg_dma_address(sgent);
|
||||
+ unsigned int len = sg_dma_len(sgent);
|
||||
+
|
||||
+ for (j = 0; j < len; j += max_size) {
|
||||
+ struct bcm2835_dma_cb *control_block =
|
||||
+ &d->control_block_base[i + split_cnt];
|
||||
+
|
||||
+ /* Setup addresses */
|
||||
+ if (d->dir == DMA_DEV_TO_MEM) {
|
||||
+ control_block->info = BCM2835_DMA_D_INC |
|
||||
+ BCM2835_DMA_D_WIDTH |
|
||||
+ BCM2835_DMA_S_DREQ;
|
||||
+ control_block->src = dev_addr;
|
||||
+ control_block->dst = addr + (dma_addr_t)j;
|
||||
+ } else {
|
||||
+ control_block->info = BCM2835_DMA_S_INC |
|
||||
+ BCM2835_DMA_S_WIDTH |
|
||||
+ BCM2835_DMA_D_DREQ;
|
||||
+ control_block->src = addr + (dma_addr_t)j;
|
||||
+ control_block->dst = dev_addr;
|
||||
+ }
|
||||
+
|
||||
+ /* Common part */
|
||||
+ control_block->info |=
|
||||
+ BCM2835_DMA_WAITS(BCM2835_DMA_WAIT_CYCLES);
|
||||
+ control_block->info |= BCM2835_DMA_WAIT_RESP;
|
||||
+
|
||||
+ /* Enable */
|
||||
+ if (i == sg_len - 1 && len - j <= max_size)
|
||||
+ control_block->info |= BCM2835_DMA_INT_EN;
|
||||
+
|
||||
+ /* Setup synchronization */
|
||||
+ if (sync_type)
|
||||
+ control_block->info |= sync_type;
|
||||
+
|
||||
+ /* Setup DREQ channel */
|
||||
+ if (c->dreq)
|
||||
+ control_block->info |=
|
||||
+ BCM2835_DMA_PER_MAP(c->dreq);
|
||||
+
|
||||
+ /* Length of a frame */
|
||||
+ control_block->length = min(len - j, max_size);
|
||||
+ d->size += control_block->length;
|
||||
+
|
||||
+ if (i < sg_len - 1 || len - j > max_size) {
|
||||
+ /* Next block is the next frame. */
|
||||
+ control_block->next =
|
||||
+ d->control_block_base_phys +
|
||||
+ sizeof(struct bcm2835_dma_cb) *
|
||||
+ (i + split_cnt + 1);
|
||||
+ } else {
|
||||
+ /* Next block is empty. */
|
||||
+ control_block->next = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (len - j > max_size)
|
||||
+ split_cnt++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ c->cyclic = false;
|
||||
+
|
||||
return vchan_tx_prep(&c->vc, &d->vd, flags);
|
||||
error_cb:
|
||||
i--;
|
||||
@@ -620,6 +796,7 @@ static int bcm2835_dma_probe(struct plat
|
||||
od->ddev.device_tx_status = bcm2835_dma_tx_status;
|
||||
od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
|
||||
od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
|
||||
+ od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg;
|
||||
od->ddev.device_config = bcm2835_dma_slave_config;
|
||||
od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
|
||||
od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
@@ -708,4 +885,5 @@ module_platform_driver(bcm2835_dma_drive
|
||||
MODULE_ALIAS("platform:bcm2835-dma");
|
||||
MODULE_DESCRIPTION("BCM2835 DMA engine driver");
|
||||
MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
|
||||
+MODULE_AUTHOR("Gellert Weisz <gellert@raspberrypi.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,29 @@
|
|||
From 6ff0d626e7d84df71f6bc75e2c5ed35c42858bcc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Sat, 3 Oct 2015 15:58:59 +0200
|
||||
Subject: [PATCH 021/127] dmaengine: bcm2835: set residue_granularity field
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
bcm2835-dma supports residue reporting at burst level but didn't report
|
||||
this via the residue_granularity field.
|
||||
|
||||
Without this field set properly we get playback issues with I2S cards.
|
||||
|
||||
[by HiassofT, taken from bcm2708-dmaengine]
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/dma/bcm2835-dma.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -802,6 +802,7 @@ static int bcm2835_dma_probe(struct plat
|
||||
od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
|
||||
od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
|
||||
+ od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
|
||||
od->ddev.dev = &pdev->dev;
|
||||
INIT_LIST_HEAD(&od->ddev.channels);
|
||||
spin_lock_init(&od->lock);
|
|
@ -0,0 +1,98 @@
|
|||
From 16dc5e0535e48ce3e9c6995c87118e9e7b5b775a Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Sat, 3 Oct 2015 22:22:55 +0200
|
||||
Subject: [PATCH 022/127] dmaengine: bcm2835: Load driver early and support
|
||||
legacy API
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Load driver early since at least bcm2708_fb doesn't support deferred
|
||||
probing and even if it did, we don't want the video driver deferred.
|
||||
Support the legacy DMA API which is needed by bcm2708_fb.
|
||||
Don't mask out channel 2.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/dma/Kconfig | 2 +-
|
||||
drivers/dma/bcm2835-dma.c | 30 ++++++++++++++++++++++++------
|
||||
2 files changed, 25 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/dma/Kconfig
|
||||
+++ b/drivers/dma/Kconfig
|
||||
@@ -108,7 +108,7 @@ config COH901318
|
||||
|
||||
config DMA_BCM2835
|
||||
tristate "BCM2835 DMA engine support"
|
||||
- depends on ARCH_BCM2835
|
||||
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
|
||||
select DMA_ENGINE
|
||||
select DMA_VIRTUAL_CHANNELS
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
+#include <linux/platform_data/dma-bcm2708.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
@@ -786,6 +787,10 @@ static int bcm2835_dma_probe(struct plat
|
||||
if (IS_ERR(base))
|
||||
return PTR_ERR(base);
|
||||
|
||||
+ rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK);
|
||||
+ if (rc)
|
||||
+ dev_err(&pdev->dev, "Failed to initialize the legacy API\n");
|
||||
+
|
||||
od->base = base;
|
||||
|
||||
dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
|
||||
@@ -818,11 +823,8 @@ static int bcm2835_dma_probe(struct plat
|
||||
goto err_no_dma;
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Do not use the FIQ and BULK channels,
|
||||
- * because they are used by the GPU.
|
||||
- */
|
||||
- chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK);
|
||||
+ /* Channel 0 is used by the legacy API */
|
||||
+ chans_available &= ~BCM2835_DMA_BULK_MASK;
|
||||
|
||||
for (i = 0; i < pdev->num_resources; i++) {
|
||||
irq = platform_get_irq(pdev, i);
|
||||
@@ -866,6 +868,7 @@ static int bcm2835_dma_remove(struct pla
|
||||
{
|
||||
struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
|
||||
|
||||
+ bcm_dmaman_remove(pdev);
|
||||
dma_async_device_unregister(&od->ddev);
|
||||
bcm2835_dma_free(od);
|
||||
|
||||
@@ -881,7 +884,22 @@ static struct platform_driver bcm2835_dm
|
||||
},
|
||||
};
|
||||
|
||||
-module_platform_driver(bcm2835_dma_driver);
|
||||
+static int bcm2835_dma_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2835_dma_driver);
|
||||
+}
|
||||
+
|
||||
+static void bcm2835_dma_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&bcm2835_dma_driver);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Load after serial driver (arch_initcall) so we see the messages if it fails,
|
||||
+ * but before drivers (module_init) that need a DMA channel.
|
||||
+ */
|
||||
+subsys_initcall(bcm2835_dma_init);
|
||||
+module_exit(bcm2835_dma_exit);
|
||||
|
||||
MODULE_ALIAS("platform:bcm2835-dma");
|
||||
MODULE_DESCRIPTION("BCM2835 DMA engine driver");
|
|
@ -0,0 +1,21 @@
|
|||
From 50eef5c715b894683aebf81332c82426dc10f8cb Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 10 Oct 2015 12:29:18 +0200
|
||||
Subject: [PATCH 023/127] bcm2835-dma: Fix dreq not set for slave transfers
|
||||
|
||||
Set dreq to slave_id if it is not set like in bcm2708-dmaengine.
|
||||
---
|
||||
drivers/dma/bcm2835-dma.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -657,6 +657,8 @@ static int bcm2835_dma_slave_config(stru
|
||||
}
|
||||
|
||||
c->cfg = *cfg;
|
||||
+ if (!c->dreq)
|
||||
+ c->dreq = cfg->slave_id;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
From c7e464c38d38ad59899c94dfad6c3455c18f7d76 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 12:28:30 +0200
|
||||
Subject: [PATCH 024/127] bcm2835-dma: Limit cyclic transfers on lite channels
|
||||
to 32k
|
||||
|
||||
Transfers larger than 32k cause repeated clicking with I2S soundcards.
|
||||
The exact reason is yet unknown, so limit to 32k as bcm2708-dmaengine
|
||||
did as an intermediate fix.
|
||||
---
|
||||
drivers/dma/bcm2835-dma.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -144,6 +144,12 @@ struct bcm2835_desc {
|
||||
*/
|
||||
#define MAX_LITE_TRANSFER (SZ_64K - 4)
|
||||
|
||||
+/*
|
||||
+ * Transfers larger than 32k cause issues with the bcm2708-i2s driver,
|
||||
+ * so limit transfer size to 32k as bcm2708-dmaengine did.
|
||||
+ */
|
||||
+#define MAX_CYCLIC_LITE_TRANSFER SZ_32K
|
||||
+
|
||||
static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
|
||||
{
|
||||
return container_of(d, struct bcm2835_dmadev, ddev);
|
||||
@@ -412,7 +418,7 @@ static struct dma_async_tx_descriptor *b
|
||||
d->c = c;
|
||||
d->dir = direction;
|
||||
if (c->ch >= 8) /* LITE channel */
|
||||
- max_size = MAX_LITE_TRANSFER;
|
||||
+ max_size = MAX_CYCLIC_LITE_TRANSFER;
|
||||
else
|
||||
max_size = MAX_NORMAL_TRANSFER;
|
||||
period_len = min(period_len, max_size);
|
|
@ -0,0 +1,57 @@
|
|||
From 34cb40cb97cd3080d3d0f314b2b063939b90c069 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Sat, 15 Aug 2015 20:50:02 +0200
|
||||
Subject: [PATCH 025/127] bcm2835: Add support for uart1
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This is a hack until a proper solution is agreed upon.
|
||||
Martin Sperl is doing some work in this area.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
arch/arm/mach-bcm/board_bcm2835.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
--- a/arch/arm/mach-bcm/board_bcm2835.c
|
||||
+++ b/arch/arm/mach-bcm/board_bcm2835.c
|
||||
@@ -22,6 +22,29 @@
|
||||
#include <asm/mach/arch.h>
|
||||
#include <asm/mach/map.h>
|
||||
|
||||
+/* Use this hack until a proper solution is agreed upon */
|
||||
+static void __init bcm2835_init_uart1(void)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+
|
||||
+ np = of_find_compatible_node(NULL, NULL, "brcm,bcm2835-aux-uart");
|
||||
+ if (of_device_is_available(np)) {
|
||||
+ np = of_find_compatible_node(NULL, NULL,
|
||||
+ "bcrm,bcm2835-aux-enable");
|
||||
+ if (np) {
|
||||
+ void __iomem *base = of_iomap(np, 0);
|
||||
+
|
||||
+ if (!base) {
|
||||
+ pr_err("bcm2835: Failed enabling Mini UART\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ writel(1, base);
|
||||
+ pr_info("bcm2835: Mini UART enabled\n");
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void __init bcm2835_init(void)
|
||||
{
|
||||
struct device_node *np = of_find_node_by_path("/system");
|
||||
@@ -42,6 +65,8 @@ static void __init bcm2835_init(void)
|
||||
system_rev = val;
|
||||
if (!of_property_read_u64(np, "linux,serial", &val64))
|
||||
system_serial_low = val64;
|
||||
+
|
||||
+ bcm2835_init_uart1();
|
||||
}
|
||||
|
||||
static const char * const bcm2835_compat[] = {
|
|
@ -0,0 +1,62 @@
|
|||
From 40946ea47dd52c827b30d3601f7b393c46fbfcf3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 26 Jun 2015 14:21:20 +0200
|
||||
Subject: [PATCH 026/127] firmware: bcm2835: Add missing property tags
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -63,6 +63,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
|
||||
RPI_FIRMWARE_GET_TURBO = 0x00030009,
|
||||
RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
|
||||
+ RPI_FIRMWARE_GET_STC = 0x0003000b,
|
||||
RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
|
||||
RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
|
||||
RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
|
||||
@@ -72,10 +73,12 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
|
||||
RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
|
||||
RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
|
||||
+ RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021,
|
||||
RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
|
||||
RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
|
||||
RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
|
||||
RPI_FIRMWARE_SET_TURBO = 0x00038009,
|
||||
+ RPI_FIRMWARE_SET_CUSTOMER_OTP = 0x00038021,
|
||||
|
||||
/* Dispmanx TAGS */
|
||||
RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
|
||||
@@ -89,6 +92,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF = 0x0004000f,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
|
||||
@@ -98,6 +102,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VSYNC = 0x0004400e,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
|
||||
@@ -106,6 +111,9 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
|
||||
+
|
||||
+ RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
|
||||
|
||||
RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
|
||||
RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,138 @@
|
|||
From ceefa4e6b0d4b529eed6666120674cccde24d59a Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 11 Nov 2015 21:01:15 +0000
|
||||
Subject: [PATCH 028/127] squash: include ARCH_BCM2708 / ARCH_BCM2709
|
||||
|
||||
---
|
||||
drivers/char/hw_random/Kconfig | 2 +-
|
||||
drivers/mailbox/Kconfig | 2 +-
|
||||
drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++--
|
||||
drivers/pinctrl/Makefile | 1 +
|
||||
drivers/pwm/Kconfig | 2 +-
|
||||
drivers/spi/Kconfig | 2 +-
|
||||
drivers/watchdog/Kconfig | 2 +-
|
||||
sound/soc/bcm/Kconfig | 2 +-
|
||||
8 files changed, 23 insertions(+), 8 deletions(-)
|
||||
|
||||
--- 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
|
||||
--- a/drivers/mailbox/Kconfig
|
||||
+++ b/drivers/mailbox/Kconfig
|
||||
@@ -65,7 +65,7 @@ config ALTERA_MBOX
|
||||
|
||||
config BCM2835_MBOX
|
||||
tristate "BCM2835 Mailbox"
|
||||
- depends on ARCH_BCM2835
|
||||
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
|
||||
help
|
||||
An implementation of the BCM2385 Mailbox. It is used to invoke
|
||||
the services of the Videocore. Say Y here if you want to use the
|
||||
--- a/drivers/mailbox/bcm2835-mailbox.c
|
||||
+++ b/drivers/mailbox/bcm2835-mailbox.c
|
||||
@@ -51,12 +51,15 @@
|
||||
#define MAIL1_WRT (ARM_0_MAIL1 + 0x00)
|
||||
#define MAIL1_STA (ARM_0_MAIL1 + 0x18)
|
||||
|
||||
+/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */
|
||||
+#ifndef ARM_MS_FULL
|
||||
/* Status register: FIFO state. */
|
||||
#define ARM_MS_FULL BIT(31)
|
||||
#define ARM_MS_EMPTY BIT(30)
|
||||
|
||||
/* Configuration register: Enable interrupts. */
|
||||
#define ARM_MC_IHAVEDATAIRQEN BIT(0)
|
||||
+#endif
|
||||
|
||||
struct bcm2835_mbox {
|
||||
void __iomem *regs;
|
||||
@@ -151,7 +154,7 @@ static int bcm2835_mbox_probe(struct pla
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&mbox->lock);
|
||||
|
||||
- ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0),
|
||||
+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
|
||||
bcm2835_mbox_irq, 0, dev_name(dev), mbox);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n",
|
||||
@@ -209,7 +212,18 @@ static struct platform_driver bcm2835_mb
|
||||
.probe = bcm2835_mbox_probe,
|
||||
.remove = bcm2835_mbox_remove,
|
||||
};
|
||||
-module_platform_driver(bcm2835_mbox_driver);
|
||||
+
|
||||
+static int __init bcm2835_mbox_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&bcm2835_mbox_driver);
|
||||
+}
|
||||
+arch_initcall(bcm2835_mbox_init);
|
||||
+
|
||||
+static void __init bcm2835_mbox_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&bcm2835_mbox_driver);
|
||||
+}
|
||||
+module_exit(bcm2835_mbox_exit);
|
||||
|
||||
MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>");
|
||||
MODULE_DESCRIPTION("BCM2835 mailbox IPC driver");
|
||||
--- a/drivers/pinctrl/Makefile
|
||||
+++ b/drivers/pinctrl/Makefile
|
||||
@@ -40,6 +40,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/
|
||||
--- a/drivers/pwm/Kconfig
|
||||
+++ b/drivers/pwm/Kconfig
|
||||
@@ -85,7 +85,7 @@ config PWM_BCM_KONA
|
||||
|
||||
config PWM_BCM2835
|
||||
tristate "BCM2835 PWM support"
|
||||
- depends on ARCH_BCM2835
|
||||
+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709
|
||||
help
|
||||
PWM framework driver for BCM2835 controller (Raspberry Pi)
|
||||
|
||||
--- a/drivers/spi/Kconfig
|
||||
+++ b/drivers/spi/Kconfig
|
||||
@@ -78,7 +78,7 @@ config SPI_ATMEL
|
||||
config SPI_BCM2835
|
||||
tristate "BCM2835 SPI controller"
|
||||
depends on GPIOLIB
|
||||
- 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.
|
||||
--- a/drivers/watchdog/Kconfig
|
||||
+++ b/drivers/watchdog/Kconfig
|
||||
@@ -1291,7 +1291,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/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -1,6 +1,6 @@
|
||||
config SND_BCM2835_SOC_I2S
|
||||
tristate "SoC Audio support for the Broadcom BCM2835 I2S module"
|
||||
- depends on ARCH_BCM2835 || COMPILE_TEST
|
||||
+ depends on ARCH_BCM2835 || MACH_BCM2708 || MACH_BCM2709 || COMPILE_TEST
|
||||
select SND_SOC_GENERIC_DMAENGINE_PCM
|
||||
select REGMAP_MMIO
|
||||
help
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,612 @@
|
|||
From 51d9f11052d8e51931b1c5f816d737e64e1caa22 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Meier <florian.meier@koalo.de>
|
||||
Date: Fri, 22 Nov 2013 14:22:53 +0100
|
||||
Subject: [PATCH 031/127] dmaengine: Add support for BCM2708
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add support for DMA controller of BCM2708 as used in the Raspberry Pi.
|
||||
Currently it only supports cyclic DMA.
|
||||
|
||||
Signed-off-by: Florian Meier <florian.meier@koalo.de>
|
||||
|
||||
dmaengine: expand functionality by supporting scatter/gather transfers sdhci-bcm2708 and dma.c: fix for LITE channels
|
||||
|
||||
DMA: fix cyclic LITE length overflow bug
|
||||
|
||||
dmaengine: bcm2708: Remove chancnt affectations
|
||||
|
||||
Mirror bcm2835-dma.c commit 9eba5536a7434c69d8c185d4bd1c70734d92287d:
|
||||
chancnt is already filled by dma_async_device_register, which uses the channel
|
||||
list to know how much channels there is.
|
||||
|
||||
Since it's already filled, we can safely remove it from the drivers' probe
|
||||
function.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: overwrite dreq only if it is not set
|
||||
|
||||
dreq is set when the DMA channel is fetched from Device Tree.
|
||||
slave_id is set using dmaengine_slave_config().
|
||||
Only overwrite dreq with slave_id if it is not set.
|
||||
|
||||
dreq/slave_id in the cyclic DMA case is not touched, because I don't
|
||||
have hardware to test with.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: do device registration in the board file
|
||||
|
||||
Don't register the device in the driver. Do it in the board file.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: don't restrict DT support to ARCH_BCM2835
|
||||
|
||||
Both ARCH_BCM2835 and ARCH_BCM270x are built with OF now.
|
||||
Add Device Tree support to the non ARCH_BCM2835 case.
|
||||
Use the same driver name regardless of architecture.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
BCM270x_DT: add bcm2835-dma entry
|
||||
|
||||
Add Device Tree entry for bcm2835-dma.
|
||||
The entry doesn't contain any resources since they are handled
|
||||
by the arch/arm/mach-bcm270x/dma.c driver.
|
||||
In non-DT mode, don't add the device in the board file.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
bcm2708-dmaengine: Add debug options
|
||||
|
||||
BCM270x: Add memory and irq resources to dmaengine device and DT
|
||||
|
||||
Prepare for merging of the legacy DMA API arch driver dma.c
|
||||
with bcm2708-dmaengine by adding memory and irq resources both
|
||||
to platform file device and Device Tree node.
|
||||
Don't use BCM_DMAMAN_DRIVER_NAME so we don't have to include mach/dma.h
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Merge with arch dma.c driver and disable dma.c
|
||||
|
||||
Merge the legacy DMA API driver with bcm2708-dmaengine.
|
||||
This is done so we can use bcm2708_fb on ARCH_BCM2835 (mailbox
|
||||
driver is also needed).
|
||||
|
||||
Changes to the dma.c code:
|
||||
- Use BIT() macro.
|
||||
- Cutdown some comments to one line.
|
||||
- Add mutex to vc_dmaman and use this, since the dev lock is locked
|
||||
during probing of the engine part.
|
||||
- Add global g_dmaman variable since drvdata is used by the engine part.
|
||||
- Restructure for readability:
|
||||
vc_dmaman_chan_alloc()
|
||||
vc_dmaman_chan_free()
|
||||
bcm_dma_chan_free()
|
||||
- Restructure bcm_dma_chan_alloc() to simplify error handling.
|
||||
- Use device irq resources instead of hardcoded bcm_dma_irqs table.
|
||||
- Remove dev_dmaman_register() and code it directly.
|
||||
- Remove dev_dmaman_deregister() and code it directly.
|
||||
- Simplify bcm_dmaman_probe() using devm_* functions.
|
||||
- Get dmachans from DT if available.
|
||||
- Keep 'dma.dmachans' module argument name for backwards compatibility.
|
||||
|
||||
Make it available on ARCH_BCM2835 as well.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: set residue_granularity field
|
||||
|
||||
bcm2708-dmaengine supports residue reporting at burst level
|
||||
but didn't report this via the residue_granularity field.
|
||||
|
||||
Without this field set properly we get playback issues with I2S cards.
|
||||
|
||||
dmaengine: bcm2708-dmaengine: Fix memory leak when stopping a running transfer
|
||||
|
||||
bcm2708-dmaengine: Use more DMA channels (but not 12)
|
||||
|
||||
1) Only the bcm2708_fb drivers uses the legacy DMA API, and
|
||||
it requires a BULK-capable channel, so all other types
|
||||
(FAST, NORMAL and LITE) can be made available to the regular
|
||||
DMA API.
|
||||
|
||||
2) DMA channels 11-14 share an interrupt. The driver can't
|
||||
handle this, so don't use channels 12-14 (12 was used, probably
|
||||
because it appears to have an interrupt, but in reality that
|
||||
interrupt is for activity on ANY channel). This may explain
|
||||
a lockup encountered when running out of DMA channels.
|
||||
|
||||
The combined effect of this patch is to leave 7 DMA channels
|
||||
available + channel 0 for bcm2708_fb via the legacy API.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1110
|
||||
https://github.com/raspberrypi/linux/issues/1108
|
||||
|
||||
dmaengine: bcm2708: Make legacy API available for bcm2835-dma
|
||||
|
||||
bcm2708_fb uses the legacy DMA API, so in order to start using
|
||||
bcm2835-dma, bcm2835-dma has to support the legacy API. Make this
|
||||
possible by exporting bcm_dmaman_probe() and bcm_dmaman_remove().
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Change DT compatible string
|
||||
|
||||
Both bcm2835-dma and bcm2708-dmaengine have the same compatible string.
|
||||
So change compatible to "brcm,bcm2708-dma".
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
|
||||
dmaengine: bcm2708: Remove driver but keep legacy API
|
||||
|
||||
Dropping non-DT support means we don't need this driver,
|
||||
but we still need the legacy DMA API.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/dma/Kconfig | 4 +
|
||||
drivers/dma/Makefile | 1 +
|
||||
drivers/dma/bcm2708-dmaengine.c | 281 ++++++++++++++++++++++++++++++
|
||||
include/linux/platform_data/dma-bcm2708.h | 143 +++++++++++++++
|
||||
4 files changed, 429 insertions(+)
|
||||
create mode 100644 drivers/dma/bcm2708-dmaengine.c
|
||||
create mode 100644 include/linux/platform_data/dma-bcm2708.h
|
||||
|
||||
--- a/drivers/dma/Kconfig
|
||||
+++ b/drivers/dma/Kconfig
|
||||
@@ -470,6 +470,10 @@ config TIMB_DMA
|
||||
help
|
||||
Enable support for the Timberdale FPGA DMA engine.
|
||||
|
||||
+config DMA_BCM2708
|
||||
+ tristate "BCM2708 DMA legacy API support"
|
||||
+ depends on DMA_BCM2835
|
||||
+
|
||||
config TI_CPPI41
|
||||
tristate "AM33xx CPPI41 DMA support"
|
||||
depends on ARCH_OMAP
|
||||
--- a/drivers/dma/Makefile
|
||||
+++ b/drivers/dma/Makefile
|
||||
@@ -18,6 +18,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
|
||||
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
|
||||
obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o
|
||||
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
|
||||
+obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o
|
||||
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
|
||||
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
|
||||
obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/dma/bcm2708-dmaengine.c
|
||||
@@ -0,0 +1,281 @@
|
||||
+/*
|
||||
+ * BCM2708 legacy DMA API
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License as published by
|
||||
+ * the Free Software Foundation; either version 2 of the License, or
|
||||
+ * (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+ * GNU General Public License for more details.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/platform_data/dma-bcm2708.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+
|
||||
+#include "virt-dma.h"
|
||||
+
|
||||
+#define CACHE_LINE_MASK 31
|
||||
+#define DEFAULT_DMACHAN_BITMAP 0x10 /* channel 4 only */
|
||||
+
|
||||
+/* valid only for channels 0 - 14, 15 has its own base address */
|
||||
+#define BCM2708_DMA_CHAN(n) ((n) << 8) /* base address */
|
||||
+#define BCM2708_DMA_CHANIO(dma_base, n) \
|
||||
+ ((void __iomem *)((char *)(dma_base) + BCM2708_DMA_CHAN(n)))
|
||||
+
|
||||
+struct vc_dmaman {
|
||||
+ void __iomem *dma_base;
|
||||
+ u32 chan_available; /* bitmap of available channels */
|
||||
+ u32 has_feature[BCM_DMA_FEATURE_COUNT]; /* bitmap of feature presence */
|
||||
+ struct mutex lock;
|
||||
+};
|
||||
+
|
||||
+static struct device *dmaman_dev; /* we assume there's only one! */
|
||||
+static struct vc_dmaman *g_dmaman; /* DMA manager */
|
||||
+
|
||||
+/* DMA Auxiliary Functions */
|
||||
+
|
||||
+/* A DMA buffer on an arbitrary boundary may separate a cache line into a
|
||||
+ section inside the DMA buffer and another section outside it.
|
||||
+ Even if we flush DMA buffers from the cache there is always the chance that
|
||||
+ during a DMA someone will access the part of a cache line that is outside
|
||||
+ the DMA buffer - which will then bring in unwelcome data.
|
||||
+ Without being able to dictate our own buffer pools we must insist that
|
||||
+ DMA buffers consist of a whole number of cache lines.
|
||||
+*/
|
||||
+extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < sg_len; i++) {
|
||||
+ if (sg_ptr[i].offset & CACHE_LINE_MASK ||
|
||||
+ sg_ptr[i].length & CACHE_LINE_MASK)
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_sg_suitable_for_dma);
|
||||
+
|
||||
+extern void bcm_dma_start(void __iomem *dma_chan_base,
|
||||
+ dma_addr_t control_block)
|
||||
+{
|
||||
+ dsb(); /* ARM data synchronization (push) operation */
|
||||
+
|
||||
+ writel(control_block, dma_chan_base + BCM2708_DMA_ADDR);
|
||||
+ writel(BCM2708_DMA_ACTIVE, dma_chan_base + BCM2708_DMA_CS);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_start);
|
||||
+
|
||||
+extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ dsb();
|
||||
+
|
||||
+ /* ugly busy wait only option for now */
|
||||
+ while (readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE)
|
||||
+ cpu_relax();
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_wait_idle);
|
||||
+
|
||||
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ dsb();
|
||||
+
|
||||
+ return readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_ACTIVE;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_is_busy);
|
||||
+
|
||||
+/* Complete an ongoing DMA (assuming its results are to be ignored)
|
||||
+ Does nothing if there is no DMA in progress.
|
||||
+ This routine waits for the current AXI transfer to complete before
|
||||
+ terminating the current DMA. If the current transfer is hung on a DREQ used
|
||||
+ by an uncooperative peripheral the AXI transfer may never complete. In this
|
||||
+ case the routine times out and return a non-zero error code.
|
||||
+ Use of this routine doesn't guarantee that the ongoing or aborted DMA
|
||||
+ does not produce an interrupt.
|
||||
+*/
|
||||
+extern int bcm_dma_abort(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ unsigned long int cs;
|
||||
+ int rc = 0;
|
||||
+
|
||||
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ if (BCM2708_DMA_ACTIVE & cs) {
|
||||
+ long int timeout = 10000;
|
||||
+
|
||||
+ /* write 0 to the active bit - pause the DMA */
|
||||
+ writel(0, dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ /* wait for any current AXI transfer to complete */
|
||||
+ while (0 != (cs & BCM2708_DMA_ISPAUSED) && --timeout >= 0)
|
||||
+ cs = readl(dma_chan_base + BCM2708_DMA_CS);
|
||||
+
|
||||
+ if (0 != (cs & BCM2708_DMA_ISPAUSED)) {
|
||||
+ /* we'll un-pause when we set of our next DMA */
|
||||
+ rc = -ETIMEDOUT;
|
||||
+
|
||||
+ } else if (BCM2708_DMA_ACTIVE & cs) {
|
||||
+ /* terminate the control block chain */
|
||||
+ writel(0, dma_chan_base + BCM2708_DMA_NEXTCB);
|
||||
+
|
||||
+ /* abort the whole DMA */
|
||||
+ writel(BCM2708_DMA_ABORT | BCM2708_DMA_ACTIVE,
|
||||
+ dma_chan_base + BCM2708_DMA_CS);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_abort);
|
||||
+
|
||||
+ /* DMA Manager Device Methods */
|
||||
+
|
||||
+static void vc_dmaman_init(struct vc_dmaman *dmaman, void __iomem *dma_base,
|
||||
+ u32 chans_available)
|
||||
+{
|
||||
+ dmaman->dma_base = dma_base;
|
||||
+ dmaman->chan_available = chans_available;
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_FAST_ORD] = 0x0c; /* 2 & 3 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_BULK_ORD] = 0x01; /* 0 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_NORMAL_ORD] = 0xfe; /* 1 to 7 */
|
||||
+ dmaman->has_feature[BCM_DMA_FEATURE_LITE_ORD] = 0x7f00; /* 8 to 14 */
|
||||
+}
|
||||
+
|
||||
+static int vc_dmaman_chan_alloc(struct vc_dmaman *dmaman,
|
||||
+ unsigned required_feature_set)
|
||||
+{
|
||||
+ u32 chans;
|
||||
+ int chan = 0;
|
||||
+ int feature;
|
||||
+
|
||||
+ chans = dmaman->chan_available;
|
||||
+ for (feature = 0; feature < BCM_DMA_FEATURE_COUNT; feature++)
|
||||
+ /* select the subset of available channels with the desired
|
||||
+ features */
|
||||
+ if (required_feature_set & (1 << feature))
|
||||
+ chans &= dmaman->has_feature[feature];
|
||||
+
|
||||
+ if (!chans)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ /* return the ordinal of the first channel in the bitmap */
|
||||
+ while (chans != 0 && (chans & 1) == 0) {
|
||||
+ chans >>= 1;
|
||||
+ chan++;
|
||||
+ }
|
||||
+ /* claim the channel */
|
||||
+ dmaman->chan_available &= ~(1 << chan);
|
||||
+
|
||||
+ return chan;
|
||||
+}
|
||||
+
|
||||
+static int vc_dmaman_chan_free(struct vc_dmaman *dmaman, int chan)
|
||||
+{
|
||||
+ if (chan < 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if ((1 << chan) & dmaman->chan_available)
|
||||
+ return -EIDRM;
|
||||
+
|
||||
+ dmaman->chan_available |= (1 << chan);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* DMA Manager Monitor */
|
||||
+
|
||||
+extern int bcm_dma_chan_alloc(unsigned required_feature_set,
|
||||
+ void __iomem **out_dma_base, int *out_dma_irq)
|
||||
+{
|
||||
+ struct vc_dmaman *dmaman = g_dmaman;
|
||||
+ struct platform_device *pdev = to_platform_device(dmaman_dev);
|
||||
+ struct resource *r;
|
||||
+ int chan;
|
||||
+
|
||||
+ if (!dmaman_dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ mutex_lock(&dmaman->lock);
|
||||
+ chan = vc_dmaman_chan_alloc(dmaman, required_feature_set);
|
||||
+ if (chan < 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, (unsigned int)chan);
|
||||
+ if (!r) {
|
||||
+ dev_err(dmaman_dev, "failed to get irq for DMA channel %d\n",
|
||||
+ chan);
|
||||
+ vc_dmaman_chan_free(dmaman, chan);
|
||||
+ chan = -ENOENT;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ *out_dma_base = BCM2708_DMA_CHANIO(dmaman->dma_base, chan);
|
||||
+ *out_dma_irq = r->start;
|
||||
+ dev_dbg(dmaman_dev,
|
||||
+ "Legacy API allocated channel=%d, base=%p, irq=%i\n",
|
||||
+ chan, *out_dma_base, *out_dma_irq);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&dmaman->lock);
|
||||
+
|
||||
+ return chan;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_chan_alloc);
|
||||
+
|
||||
+extern int bcm_dma_chan_free(int channel)
|
||||
+{
|
||||
+ struct vc_dmaman *dmaman = g_dmaman;
|
||||
+ int rc;
|
||||
+
|
||||
+ if (!dmaman_dev)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ mutex_lock(&dmaman->lock);
|
||||
+ rc = vc_dmaman_chan_free(dmaman, channel);
|
||||
+ mutex_unlock(&dmaman->lock);
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcm_dma_chan_free);
|
||||
+
|
||||
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
|
||||
+ u32 chans_available)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct vc_dmaman *dmaman;
|
||||
+
|
||||
+ dmaman = devm_kzalloc(dev, sizeof(*dmaman), GFP_KERNEL);
|
||||
+ if (!dmaman)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_init(&dmaman->lock);
|
||||
+ vc_dmaman_init(dmaman, base, chans_available);
|
||||
+ g_dmaman = dmaman;
|
||||
+ dmaman_dev = dev;
|
||||
+
|
||||
+ dev_info(dev, "DMA legacy API manager at %p, dmachans=0x%x\n",
|
||||
+ base, chans_available);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(bcm_dmaman_probe);
|
||||
+
|
||||
+int bcm_dmaman_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ dmaman_dev = NULL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(bcm_dmaman_remove);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- /dev/null
|
||||
+++ b/include/linux/platform_data/dma-bcm2708.h
|
||||
@@ -0,0 +1,143 @@
|
||||
+/*
|
||||
+ * 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.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _PLAT_BCM2708_DMA_H
|
||||
+#define _PLAT_BCM2708_DMA_H
|
||||
+
|
||||
+/* DMA CS Control and Status bits */
|
||||
+#define BCM2708_DMA_ACTIVE BIT(0)
|
||||
+#define BCM2708_DMA_INT BIT(2)
|
||||
+#define BCM2708_DMA_ISPAUSED BIT(4) /* Pause requested or not active */
|
||||
+#define BCM2708_DMA_ISHELD BIT(5) /* Is held by DREQ flow control */
|
||||
+#define BCM2708_DMA_ERR BIT(8)
|
||||
+#define BCM2708_DMA_ABORT BIT(30) /* stop current CB, go to next, WO */
|
||||
+#define BCM2708_DMA_RESET BIT(31) /* WO, self clearing */
|
||||
+
|
||||
+/* DMA control block "info" field bits */
|
||||
+#define BCM2708_DMA_INT_EN BIT(0)
|
||||
+#define BCM2708_DMA_TDMODE BIT(1)
|
||||
+#define BCM2708_DMA_WAIT_RESP BIT(3)
|
||||
+#define BCM2708_DMA_D_INC BIT(4)
|
||||
+#define BCM2708_DMA_D_WIDTH BIT(5)
|
||||
+#define BCM2708_DMA_D_DREQ BIT(6)
|
||||
+#define BCM2708_DMA_S_INC BIT(8)
|
||||
+#define BCM2708_DMA_S_WIDTH BIT(9)
|
||||
+#define BCM2708_DMA_S_DREQ BIT(10)
|
||||
+
|
||||
+#define BCM2708_DMA_BURST(x) (((x) & 0xf) << 12)
|
||||
+#define BCM2708_DMA_PER_MAP(x) ((x) << 16)
|
||||
+#define BCM2708_DMA_WAITS(x) (((x) & 0x1f) << 21)
|
||||
+
|
||||
+#define BCM2708_DMA_DREQ_EMMC 11
|
||||
+#define BCM2708_DMA_DREQ_SDHOST 13
|
||||
+
|
||||
+#define BCM2708_DMA_CS 0x00 /* Control and Status */
|
||||
+#define BCM2708_DMA_ADDR 0x04
|
||||
+/* the current control block appears in the following registers - read only */
|
||||
+#define BCM2708_DMA_INFO 0x08
|
||||
+#define BCM2708_DMA_SOURCE_AD 0x0c
|
||||
+#define BCM2708_DMA_DEST_AD 0x10
|
||||
+#define BCM2708_DMA_NEXTCB 0x1C
|
||||
+#define BCM2708_DMA_DEBUG 0x20
|
||||
+
|
||||
+#define BCM2708_DMA4_CS (BCM2708_DMA_CHAN(4) + BCM2708_DMA_CS)
|
||||
+#define BCM2708_DMA4_ADDR (BCM2708_DMA_CHAN(4) + BCM2708_DMA_ADDR)
|
||||
+
|
||||
+#define BCM2708_DMA_TDMODE_LEN(w, h) ((h) << 16 | (w))
|
||||
+
|
||||
+/* When listing features we can ask for when allocating DMA channels give
|
||||
+ those with higher priority smaller ordinal numbers */
|
||||
+#define BCM_DMA_FEATURE_FAST_ORD 0
|
||||
+#define BCM_DMA_FEATURE_BULK_ORD 1
|
||||
+#define BCM_DMA_FEATURE_NORMAL_ORD 2
|
||||
+#define BCM_DMA_FEATURE_LITE_ORD 3
|
||||
+#define BCM_DMA_FEATURE_FAST BIT(BCM_DMA_FEATURE_FAST_ORD)
|
||||
+#define BCM_DMA_FEATURE_BULK BIT(BCM_DMA_FEATURE_BULK_ORD)
|
||||
+#define BCM_DMA_FEATURE_NORMAL BIT(BCM_DMA_FEATURE_NORMAL_ORD)
|
||||
+#define BCM_DMA_FEATURE_LITE BIT(BCM_DMA_FEATURE_LITE_ORD)
|
||||
+#define BCM_DMA_FEATURE_COUNT 4
|
||||
+
|
||||
+struct bcm2708_dma_cb {
|
||||
+ unsigned long info;
|
||||
+ unsigned long src;
|
||||
+ unsigned long dst;
|
||||
+ unsigned long length;
|
||||
+ unsigned long stride;
|
||||
+ unsigned long next;
|
||||
+ unsigned long pad[2];
|
||||
+};
|
||||
+
|
||||
+struct scatterlist;
|
||||
+struct platform_device;
|
||||
+
|
||||
+#ifdef CONFIG_DMA_BCM2708
|
||||
+
|
||||
+int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
|
||||
+void bcm_dma_start(void __iomem *dma_chan_base, dma_addr_t control_block);
|
||||
+void bcm_dma_wait_idle(void __iomem *dma_chan_base);
|
||||
+bool bcm_dma_is_busy(void __iomem *dma_chan_base);
|
||||
+int bcm_dma_abort(void __iomem *dma_chan_base);
|
||||
+
|
||||
+/* return channel no or -ve error */
|
||||
+int bcm_dma_chan_alloc(unsigned preferred_feature_set,
|
||||
+ void __iomem **out_dma_base, int *out_dma_irq);
|
||||
+int bcm_dma_chan_free(int channel);
|
||||
+
|
||||
+int bcm_dmaman_probe(struct platform_device *pdev, void __iomem *base,
|
||||
+ u32 chans_available);
|
||||
+int bcm_dmaman_remove(struct platform_device *pdev);
|
||||
+
|
||||
+#else /* CONFIG_DMA_BCM2708 */
|
||||
+
|
||||
+static inline int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr,
|
||||
+ int sg_len)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline void bcm_dma_start(void __iomem *dma_chan_base,
|
||||
+ dma_addr_t control_block) { }
|
||||
+
|
||||
+static inline void bcm_dma_wait_idle(void __iomem *dma_chan_base) { }
|
||||
+
|
||||
+static inline bool bcm_dma_is_busy(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_abort(void __iomem *dma_chan_base)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_chan_alloc(unsigned preferred_feature_set,
|
||||
+ void __iomem **out_dma_base,
|
||||
+ int *out_dma_irq)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dma_chan_free(int channel)
|
||||
+{
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dmaman_probe(struct platform_device *pdev,
|
||||
+ void __iomem *base, u32 chans_available)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline int bcm_dmaman_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif /* CONFIG_DMA_BCM2708 */
|
||||
+
|
||||
+#endif /* _PLAT_BCM2708_DMA_H */
|
|
@ -0,0 +1,75 @@
|
|||
From 664c65e9a1191f4123b3d88595735d9ab56839e6 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 17 Apr 2015 19:30:22 +0100
|
||||
Subject: [PATCH 032/127] 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
|
||||
@@ -1510,6 +1510,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
|
||||
@@ -1832,7 +1832,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
|
||||
@@ -1003,7 +1003,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
|
||||
@@ -143,7 +143,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
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
|
@ -0,0 +1,991 @@
|
|||
From bb0a865b1cbbb1dd887378111af03727884e3476 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 17 Jun 2015 16:07:06 +0100
|
||||
Subject: [PATCH 038/127] 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 | 422 +++++++++++++++++++++++++++
|
||||
include/linux/broadcom/vc_mem.h | 35 +++
|
||||
6 files changed, 469 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,422 @@
|
||||
+/*****************************************************************************
|
||||
+* 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/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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,306 @@
|
|||
From 6ddd3a6f0a8a3e4506b4fe4e1b410d9d945c5df2 Mon Sep 17 00:00:00 2001
|
||||
From: Luke Wren <luke@raspberrypi.org>
|
||||
Date: Fri, 21 Aug 2015 23:14:48 +0100
|
||||
Subject: [PATCH 040/127] Add /dev/gpiomem device for rootless user GPIO access
|
||||
|
||||
Signed-off-by: Luke Wren <luke@raspberrypi.org>
|
||||
|
||||
bcm2835-gpiomem: Fix for ARCH_BCM2835 builds
|
||||
|
||||
Build on ARCH_BCM2835, and fail to probe if no IO resource.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1154
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 9 ++
|
||||
drivers/char/broadcom/Makefile | 3 +
|
||||
drivers/char/broadcom/bcm2835-gpiomem.c | 260 ++++++++++++++++++++++++++++++++
|
||||
3 files changed, 272 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
|
||||
--- a/drivers/char/broadcom/Kconfig
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -32,3 +32,12 @@ config BCM_VC_SM
|
||||
help
|
||||
Support for the VC shared memory on the Broadcom reference
|
||||
design. Uses the VCHIQ stack.
|
||||
+
|
||||
+config BCM2835_DEVGPIOMEM
|
||||
+ tristate "/dev/gpiomem rootless GPIO access via mmap() on the BCM2835"
|
||||
+ default m
|
||||
+ help
|
||||
+ Provides users with root-free access to the GPIO registers
|
||||
+ on the 2835. Calling mmap(/dev/gpiomem) will map the GPIO
|
||||
+ register page to the user's pointer.
|
||||
+
|
||||
--- a/drivers/char/broadcom/Makefile
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -1,3 +1,6 @@
|
||||
obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
obj-$(CONFIG_BCM_VC_SM) += vc_sm/
|
||||
+
|
||||
+obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
|
||||
+
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/bcm2835-gpiomem.c
|
||||
@@ -0,0 +1,260 @@
|
||||
+/**
|
||||
+ * GPIO memory device driver
|
||||
+ *
|
||||
+ * Creates a chardev /dev/gpiomem which will provide user access to
|
||||
+ * the BCM2835's GPIO registers when it is mmap()'d.
|
||||
+ * No longer need root for user GPIO access, but without relaxing permissions
|
||||
+ * on /dev/mem.
|
||||
+ *
|
||||
+ * Written by Luke Wren <luke@raspberrypi.org>
|
||||
+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
|
||||
+ *
|
||||
+ * 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/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/pagemap.h>
|
||||
+#include <linux/io.h>
|
||||
+
|
||||
+#define DEVICE_NAME "bcm2835-gpiomem"
|
||||
+#define DRIVER_NAME "gpiomem-bcm2835"
|
||||
+#define DEVICE_MINOR 0
|
||||
+
|
||||
+struct bcm2835_gpiomem_instance {
|
||||
+ unsigned long gpio_regs_phys;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+static struct cdev bcm2835_gpiomem_cdev;
|
||||
+static dev_t bcm2835_gpiomem_devid;
|
||||
+static struct class *bcm2835_gpiomem_class;
|
||||
+static struct device *bcm2835_gpiomem_dev;
|
||||
+static struct bcm2835_gpiomem_instance *inst;
|
||||
+
|
||||
+
|
||||
+/****************************************************************************
|
||||
+*
|
||||
+* GPIO mem chardev file ops
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static int bcm2835_gpiomem_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ dev_info(inst->dev, "gpiomem device opened.");
|
||||
+
|
||||
+ if (dev != DEVICE_MINOR) {
|
||||
+ dev_err(inst->dev, "Unknown minor device: %d", dev);
|
||||
+ ret = -ENXIO;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_gpiomem_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ int dev = iminor(inode);
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (dev != DEVICE_MINOR) {
|
||||
+ dev_err(inst->dev, "Unknown minor device %d", dev);
|
||||
+ ret = -ENXIO;
|
||||
+ }
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct vm_operations_struct bcm2835_gpiomem_vm_ops = {
|
||||
+#ifdef CONFIG_HAVE_IOREMAP_PROT
|
||||
+ .access = generic_access_phys
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_gpiomem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
+{
|
||||
+ /* Ignore what the user says - they're getting the GPIO regs
|
||||
+ whether they like it or not! */
|
||||
+ unsigned long gpio_page = inst->gpio_regs_phys >> PAGE_SHIFT;
|
||||
+
|
||||
+ vma->vm_page_prot = phys_mem_access_prot(file, gpio_page,
|
||||
+ PAGE_SIZE,
|
||||
+ vma->vm_page_prot);
|
||||
+ vma->vm_ops = &bcm2835_gpiomem_vm_ops;
|
||||
+ if (remap_pfn_range(vma, vma->vm_start,
|
||||
+ gpio_page,
|
||||
+ PAGE_SIZE,
|
||||
+ vma->vm_page_prot)) {
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct file_operations
|
||||
+bcm2835_gpiomem_fops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .open = bcm2835_gpiomem_open,
|
||||
+ .release = bcm2835_gpiomem_release,
|
||||
+ .mmap = bcm2835_gpiomem_mmap,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+ /****************************************************************************
|
||||
+*
|
||||
+* Probe and remove functions
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+
|
||||
+static int bcm2835_gpiomem_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int err;
|
||||
+ void *ptr_err;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct resource *ioresource;
|
||||
+
|
||||
+ /* Allocate buffers and instance data */
|
||||
+
|
||||
+ inst = kzalloc(sizeof(struct bcm2835_gpiomem_instance), GFP_KERNEL);
|
||||
+
|
||||
+ if (!inst) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto failed_inst_alloc;
|
||||
+ }
|
||||
+
|
||||
+ inst->dev = dev;
|
||||
+
|
||||
+ ioresource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
+ if (ioresource) {
|
||||
+ inst->gpio_regs_phys = ioresource->start;
|
||||
+ } else {
|
||||
+ dev_err(inst->dev, "failed to get IO resource");
|
||||
+ err = -ENOENT;
|
||||
+ goto failed_get_resource;
|
||||
+ }
|
||||
+
|
||||
+ /* Create character device entries */
|
||||
+
|
||||
+ err = alloc_chrdev_region(&bcm2835_gpiomem_devid,
|
||||
+ DEVICE_MINOR, 1, DEVICE_NAME);
|
||||
+ if (err != 0) {
|
||||
+ dev_err(inst->dev, "unable to allocate device number");
|
||||
+ goto failed_alloc_chrdev;
|
||||
+ }
|
||||
+ cdev_init(&bcm2835_gpiomem_cdev, &bcm2835_gpiomem_fops);
|
||||
+ bcm2835_gpiomem_cdev.owner = THIS_MODULE;
|
||||
+ err = cdev_add(&bcm2835_gpiomem_cdev, bcm2835_gpiomem_devid, 1);
|
||||
+ if (err != 0) {
|
||||
+ dev_err(inst->dev, "unable to register device");
|
||||
+ goto failed_cdev_add;
|
||||
+ }
|
||||
+
|
||||
+ /* Create sysfs entries */
|
||||
+
|
||||
+ bcm2835_gpiomem_class = class_create(THIS_MODULE, DEVICE_NAME);
|
||||
+ ptr_err = bcm2835_gpiomem_class;
|
||||
+ if (IS_ERR(ptr_err))
|
||||
+ goto failed_class_create;
|
||||
+
|
||||
+ bcm2835_gpiomem_dev = device_create(bcm2835_gpiomem_class, NULL,
|
||||
+ bcm2835_gpiomem_devid, NULL,
|
||||
+ "gpiomem");
|
||||
+ ptr_err = bcm2835_gpiomem_dev;
|
||||
+ if (IS_ERR(ptr_err))
|
||||
+ goto failed_device_create;
|
||||
+
|
||||
+ dev_info(inst->dev, "Initialised: Registers at 0x%08lx",
|
||||
+ inst->gpio_regs_phys);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+failed_device_create:
|
||||
+ class_destroy(bcm2835_gpiomem_class);
|
||||
+failed_class_create:
|
||||
+ cdev_del(&bcm2835_gpiomem_cdev);
|
||||
+ err = PTR_ERR(ptr_err);
|
||||
+failed_cdev_add:
|
||||
+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
|
||||
+failed_alloc_chrdev:
|
||||
+failed_get_resource:
|
||||
+ kfree(inst);
|
||||
+failed_inst_alloc:
|
||||
+ dev_err(inst->dev, "could not load bcm2835_gpiomem");
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_gpiomem_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = inst->dev;
|
||||
+
|
||||
+ kfree(inst);
|
||||
+ device_destroy(bcm2835_gpiomem_class, bcm2835_gpiomem_devid);
|
||||
+ class_destroy(bcm2835_gpiomem_class);
|
||||
+ cdev_del(&bcm2835_gpiomem_cdev);
|
||||
+ unregister_chrdev_region(bcm2835_gpiomem_devid, 1);
|
||||
+
|
||||
+ dev_info(dev, "GPIO mem driver removed - OK");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+ /****************************************************************************
|
||||
+*
|
||||
+* Register the driver with device tree
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static const struct of_device_id bcm2835_gpiomem_of_match[] = {
|
||||
+ {.compatible = "brcm,bcm2835-gpiomem",},
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_gpiomem_of_match);
|
||||
+
|
||||
+static struct platform_driver bcm2835_gpiomem_driver = {
|
||||
+ .probe = bcm2835_gpiomem_probe,
|
||||
+ .remove = bcm2835_gpiomem_remove,
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = bcm2835_gpiomem_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(bcm2835_gpiomem_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:gpiomem-bcm2835");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION("gpiomem driver for accessing GPIO from userspace");
|
||||
+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,358 @@
|
|||
From 142af590ca0a7fc36905f5bd123103c730d22a07 Mon Sep 17 00:00:00 2001
|
||||
From: Luke Wren <wren6991@gmail.com>
|
||||
Date: Sat, 5 Sep 2015 01:16:10 +0100
|
||||
Subject: [PATCH 042/127] Add SMI NAND driver
|
||||
|
||||
Signed-off-by: Luke Wren <wren6991@gmail.com>
|
||||
---
|
||||
.../bindings/mtd/brcm,bcm2835-smi-nand.txt | 42 ++++
|
||||
drivers/mtd/nand/Kconfig | 7 +
|
||||
drivers/mtd/nand/Makefile | 1 +
|
||||
drivers/mtd/nand/bcm2835_smi_nand.c | 268 +++++++++++++++++++++
|
||||
4 files changed, 318 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
|
||||
create mode 100644 drivers/mtd/nand/bcm2835_smi_nand.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/mtd/brcm,bcm2835-smi-nand.txt
|
||||
@@ -0,0 +1,42 @@
|
||||
+* BCM2835 SMI NAND flash
|
||||
+
|
||||
+This driver is a shim between the BCM2835 SMI driver (SMI is a peripheral for
|
||||
+talking to parallel register interfaces) and Linux's MTD layer.
|
||||
+
|
||||
+Required properties:
|
||||
+- compatible: "brcm,bcm2835-smi-nand"
|
||||
+- status: "okay"
|
||||
+
|
||||
+Optional properties:
|
||||
+- partition@n, where n is an integer from a consecutive sequence starting at 0
|
||||
+ - Difficult to store partition table on NAND device - normally put it
|
||||
+ in the source code, kernel bootparams, or device tree (the best way!)
|
||||
+ - Sub-properties:
|
||||
+ - label: the partition name, as shown by mtdinfo /dev/mtd*
|
||||
+ - reg: the size and offset of this partition.
|
||||
+ - (optional) read-only: an empty property flagging as read only
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+nand: flash@0 {
|
||||
+ compatible = "brcm,bcm2835-smi-nand";
|
||||
+ status = "okay";
|
||||
+
|
||||
+ partition@0 {
|
||||
+ label = "stage2";
|
||||
+ // 128k
|
||||
+ reg = <0 0x20000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ partition@1 {
|
||||
+ label = "firmware";
|
||||
+ // 16M
|
||||
+ reg = <0x20000 0x1000000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+ partition@2 {
|
||||
+ label = "root";
|
||||
+ // 2G
|
||||
+ reg = <0x1020000 0x80000000>;
|
||||
+ };
|
||||
+};
|
||||
\ No newline at end of file
|
||||
--- a/drivers/mtd/nand/Kconfig
|
||||
+++ b/drivers/mtd/nand/Kconfig
|
||||
@@ -41,6 +41,13 @@ config MTD_SM_COMMON
|
||||
tristate
|
||||
default n
|
||||
|
||||
+config MTD_NAND_BCM2835_SMI
|
||||
+ tristate "Use Broadcom's Secondary Memory Interface as a NAND controller (BCM283x)"
|
||||
+ depends on (MACH_BCM2708 || MACH_BCM2709 || ARCH_BCM2835) && BCM2835_SMI && MTD_NAND
|
||||
+ default m
|
||||
+ help
|
||||
+ Uses the BCM2835's SMI peripheral as a NAND controller.
|
||||
+
|
||||
config MTD_NAND_DENALI
|
||||
tristate
|
||||
|
||||
--- a/drivers/mtd/nand/Makefile
|
||||
+++ b/drivers/mtd/nand/Makefile
|
||||
@@ -14,6 +14,7 @@ obj-$(CONFIG_MTD_NAND_DENALI) += denali
|
||||
obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o
|
||||
obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o
|
||||
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
|
||||
+obj-$(CONFIG_MTD_NAND_BCM2835_SMI) += bcm2835_smi_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o
|
||||
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
|
||||
obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/bcm2835_smi_nand.c
|
||||
@@ -0,0 +1,268 @@
|
||||
+/**
|
||||
+ * NAND flash driver for Broadcom Secondary Memory Interface
|
||||
+ *
|
||||
+ * Written by Luke Wren <luke@raspberrypi.org>
|
||||
+ * Copyright (c) 2015, Raspberry Pi (Trading) Ltd.
|
||||
+ *
|
||||
+ * 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/of.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/mtd/nand.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+
|
||||
+#include <linux/broadcom/bcm2835_smi.h>
|
||||
+
|
||||
+#define DEVICE_NAME "bcm2835-smi-nand"
|
||||
+#define DRIVER_NAME "smi-nand-bcm2835"
|
||||
+
|
||||
+struct bcm2835_smi_nand_host {
|
||||
+ struct bcm2835_smi_instance *smi_inst;
|
||||
+ struct nand_chip nand_chip;
|
||||
+ struct mtd_info mtd;
|
||||
+ struct device *dev;
|
||||
+};
|
||||
+
|
||||
+/****************************************************************************
|
||||
+*
|
||||
+* NAND functionality implementation
|
||||
+*
|
||||
+****************************************************************************/
|
||||
+
|
||||
+#define SMI_NAND_CLE_PIN 0x01
|
||||
+#define SMI_NAND_ALE_PIN 0x02
|
||||
+
|
||||
+static inline void bcm2835_smi_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
|
||||
+ unsigned int ctrl)
|
||||
+{
|
||||
+ uint32_t cmd32 = cmd;
|
||||
+ uint32_t addr = ~(SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
|
||||
+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
|
||||
+ struct bcm2835_smi_instance *inst = host->smi_inst;
|
||||
+
|
||||
+ if (ctrl & NAND_CLE)
|
||||
+ addr |= SMI_NAND_CLE_PIN;
|
||||
+ if (ctrl & NAND_ALE)
|
||||
+ addr |= SMI_NAND_ALE_PIN;
|
||||
+ /* Lower ALL the CS pins! */
|
||||
+ if (ctrl & NAND_NCE)
|
||||
+ addr &= (SMI_NAND_CLE_PIN | SMI_NAND_ALE_PIN);
|
||||
+
|
||||
+ bcm2835_smi_set_address(inst, addr);
|
||||
+
|
||||
+ if (cmd != NAND_CMD_NONE)
|
||||
+ bcm2835_smi_write_buf(inst, &cmd32, 1);
|
||||
+}
|
||||
+
|
||||
+static inline uint8_t bcm2835_smi_nand_read_byte(struct mtd_info *mtd)
|
||||
+{
|
||||
+ uint8_t byte;
|
||||
+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
|
||||
+ struct bcm2835_smi_instance *inst = host->smi_inst;
|
||||
+
|
||||
+ bcm2835_smi_read_buf(inst, &byte, 1);
|
||||
+ return byte;
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2835_smi_nand_write_byte(struct mtd_info *mtd,
|
||||
+ uint8_t byte)
|
||||
+{
|
||||
+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
|
||||
+ struct bcm2835_smi_instance *inst = host->smi_inst;
|
||||
+
|
||||
+ bcm2835_smi_write_buf(inst, &byte, 1);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2835_smi_nand_write_buf(struct mtd_info *mtd,
|
||||
+ const uint8_t *buf, int len)
|
||||
+{
|
||||
+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
|
||||
+ struct bcm2835_smi_instance *inst = host->smi_inst;
|
||||
+
|
||||
+ bcm2835_smi_write_buf(inst, buf, len);
|
||||
+}
|
||||
+
|
||||
+static inline void bcm2835_smi_nand_read_buf(struct mtd_info *mtd,
|
||||
+ uint8_t *buf, int len)
|
||||
+{
|
||||
+ struct bcm2835_smi_nand_host *host = dev_get_drvdata(mtd->dev.parent);
|
||||
+ struct bcm2835_smi_instance *inst = host->smi_inst;
|
||||
+
|
||||
+ bcm2835_smi_read_buf(inst, buf, len);
|
||||
+}
|
||||
+
|
||||
+/****************************************************************************
|
||||
+*
|
||||
+* Probe and remove functions
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static int bcm2835_smi_nand_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct bcm2835_smi_nand_host *host;
|
||||
+ struct nand_chip *this;
|
||||
+ struct mtd_info *mtd;
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *node = dev->of_node, *smi_node;
|
||||
+ struct mtd_part_parser_data ppdata;
|
||||
+ struct smi_settings *smi_settings;
|
||||
+ struct bcm2835_smi_instance *smi_inst;
|
||||
+ int ret = -ENXIO;
|
||||
+
|
||||
+ if (!node) {
|
||||
+ dev_err(dev, "No device tree node supplied!");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ smi_node = of_parse_phandle(node, "smi_handle", 0);
|
||||
+
|
||||
+ /* Request use of SMI peripheral: */
|
||||
+ smi_inst = bcm2835_smi_get(smi_node);
|
||||
+
|
||||
+ if (!smi_inst) {
|
||||
+ dev_err(dev, "Could not register with SMI.");
|
||||
+ return -EPROBE_DEFER;
|
||||
+ }
|
||||
+
|
||||
+ /* Set SMI timing and bus width */
|
||||
+
|
||||
+ smi_settings = bcm2835_smi_get_settings_from_regs(smi_inst);
|
||||
+
|
||||
+ smi_settings->data_width = SMI_WIDTH_8BIT;
|
||||
+ smi_settings->read_setup_time = 2;
|
||||
+ smi_settings->read_hold_time = 1;
|
||||
+ smi_settings->read_pace_time = 1;
|
||||
+ smi_settings->read_strobe_time = 3;
|
||||
+
|
||||
+ smi_settings->write_setup_time = 2;
|
||||
+ smi_settings->write_hold_time = 1;
|
||||
+ smi_settings->write_pace_time = 1;
|
||||
+ smi_settings->write_strobe_time = 3;
|
||||
+
|
||||
+ bcm2835_smi_set_regs_from_settings(smi_inst);
|
||||
+
|
||||
+ host = devm_kzalloc(dev, sizeof(struct bcm2835_smi_nand_host),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!host)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ host->dev = dev;
|
||||
+ host->smi_inst = smi_inst;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, host);
|
||||
+
|
||||
+ /* Link the structures together */
|
||||
+
|
||||
+ this = &host->nand_chip;
|
||||
+ mtd = &host->mtd;
|
||||
+ mtd->priv = this;
|
||||
+ mtd->owner = THIS_MODULE;
|
||||
+ mtd->dev.parent = dev;
|
||||
+ mtd->name = DRIVER_NAME;
|
||||
+ ppdata.of_node = node;
|
||||
+
|
||||
+ /* 20 us command delay time... */
|
||||
+ this->chip_delay = 20;
|
||||
+
|
||||
+ this->priv = host;
|
||||
+ this->cmd_ctrl = bcm2835_smi_nand_cmd_ctrl;
|
||||
+ this->read_byte = bcm2835_smi_nand_read_byte;
|
||||
+ this->write_byte = bcm2835_smi_nand_write_byte;
|
||||
+ this->write_buf = bcm2835_smi_nand_write_buf;
|
||||
+ this->read_buf = bcm2835_smi_nand_read_buf;
|
||||
+
|
||||
+ this->ecc.mode = NAND_ECC_SOFT;
|
||||
+
|
||||
+ /* Should never be accessed directly: */
|
||||
+
|
||||
+ this->IO_ADDR_R = (void *)0xdeadbeef;
|
||||
+ this->IO_ADDR_W = (void *)0xdeadbeef;
|
||||
+
|
||||
+ /* First scan to find the device and get the page size */
|
||||
+
|
||||
+ if (nand_scan_ident(mtd, 1, NULL))
|
||||
+ return -ENXIO;
|
||||
+
|
||||
+ /* Second phase scan */
|
||||
+
|
||||
+ if (nand_scan_tail(mtd))
|
||||
+ return -ENXIO;
|
||||
+
|
||||
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
|
||||
+ if (!ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ nand_release(mtd);
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_smi_nand_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct bcm2835_smi_nand_host *host = platform_get_drvdata(pdev);
|
||||
+
|
||||
+ nand_release(&host->mtd);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/****************************************************************************
|
||||
+*
|
||||
+* Register the driver with device tree
|
||||
+*
|
||||
+***************************************************************************/
|
||||
+
|
||||
+static const struct of_device_id bcm2835_smi_nand_of_match[] = {
|
||||
+ {.compatible = "brcm,bcm2835-smi-nand",},
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+MODULE_DEVICE_TABLE(of, bcm2835_smi_nand_of_match);
|
||||
+
|
||||
+static struct platform_driver bcm2835_smi_nand_driver = {
|
||||
+ .probe = bcm2835_smi_nand_probe,
|
||||
+ .remove = bcm2835_smi_nand_remove,
|
||||
+ .driver = {
|
||||
+ .name = DRIVER_NAME,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = bcm2835_smi_nand_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(bcm2835_smi_nand_driver);
|
||||
+
|
||||
+MODULE_ALIAS("platform:smi-nand-bcm2835");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_DESCRIPTION
|
||||
+ ("Driver for NAND chips using Broadcom Secondary Memory Interface");
|
||||
+MODULE_AUTHOR("Luke Wren <luke@raspberrypi.org>");
|
|
@ -0,0 +1,841 @@
|
|||
From b9a3e6cbf575d0463af4b47ce48f76624bae10a1 Mon Sep 17 00:00:00 2001
|
||||
From: Aron Szabo <aron@aron.ws>
|
||||
Date: Sat, 16 Jun 2012 12:15:55 +0200
|
||||
Subject: [PATCH 043/127] 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 | 730 ++++++++++++++++++++++++++++++++++
|
||||
include/linux/platform_data/bcm2708.h | 23 ++
|
||||
4 files changed, 760 insertions(+)
|
||||
create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
|
||||
create mode 100644 include/linux/platform_data/bcm2708.h
|
||||
|
||||
--- 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,730 @@
|
||||
+/*
|
||||
+ * 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 <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;
|
||||
+ 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");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ 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 {
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
+
|
||||
+// 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");
|
||||
--- /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
|
|
@ -0,0 +1,257 @@
|
|||
From 21e72e1f417fe2c097fe8f8ba4963abdde88a6ca Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:49:20 +0100
|
||||
Subject: [PATCH 044/127] Add cpufreq driver
|
||||
|
||||
Signed-off-by: popcornmix <popcornmix@gmail.com>
|
||||
---
|
||||
drivers/cpufreq/Kconfig.arm | 9 ++
|
||||
drivers/cpufreq/Makefile | 1 +
|
||||
drivers/cpufreq/bcm2835-cpufreq.c | 213 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 223 insertions(+)
|
||||
create mode 100644 drivers/cpufreq/bcm2835-cpufreq.c
|
||||
|
||||
--- a/drivers/cpufreq/Kconfig.arm
|
||||
+++ b/drivers/cpufreq/Kconfig.arm
|
||||
@@ -217,6 +217,15 @@ config ARM_SPEAR_CPUFREQ
|
||||
help
|
||||
This adds the CPUFreq driver support for SPEAr SOCs.
|
||||
|
||||
+config ARM_BCM2835_CPUFREQ
|
||||
+ depends on RASPBERRYPI_FIRMWARE
|
||||
+ bool "BCM2835 Driver"
|
||||
+ default y
|
||||
+ help
|
||||
+ This adds the CPUFreq driver for BCM2835
|
||||
+
|
||||
+ If in doubt, say N.
|
||||
+
|
||||
config ARM_TEGRA20_CPUFREQ
|
||||
bool "Tegra20 CPUFreq support"
|
||||
depends on ARCH_TEGRA
|
||||
--- a/drivers/cpufreq/Makefile
|
||||
+++ b/drivers/cpufreq/Makefile
|
||||
@@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa11
|
||||
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
|
||||
obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o
|
||||
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
|
||||
+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
|
||||
obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
|
||||
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/cpufreq/bcm2835-cpufreq.c
|
||||
@@ -0,0 +1,213 @@
|
||||
+/*****************************************************************************
|
||||
+* 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 <soc/bcm2835/raspberrypi-firmware.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__)
|
||||
+
|
||||
+/* ---------- 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 int bcm2835_cpufreq_clock_property(u32 tag, u32 id, u32 *val)
|
||||
+{
|
||||
+ struct rpi_firmware *fw = rpi_firmware_get(NULL);
|
||||
+ struct {
|
||||
+ u32 id;
|
||||
+ u32 val;
|
||||
+ } packet;
|
||||
+ int ret;
|
||||
+
|
||||
+ packet.id = id;
|
||||
+ packet.val = *val;
|
||||
+ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ *val = packet.val;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
|
||||
+{
|
||||
+ u32 rate = arm_rate * 1000;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = bcm2835_cpufreq_clock_property(RPI_FIRMWARE_SET_CLOCK_RATE, VCMSG_ID_ARM_CLOCK, &rate);
|
||||
+ if (ret) {
|
||||
+ print_err("Failed to set clock: %d (%d)\n", arm_rate, ret);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ rate /= 1000;
|
||||
+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, rate);
|
||||
+
|
||||
+ return rate;
|
||||
+}
|
||||
+
|
||||
+static uint32_t bcm2835_cpufreq_get_clock(int tag)
|
||||
+{
|
||||
+ u32 rate;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = bcm2835_cpufreq_clock_property(tag, VCMSG_ID_ARM_CLOCK, &rate);
|
||||
+ if (ret) {
|
||||
+ print_err("Failed to get clock (%d)\n", ret);
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ rate /= 1000;
|
||||
+ print_debug("%s frequency = %u\n",
|
||||
+ tag == RPI_FIRMWARE_GET_CLOCK_RATE ? "Current":
|
||||
+ tag == RPI_FIRMWARE_GET_MIN_CLOCK_RATE ? "Min":
|
||||
+ tag == RPI_FIRMWARE_GET_MAX_CLOCK_RATE ? "Max":
|
||||
+ "Unexpected", rate);
|
||||
+
|
||||
+ return 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 */
|
||||
+
|
||||
+ if (!rpi_firmware_get(NULL)) {
|
||||
+ print_err("Firmware is not available\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ /* now find out what the maximum and minimum frequencies are */
|
||||
+ bcm2835_freq_table[0].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MIN_CLOCK_RATE);
|
||||
+ bcm2835_freq_table[1].frequency = bcm2835_cpufreq_get_clock(RPI_FIRMWARE_GET_MAX_CLOCK_RATE);
|
||||
+
|
||||
+ 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(RPI_FIRMWARE_GET_CLOCK_RATE);
|
||||
+ print_debug("cpu%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);
|
|
@ -0,0 +1,193 @@
|
|||
From ffe7f669c4106fafe86597774697048258cedbc9 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 26 Mar 2013 19:24:24 +0000
|
||||
Subject: [PATCH 045/127] 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>
|
||||
---
|
||||
drivers/thermal/Kconfig | 7 ++
|
||||
drivers/thermal/Makefile | 1 +
|
||||
drivers/thermal/bcm2835-thermal.c | 141 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 149 insertions(+)
|
||||
create mode 100644 drivers/thermal/bcm2835-thermal.c
|
||||
|
||||
--- a/drivers/thermal/Kconfig
|
||||
+++ b/drivers/thermal/Kconfig
|
||||
@@ -285,6 +285,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 RASPBERRYPI_FIRMWARE
|
||||
+ 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
|
||||
@@ -38,6 +38,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_IOSF_CORE) += intel_soc_dts_iosf.o
|
||||
obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/thermal/bcm2835-thermal.c
|
||||
@@ -0,0 +1,141 @@
|
||||
+/*****************************************************************************
|
||||
+* 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/module.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/thermal.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+static int bcm2835_thermal_get_property(struct thermal_zone_device *tz,
|
||||
+ int *temp, u32 tag)
|
||||
+{
|
||||
+ struct rpi_firmware *fw = tz->devdata;
|
||||
+ struct {
|
||||
+ u32 id;
|
||||
+ u32 val;
|
||||
+ } packet;
|
||||
+ int ret;
|
||||
+
|
||||
+ *temp = 0;
|
||||
+ packet.id = 0;
|
||||
+ ret = rpi_firmware_property(fw, tag, &packet, sizeof(packet));
|
||||
+ if (ret) {
|
||||
+ dev_err(&tz->device, "Failed to get temperature\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ *temp = packet.val;
|
||||
+ dev_dbg(&tz->device, "%stemp=%d\n",
|
||||
+ tag == RPI_FIRMWARE_GET_MAX_TEMPERATURE ? "max" : "", *temp);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
|
||||
+ int *temp)
|
||||
+{
|
||||
+ return bcm2835_thermal_get_property(tz, temp,
|
||||
+ RPI_FIRMWARE_GET_TEMPERATURE);
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_get_max_temp(struct thermal_zone_device *tz,
|
||||
+ int trip, int *temp)
|
||||
+{
|
||||
+ /*
|
||||
+ * The maximum safe temperature of the SoC.
|
||||
+ * Overclock may be disabled above this temperature.
|
||||
+ */
|
||||
+ return bcm2835_thermal_get_property(tz, temp,
|
||||
+ RPI_FIRMWARE_GET_MAX_TEMPERATURE);
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_get_trip_type(struct thermal_zone_device *tz,
|
||||
+ int trip, enum thermal_trip_type *type)
|
||||
+{
|
||||
+ *type = THERMAL_TRIP_HOT;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_get_mode(struct thermal_zone_device *tz,
|
||||
+ enum thermal_device_mode *mode)
|
||||
+{
|
||||
+ *mode = THERMAL_DEVICE_ENABLED;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct thermal_zone_device_ops ops = {
|
||||
+ .get_temp = bcm2835_thermal_get_temp,
|
||||
+ .get_trip_temp = bcm2835_thermal_get_max_temp,
|
||||
+ .get_trip_type = bcm2835_thermal_get_trip_type,
|
||||
+ .get_mode = bcm2835_thermal_get_mode,
|
||||
+};
|
||||
+
|
||||
+static int bcm2835_thermal_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *fw_np;
|
||||
+ struct rpi_firmware *fw;
|
||||
+ struct thermal_zone_device *tz;
|
||||
+
|
||||
+ fw_np = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
|
||||
+/* Remove comment when booting without Device Tree is no longer supported
|
||||
+ if (!fw_np) {
|
||||
+ dev_err(&pdev->dev, "Missing firmware node\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+*/
|
||||
+ fw = rpi_firmware_get(fw_np);
|
||||
+ if (!fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ tz = thermal_zone_device_register("bcm2835_thermal", 1, 0, fw, &ops,
|
||||
+ NULL, 0, 0);
|
||||
+ if (IS_ERR(tz)) {
|
||||
+ dev_err(&pdev->dev, "Failed to register the thermal device\n");
|
||||
+ return PTR_ERR(tz);
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, tz);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bcm2835_thermal_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ thermal_zone_device_unregister(platform_get_drvdata(pdev));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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",
|
||||
+ .of_match_table = bcm2835_thermal_of_match_table,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(bcm2835_thermal_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Dorian Peake");
|
||||
+MODULE_AUTHOR("Noralf Trønnes");
|
||||
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,635 @@
|
|||
From 052aa5593d1cd52bbabc0985e9630f8272f3226a Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 17 Jun 2015 15:44:08 +0100
|
||||
Subject: [PATCH 046/127] Add Chris Boot's i2c driver
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
i2c-bcm2708: Remove non-DT support
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/i2c/busses/Kconfig | 21 +-
|
||||
drivers/i2c/busses/Makefile | 2 +
|
||||
drivers/i2c/busses/i2c-bcm2708.c | 493 +++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 515 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/i2c/busses/i2c-bcm2708.c
|
||||
|
||||
--- 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 || ARCH_BCM2835
|
||||
+ 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
|
||||
@@ -365,7 +384,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,493 @@
|
||||
+/*
|
||||
+ * 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_WAIT_LOOP_COUNT 200
|
||||
+
|
||||
+#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;
|
||||
+};
|
||||
+
|
||||
+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, adap->timeout);
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ 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;
|
||||
+ case 2:
|
||||
+ adap->class = I2C_CLASS_DDC;
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_err(&pdev->dev, "can only bind to BSC 0, 1 or 2\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);
|
|
@ -0,0 +1,221 @@
|
|||
From 18ec30d7e1571af21c41b687bd12e22f05ffd0b2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 26 Jun 2015 14:27:06 +0200
|
||||
Subject: [PATCH 047/127] char: broadcom: Add vcio module
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add module for accessing the mailbox property channel through
|
||||
/dev/vcio. Was previously in bcm2708-vcio.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/char/broadcom/Kconfig | 6 ++
|
||||
drivers/char/broadcom/Makefile | 1 +
|
||||
drivers/char/broadcom/vcio.c | 175 +++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 182 insertions(+)
|
||||
create mode 100644 drivers/char/broadcom/vcio.c
|
||||
|
||||
--- a/drivers/char/broadcom/Kconfig
|
||||
+++ b/drivers/char/broadcom/Kconfig
|
||||
@@ -22,6 +22,12 @@ config BCM2708_VCMEM
|
||||
help
|
||||
Helper for videocore memory access and total size allocation.
|
||||
|
||||
+config BCM_VCIO
|
||||
+ tristate "Mailbox userspace access"
|
||||
+ depends on BCM2835_MBOX
|
||||
+ help
|
||||
+ Gives access to the mailbox property channel from userspace.
|
||||
+
|
||||
endif
|
||||
|
||||
config BCM_VC_SM
|
||||
--- a/drivers/char/broadcom/Makefile
|
||||
+++ b/drivers/char/broadcom/Makefile
|
||||
@@ -1,5 +1,6 @@
|
||||
obj-$(CONFIG_BCM_VC_CMA) += vc_cma/
|
||||
obj-$(CONFIG_BCM2708_VCMEM) += vc_mem.o
|
||||
+obj-$(CONFIG_BCM_VCIO) += vcio.o
|
||||
obj-$(CONFIG_BCM_VC_SM) += vc_sm/
|
||||
|
||||
obj-$(CONFIG_BCM2835_DEVGPIOMEM)+= bcm2835-gpiomem.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/char/broadcom/vcio.c
|
||||
@@ -0,0 +1,175 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2010 Broadcom
|
||||
+ * Copyright (C) 2015 Noralf Trønnes
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/cdev.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/fs.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/ioctl.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+#define MBOX_CHAN_PROPERTY 8
|
||||
+
|
||||
+#define VCIO_IOC_MAGIC 100
|
||||
+#define IOCTL_MBOX_PROPERTY _IOWR(VCIO_IOC_MAGIC, 0, char *)
|
||||
+
|
||||
+static struct {
|
||||
+ dev_t devt;
|
||||
+ struct cdev cdev;
|
||||
+ struct class *class;
|
||||
+ struct rpi_firmware *fw;
|
||||
+} vcio;
|
||||
+
|
||||
+static int vcio_user_property_list(void *user)
|
||||
+{
|
||||
+ u32 *buf, size;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* The first 32-bit is the size of the buffer */
|
||||
+ if (copy_from_user(&size, user, sizeof(size)))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ buf = kmalloc(size, GFP_KERNEL);
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ if (copy_from_user(buf, user, size)) {
|
||||
+ kfree(buf);
|
||||
+ return -EFAULT;
|
||||
+ }
|
||||
+
|
||||
+ /* Strip off protocol encapsulation */
|
||||
+ ret = rpi_firmware_property_list(vcio.fw, &buf[2], size - 12);
|
||||
+ if (ret) {
|
||||
+ kfree(buf);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ buf[1] = RPI_FIRMWARE_STATUS_SUCCESS;
|
||||
+ if (copy_to_user(user, buf, size))
|
||||
+ ret = -EFAULT;
|
||||
+
|
||||
+ kfree(buf);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int vcio_device_open(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ try_module_get(THIS_MODULE);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vcio_device_release(struct inode *inode, struct file *file)
|
||||
+{
|
||||
+ module_put(THIS_MODULE);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static long vcio_device_ioctl(struct file *file, unsigned int ioctl_num,
|
||||
+ unsigned long ioctl_param)
|
||||
+{
|
||||
+ switch (ioctl_num) {
|
||||
+ case IOCTL_MBOX_PROPERTY:
|
||||
+ return vcio_user_property_list((void *)ioctl_param);
|
||||
+ default:
|
||||
+ pr_err("unknown ioctl: %d\n", ioctl_num);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+const struct file_operations vcio_fops = {
|
||||
+ .unlocked_ioctl = vcio_device_ioctl,
|
||||
+ .open = vcio_device_open,
|
||||
+ .release = vcio_device_release,
|
||||
+};
|
||||
+
|
||||
+static int __init vcio_init(void)
|
||||
+{
|
||||
+ struct device_node *np;
|
||||
+ static struct device *dev;
|
||||
+ int ret;
|
||||
+
|
||||
+ np = of_find_compatible_node(NULL, NULL,
|
||||
+ "raspberrypi,bcm2835-firmware");
|
||||
+/* Uncomment this when we only boot with Device Tree
|
||||
+ if (!of_device_is_available(np))
|
||||
+ return -ENODEV;
|
||||
+*/
|
||||
+ vcio.fw = rpi_firmware_get(np);
|
||||
+ if (!vcio.fw)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ ret = alloc_chrdev_region(&vcio.devt, 0, 1, "vcio");
|
||||
+ if (ret) {
|
||||
+ pr_err("failed to allocate device number\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ cdev_init(&vcio.cdev, &vcio_fops);
|
||||
+ vcio.cdev.owner = THIS_MODULE;
|
||||
+ ret = cdev_add(&vcio.cdev, vcio.devt, 1);
|
||||
+ if (ret) {
|
||||
+ pr_err("failed to register device\n");
|
||||
+ goto err_unregister_chardev;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Create sysfs entries
|
||||
+ * 'bcm2708_vcio' is used for backwards compatibility so we don't break
|
||||
+ * userspace. Raspian has a udev rule that changes the permissions.
|
||||
+ */
|
||||
+ vcio.class = class_create(THIS_MODULE, "bcm2708_vcio");
|
||||
+ if (IS_ERR(vcio.class)) {
|
||||
+ ret = PTR_ERR(vcio.class);
|
||||
+ pr_err("failed to create class\n");
|
||||
+ goto err_cdev_del;
|
||||
+ }
|
||||
+
|
||||
+ dev = device_create(vcio.class, NULL, vcio.devt, NULL, "vcio");
|
||||
+ if (IS_ERR(dev)) {
|
||||
+ ret = PTR_ERR(dev);
|
||||
+ pr_err("failed to create device\n");
|
||||
+ goto err_class_destroy;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_class_destroy:
|
||||
+ class_destroy(vcio.class);
|
||||
+err_cdev_del:
|
||||
+ cdev_del(&vcio.cdev);
|
||||
+err_unregister_chardev:
|
||||
+ unregister_chrdev_region(vcio.devt, 1);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+module_init(vcio_init);
|
||||
+
|
||||
+static void __exit vcio_exit(void)
|
||||
+{
|
||||
+ device_destroy(vcio.class, vcio.devt);
|
||||
+ class_destroy(vcio.class);
|
||||
+ cdev_del(&vcio.cdev);
|
||||
+ unregister_chrdev_region(vcio.devt, 1);
|
||||
+}
|
||||
+module_exit(vcio_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Gray Girling");
|
||||
+MODULE_AUTHOR("Noralf Trønnes");
|
||||
+MODULE_DESCRIPTION("Mailbox userspace access");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,106 @@
|
|||
From 1d1c3e9b18717f6510b67c582e93051a3a948eb6 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Fri, 26 Jun 2015 14:25:01 +0200
|
||||
Subject: [PATCH 048/127] firmware: bcm2835: Support ARCH_BCM270x
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Support booting without Device Tree.
|
||||
Turn on USB power.
|
||||
Load driver early because of lacking support for deferred probing
|
||||
in many drivers.
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
drivers/firmware/raspberrypi.c | 41 +++++++++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 39 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/firmware/raspberrypi.c
|
||||
+++ b/drivers/firmware/raspberrypi.c
|
||||
@@ -28,6 +28,8 @@ struct rpi_firmware {
|
||||
u32 enabled;
|
||||
};
|
||||
|
||||
+static struct platform_device *g_pdev;
|
||||
+
|
||||
static DEFINE_MUTEX(transaction_lock);
|
||||
|
||||
static void response_callback(struct mbox_client *cl, void *msg)
|
||||
@@ -183,6 +185,25 @@ rpi_firmware_print_firmware_revision(str
|
||||
}
|
||||
}
|
||||
|
||||
+static int raspberrypi_firmware_set_power(struct rpi_firmware *fw,
|
||||
+ u32 domain, bool on)
|
||||
+{
|
||||
+ struct {
|
||||
+ u32 domain;
|
||||
+ u32 on;
|
||||
+ } packet;
|
||||
+ int ret;
|
||||
+
|
||||
+ packet.domain = domain;
|
||||
+ packet.on = on;
|
||||
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POWER_STATE,
|
||||
+ &packet, sizeof(packet));
|
||||
+ if (!ret && packet.on != on)
|
||||
+ ret = -EINVAL;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static int rpi_firmware_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -207,9 +228,13 @@ static int rpi_firmware_probe(struct pla
|
||||
init_completion(&fw->c);
|
||||
|
||||
platform_set_drvdata(pdev, fw);
|
||||
+ g_pdev = pdev;
|
||||
|
||||
rpi_firmware_print_firmware_revision(fw);
|
||||
|
||||
+ if (raspberrypi_firmware_set_power(fw, 3, true))
|
||||
+ dev_err(dev, "failed to turn on USB power\n");
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,6 +243,7 @@ static int rpi_firmware_remove(struct pl
|
||||
struct rpi_firmware *fw = platform_get_drvdata(pdev);
|
||||
|
||||
mbox_free_channel(fw->chan);
|
||||
+ g_pdev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -230,7 +256,7 @@ static int rpi_firmware_remove(struct pl
|
||||
*/
|
||||
struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
|
||||
{
|
||||
- struct platform_device *pdev = of_find_device_by_node(firmware_node);
|
||||
+ struct platform_device *pdev = g_pdev;
|
||||
|
||||
if (!pdev)
|
||||
return NULL;
|
||||
@@ -253,7 +279,18 @@ static struct platform_driver rpi_firmwa
|
||||
.probe = rpi_firmware_probe,
|
||||
.remove = rpi_firmware_remove,
|
||||
};
|
||||
-module_platform_driver(rpi_firmware_driver);
|
||||
+
|
||||
+static int __init rpi_firmware_init(void)
|
||||
+{
|
||||
+ return platform_driver_register(&rpi_firmware_driver);
|
||||
+}
|
||||
+subsys_initcall(rpi_firmware_init);
|
||||
+
|
||||
+static void __init rpi_firmware_exit(void)
|
||||
+{
|
||||
+ platform_driver_unregister(&rpi_firmware_driver);
|
||||
+}
|
||||
+module_exit(rpi_firmware_exit);
|
||||
|
||||
MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
|
||||
MODULE_DESCRIPTION("Raspberry Pi firmware driver");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,461 @@
|
|||
From 4ddb3fae0a5c5b6969168134b4352bceccf51b9c Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 11 May 2015 09:00:42 +0100
|
||||
Subject: [PATCH 050/127] 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/mkknlimg: Improve ARCH_BCM2835 detection
|
||||
|
||||
The board support code contains sufficient strings to be able to
|
||||
distinguish 2708 vs. 2835 builds, so remove the check for
|
||||
bcm2835-pm-wdt which could exist in either.
|
||||
|
||||
Also, since the canned configuration is no longer built in (it's
|
||||
a module), remove the config string checking.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1157
|
||||
---
|
||||
scripts/knlinfo | 168 ++++++++++++++++++++++++++++++++++++++
|
||||
scripts/mkknlimg | 244 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 412 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,244 @@
|
||||
+#!/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_strings =
|
||||
+(
|
||||
+ 'bcm2708_fb',
|
||||
+ 'brcm,bcm2835-mmc',
|
||||
+ 'brcm,bcm2835-sdhost',
|
||||
+ 'brcm,bcm2708-pinctrl',
|
||||
+ 'brcm,bcm2835-gpio',
|
||||
+ 'brcm,bcm2835',
|
||||
+ 'brcm,bcm2836'
|
||||
+);
|
||||
+
|
||||
+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, 'brcm,bcm2708-pinctrl');
|
||||
+ $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
|
||||
+ $is_283x ||= config_bool($res, 'brcm,bcm2835');
|
||||
+ $is_283x ||= config_bool($res, 'brcm,bcm2836');
|
||||
+ $dtok ||= $is_283x;
|
||||
+ $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;
|
||||
+ }
|
||||
+
|
||||
+ 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'));
|
||||
+}
|
|
@ -0,0 +1,58 @@
|
|||
From 3f46d3627061688e50e24d5bfbc0adb5deb89b97 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 5 Dec 2014 17:26:26 +0000
|
||||
Subject: [PATCH 051/127] 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
|
||||
@@ -954,22 +954,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
|
@ -0,0 +1,515 @@
|
|||
From 1cb8b3610957f9c892a7eb6e18b99eca0ac7a77d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
|
||||
Date: Sat, 15 Aug 2015 20:47:07 +0200
|
||||
Subject: [PATCH 053/127] bcm2835: Match with BCM2708 Device Trees
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
|
||||
---
|
||||
arch/arm/boot/dts/bcm2835-rpi-b-plus.dts | 132 ++++++++++++++++++---
|
||||
arch/arm/boot/dts/bcm2835-rpi-b.dts | 115 ++++++++++++++++--
|
||||
arch/arm/boot/dts/bcm2835.dtsi | 195 +++----------------------------
|
||||
3 files changed, 237 insertions(+), 205 deletions(-)
|
||||
|
||||
--- a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
|
||||
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
|
||||
@@ -1,30 +1,128 @@
|
||||
/dts-v1/;
|
||||
-#include "bcm2835-rpi.dtsi"
|
||||
+#include "bcm2835.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
|
||||
model = "Raspberry Pi Model B+";
|
||||
-
|
||||
- leds {
|
||||
- act {
|
||||
- gpios = <&gpio 47 0>;
|
||||
- };
|
||||
-
|
||||
- pwr {
|
||||
- label = "PWR";
|
||||
- gpios = <&gpio 35 0>;
|
||||
- default-state = "keep";
|
||||
- linux,default-trigger = "default-on";
|
||||
- };
|
||||
- };
|
||||
};
|
||||
|
||||
&gpio {
|
||||
- pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
|
||||
+ 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>;
|
||||
+ };
|
||||
|
||||
- /* I2S interface */
|
||||
- i2s_alt0: i2s_alt0 {
|
||||
+ i2c1_pins: i2c1 {
|
||||
+ brcm,pins = <2 3>;
|
||||
+ brcm,function = <4>;
|
||||
+ };
|
||||
+
|
||||
+ i2s_pins: i2s {
|
||||
brcm,pins = <18 19 20 21>;
|
||||
- brcm,function = <BCM2835_FSEL_ALT0>;
|
||||
+ brcm,function = <4>; /* alt0 */
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+&mmc {
|
||||
+ status = "okay";
|
||||
+ bus-width = <4>;
|
||||
+};
|
||||
+
|
||||
+&fb {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&uart0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&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>;
|
||||
+};
|
||||
+
|
||||
+&i2c2 {
|
||||
+ clock-frequency = <100000>;
|
||||
+};
|
||||
+
|
||||
+&i2s {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&i2s_pins>;
|
||||
+};
|
||||
+
|
||||
+&leds {
|
||||
+ act_led: act {
|
||||
+ label = "led0";
|
||||
+ linux,default-trigger = "mmc0";
|
||||
+ gpios = <&gpio 47 0>;
|
||||
+ };
|
||||
+
|
||||
+ pwr_led: pwr {
|
||||
+ label = "led1";
|
||||
+ linux,default-trigger = "input";
|
||||
+ gpios = <&gpio 35 0>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+/ {
|
||||
+ __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";
|
||||
+ 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";
|
||||
+ act_led_activelow = <&act_led>,"gpios:8";
|
||||
+ act_led_trigger = <&act_led>,"linux,default-trigger";
|
||||
+
|
||||
+ pwr_led_gpio = <&pwr_led>,"gpios:4";
|
||||
+ pwr_led_activelow = <&pwr_led>,"gpios:8";
|
||||
+ pwr_led_trigger = <&pwr_led>,"linux,default-trigger";
|
||||
+
|
||||
+ audio = <&audio>,"status";
|
||||
+ watchdog = <&watchdog>,"status";
|
||||
+ random = <&random>,"status";
|
||||
};
|
||||
};
|
||||
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
|
||||
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
|
||||
@@ -1,17 +1,118 @@
|
||||
/dts-v1/;
|
||||
-#include "bcm2835-rpi.dtsi"
|
||||
+#include "bcm2835.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "raspberrypi,model-b", "brcm,bcm2835";
|
||||
model = "Raspberry Pi Model B";
|
||||
+};
|
||||
|
||||
- leds {
|
||||
- act {
|
||||
- gpios = <&gpio 16 1>;
|
||||
- };
|
||||
+&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 = <28 29 30 31>;
|
||||
+ brcm,function = <6>; /* alt2 */
|
||||
};
|
||||
};
|
||||
|
||||
-&gpio {
|
||||
- pinctrl-0 = <&gpioout &alt0 &alt3>;
|
||||
+&mmc {
|
||||
+ status = "okay";
|
||||
+ bus-width = <4>;
|
||||
+};
|
||||
+
|
||||
+&fb {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&uart0 {
|
||||
+ status = "okay";
|
||||
+};
|
||||
+
|
||||
+&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>;
|
||||
+};
|
||||
+
|
||||
+&i2c2 {
|
||||
+ clock-frequency = <100000>;
|
||||
+};
|
||||
+
|
||||
+&i2s {
|
||||
+ #sound-dai-cells = <0>;
|
||||
+ pinctrl-names = "default";
|
||||
+ pinctrl-0 = <&i2s_pins>;
|
||||
+};
|
||||
+
|
||||
+&leds {
|
||||
+ act_led: act {
|
||||
+ label = "led0";
|
||||
+ linux,default-trigger = "mmc0";
|
||||
+ gpios = <&gpio 16 1>;
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+/ {
|
||||
+ __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";
|
||||
+ 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";
|
||||
+ act_led_activelow = <&act_led>,"gpios:8";
|
||||
+ act_led_trigger = <&act_led>,"linux,default-trigger";
|
||||
+
|
||||
+ audio = <&audio>,"status";
|
||||
+ watchdog = <&watchdog>,"status";
|
||||
+ random = <&random>,"status";
|
||||
+ };
|
||||
};
|
||||
--- a/arch/arm/boot/dts/bcm2835.dtsi
|
||||
+++ b/arch/arm/boot/dts/bcm2835.dtsi
|
||||
@@ -1,206 +1,39 @@
|
||||
-#include <dt-bindings/pinctrl/bcm2835.h>
|
||||
-#include <dt-bindings/clock/bcm2835.h>
|
||||
-#include "skeleton.dtsi"
|
||||
+#include "bcm2708_common.dtsi"
|
||||
|
||||
/ {
|
||||
compatible = "brcm,bcm2835";
|
||||
model = "BCM2835";
|
||||
- interrupt-parent = <&intc>;
|
||||
|
||||
chosen {
|
||||
- bootargs = "earlyprintk console=ttyAMA0";
|
||||
+ bootargs = "";
|
||||
};
|
||||
|
||||
soc {
|
||||
- compatible = "simple-bus";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <1>;
|
||||
- ranges = <0x7e000000 0x20000000 0x02000000>;
|
||||
+ ranges = <0x7e000000 0x20000000 0x01000000>;
|
||||
dma-ranges = <0x40000000 0x00000000 0x20000000>;
|
||||
|
||||
timer@7e003000 {
|
||||
compatible = "brcm,bcm2835-system-timer";
|
||||
reg = <0x7e003000 0x1000>;
|
||||
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
|
||||
- /* This could be a reference to BCM2835_CLOCK_TIMER,
|
||||
- * but we don't have the driver using the common clock
|
||||
- * support yet.
|
||||
- */
|
||||
clock-frequency = <1000000>;
|
||||
};
|
||||
|
||||
- dma: dma@7e007000 {
|
||||
- compatible = "brcm,bcm2835-dma";
|
||||
- reg = <0x7e007000 0xf00>;
|
||||
- interrupts = <1 16>,
|
||||
- <1 17>,
|
||||
- <1 18>,
|
||||
- <1 19>,
|
||||
- <1 20>,
|
||||
- <1 21>,
|
||||
- <1 22>,
|
||||
- <1 23>,
|
||||
- <1 24>,
|
||||
- <1 25>,
|
||||
- <1 26>,
|
||||
- <1 27>,
|
||||
- <1 28>;
|
||||
-
|
||||
- #dma-cells = <1>;
|
||||
- brcm,dma-channel-mask = <0x7f35>;
|
||||
- };
|
||||
-
|
||||
- intc: interrupt-controller@7e00b200 {
|
||||
- compatible = "brcm,bcm2835-armctrl-ic";
|
||||
- reg = <0x7e00b200 0x200>;
|
||||
- interrupt-controller;
|
||||
- #interrupt-cells = <2>;
|
||||
- };
|
||||
-
|
||||
- watchdog@7e100000 {
|
||||
- compatible = "brcm,bcm2835-pm-wdt";
|
||||
- reg = <0x7e100000 0x28>;
|
||||
- };
|
||||
-
|
||||
- clocks: cprman@7e101000 {
|
||||
- compatible = "brcm,bcm2835-cprman";
|
||||
- #clock-cells = <1>;
|
||||
- reg = <0x7e101000 0x2000>;
|
||||
-
|
||||
- /* CPRMAN derives everything from the platform's
|
||||
- * oscillator.
|
||||
- */
|
||||
- clocks = <&clk_osc>;
|
||||
- };
|
||||
-
|
||||
- rng@7e104000 {
|
||||
- compatible = "brcm,bcm2835-rng";
|
||||
- reg = <0x7e104000 0x10>;
|
||||
- };
|
||||
-
|
||||
- mailbox: mailbox@7e00b800 {
|
||||
- compatible = "brcm,bcm2835-mbox";
|
||||
- reg = <0x7e00b880 0x40>;
|
||||
- interrupts = <0 1>;
|
||||
- #mbox-cells = <0>;
|
||||
- };
|
||||
-
|
||||
- gpio: gpio@7e200000 {
|
||||
- compatible = "brcm,bcm2835-gpio";
|
||||
- reg = <0x7e200000 0xb4>;
|
||||
- /*
|
||||
- * The GPIO IP block is designed for 3 banks of GPIOs.
|
||||
- * Each bank has a GPIO interrupt for itself.
|
||||
- * There is an overall "any bank" interrupt.
|
||||
- * In order, these are GIC interrupts 17, 18, 19, 20.
|
||||
- * Since the BCM2835 only has 2 banks, the 2nd bank
|
||||
- * interrupt output appears to be mirrored onto the
|
||||
- * 3rd bank's interrupt signal.
|
||||
- * So, a bank0 interrupt shows up on 17, 20, and
|
||||
- * a bank1 interrupt shows up on 18, 19, 20!
|
||||
- */
|
||||
- interrupts = <2 17>, <2 18>, <2 19>, <2 20>;
|
||||
-
|
||||
- gpio-controller;
|
||||
- #gpio-cells = <2>;
|
||||
-
|
||||
- interrupt-controller;
|
||||
- #interrupt-cells = <2>;
|
||||
- };
|
||||
-
|
||||
- uart0: uart@7e201000 {
|
||||
- compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
|
||||
- reg = <0x7e201000 0x1000>;
|
||||
- interrupts = <2 25>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_UART>,
|
||||
- <&clocks BCM2835_CLOCK_VPU>;
|
||||
- clock-names = "uartclk", "apb_pclk";
|
||||
- arm,primecell-periphid = <0x00241011>;
|
||||
- };
|
||||
-
|
||||
- i2s: i2s@7e203000 {
|
||||
- compatible = "brcm,bcm2835-i2s";
|
||||
- reg = <0x7e203000 0x24>,
|
||||
- <0x7e101098 0x08>;
|
||||
-
|
||||
- dmas = <&dma 2>,
|
||||
- <&dma 3>;
|
||||
- dma-names = "tx", "rx";
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- spi: spi@7e204000 {
|
||||
- compatible = "brcm,bcm2835-spi";
|
||||
- reg = <0x7e204000 0x1000>;
|
||||
- interrupts = <2 22>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- i2c0: i2c@7e205000 {
|
||||
- compatible = "brcm,bcm2835-i2c";
|
||||
- reg = <0x7e205000 0x1000>;
|
||||
- interrupts = <2 21>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- sdhci: sdhci@7e300000 {
|
||||
- compatible = "brcm,bcm2835-sdhci";
|
||||
- reg = <0x7e300000 0x100>;
|
||||
- interrupts = <2 30>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_EMMC>;
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- i2c1: i2c@7e804000 {
|
||||
- compatible = "brcm,bcm2835-i2c";
|
||||
- reg = <0x7e804000 0x1000>;
|
||||
- interrupts = <2 21>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- i2c2: i2c@7e805000 {
|
||||
- compatible = "brcm,bcm2835-i2c";
|
||||
- reg = <0x7e805000 0x1000>;
|
||||
- interrupts = <2 21>;
|
||||
- clocks = <&clocks BCM2835_CLOCK_VPU>;
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
- status = "disabled";
|
||||
- };
|
||||
-
|
||||
- usb@7e980000 {
|
||||
- compatible = "brcm,bcm2835-usb";
|
||||
- reg = <0x7e980000 0x10000>;
|
||||
- interrupts = <1 9>;
|
||||
- };
|
||||
-
|
||||
arm-pmu {
|
||||
compatible = "arm,arm1176-pmu";
|
||||
};
|
||||
- };
|
||||
|
||||
- clocks {
|
||||
- compatible = "simple-bus";
|
||||
- #address-cells = <1>;
|
||||
- #size-cells = <0>;
|
||||
-
|
||||
- /* The oscillator is the root of the clock tree. */
|
||||
- clk_osc: clock@3 {
|
||||
- compatible = "fixed-clock";
|
||||
- reg = <3>;
|
||||
- #clock-cells = <0>;
|
||||
- clock-output-names = "osc";
|
||||
- clock-frequency = <19200000>;
|
||||
+ aux_enable: aux_enable@0x7e215004 {
|
||||
+ compatible = "bcrm,bcm2835-aux-enable";
|
||||
+ reg = <0x7e215004 0x04>;
|
||||
};
|
||||
-
|
||||
};
|
||||
};
|
||||
+
|
||||
+&intc {
|
||||
+ compatible = "brcm,bcm2835-armctrl-ic";
|
||||
+};
|
||||
+
|
||||
+&watchdog {
|
||||
+ status = "okay";
|
||||
+};
|
|
@ -0,0 +1,91 @@
|
|||
From 6faba148320fb8fc49b5cf5e5ef7864d9a1c0fd9 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 054/127] 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(©, argp, sizeof(copy)))
|
||||
+ return -EFAULT;
|
||||
+ ret = fb_copyarea_user(info, ©);
|
||||
+ 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 */
|
|
@ -0,0 +1,209 @@
|
|||
From a205b536eaf4693151d5f375426b470ed1eaa4ed Mon Sep 17 00:00:00 2001
|
||||
From: Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
Date: Thu, 20 Jun 2013 20:21:39 +0200
|
||||
Subject: [PATCH 058/127] 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
|
|
@ -0,0 +1,91 @@
|
|||
From 43512b5f55e891f325a7619fa9103e6d6566ce81 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 26 Mar 2013 17:26:38 +0000
|
||||
Subject: [PATCH 059/127] 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 = false;
|
||||
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) {
|
|
@ -0,0 +1,242 @@
|
|||
From 1dde78801877dc5280b7b1b156a2784d7e2bf982 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 8 May 2013 11:46:50 +0100
|
||||
Subject: [PATCH 060/127] 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
|
||||
---
|
||||
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 +
|
||||
5 files changed, 99 insertions(+), 9 deletions(-)
|
||||
|
||||
--- 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
|
||||
@@ -122,6 +122,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;
|
|
@ -0,0 +1,22 @@
|
|||
From 61a3c58b47a8a2b970a1ca50db15c402874eb8fd Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:54:08 +0100
|
||||
Subject: [PATCH 061/127] 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
|
||||
@@ -1900,6 +1900,10 @@ static const struct usb_device_id rtl28x
|
||||
&rtl28xxu_props, "Compro VideoMate U650F", 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,
|
|
@ -0,0 +1,49 @@
|
|||
From bbc71e816c6bf3d945e67a70db005d1f58b2b064 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 18 Dec 2013 22:16:19 +0000
|
||||
Subject: [PATCH 062/127] config: Enable CONFIG_MEMCG, but leave it disabled
|
||||
(due to memory cost). Enable with cgroup_enable=memory.
|
||||
|
||||
---
|
||||
kernel/cgroup.c | 23 ++++++++++++++++++++++-
|
||||
1 file changed, 22 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/kernel/cgroup.c
|
||||
+++ b/kernel/cgroup.c
|
||||
@@ -5273,7 +5273,7 @@ int __init cgroup_init_early(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static unsigned long cgroup_disable_mask __initdata;
|
||||
+static unsigned long cgroup_disable_mask __initdata = 1<<0;
|
||||
|
||||
/**
|
||||
* cgroup_init - cgroup initialization
|
||||
@@ -5769,6 +5769,27 @@ 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) &&
|
||||
+ strcmp(token, ss->legacy_name))
|
||||
+ continue;
|
||||
+ cgroup_disable_mask &= ~(1 << i);
|
||||
+ }
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+__setup("cgroup_enable=", cgroup_enable);
|
||||
+
|
||||
/**
|
||||
* css_tryget_online_from_dir - get corresponding css from a cgroup dentry
|
||||
* @dentry: directory dentry of interest
|
|
@ -0,0 +1,128 @@
|
|||
From 7ae297c051ae9052562cd97de4b19d05afb4c9ee 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 063/127] 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 | 5 ++++
|
||||
sound/soc/codecs/Makefile | 2 ++
|
||||
sound/soc/codecs/pcm5102a.c | 70 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 77 insertions(+)
|
||||
create mode 100644 sound/soc/codecs/pcm5102a.c
|
||||
|
||||
--- a/sound/soc/codecs/Kconfig
|
||||
+++ b/sound/soc/codecs/Kconfig
|
||||
@@ -89,6 +89,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_PCM512x_SPI if SPI_MASTER
|
||||
select SND_SOC_RT286 if I2C
|
||||
select SND_SOC_RT298 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
|
||||
@@ -549,6 +550,10 @@ config SND_SOC_RT298
|
||||
tristate
|
||||
depends on I2C
|
||||
|
||||
+config SND_SOC_PCM5102A
|
||||
+ tristate
|
||||
+ depends on I2C
|
||||
+
|
||||
config SND_SOC_RT5631
|
||||
tristate "Realtek ALC5631/RT5631 CODEC"
|
||||
depends on I2C
|
||||
--- a/sound/soc/codecs/Makefile
|
||||
+++ b/sound/soc/codecs/Makefile
|
||||
@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
|
||||
snd-soc-rl6347a-objs := rl6347a.o
|
||||
snd-soc-rt286-objs := rt286.o
|
||||
snd-soc-rt298-objs := rt298.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
|
||||
@@ -280,6 +281,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
|
||||
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
|
||||
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
|
||||
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.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,70 @@
|
||||
+/*
|
||||
+ * 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 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,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(pcm5102a_codec_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
|
||||
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,165 @@
|
|||
From 7376e0edee3df655d9176ee83f21c58b8f067207 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 064/127] 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 | 4 ++
|
||||
sound/soc/bcm/hifiberry_dac.c | 122 ++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 133 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/hifiberry_dac.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -7,3 +7,10 @@ config SND_BCM2835_SOC_I2S
|
||||
Say Y or M if you want to add support for codecs attached to
|
||||
the BCM2835 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
|
||||
@@ -3,3 +3,7 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.
|
||||
|
||||
obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-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,122 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_dac_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ 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,
|
||||
+};
|
||||
+
|
||||
+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");
|
|
@ -0,0 +1,275 @@
|
|||
From e6877f42823f6acd80d27b86816a0d87f35ea004 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 065/127] ASoC: Add support for Rpi-DAC
|
||||
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 7 +++
|
||||
sound/soc/bcm/Makefile | 2 +
|
||||
sound/soc/bcm/rpi-dac.c | 118 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
sound/soc/codecs/Kconfig | 9 ++++
|
||||
sound/soc/codecs/Makefile | 2 +
|
||||
sound/soc/codecs/pcm1794a.c | 69 ++++++++++++++++++++++++++
|
||||
6 files changed, 207 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/rpi-dac.c
|
||||
create mode 100644 sound/soc/codecs/pcm1794a.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -14,3 +14,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
|
||||
@@ -5,5 +5,7 @@ obj-$(CONFIG_SND_BCM2835_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,118 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_rpi_dac_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ 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,
|
||||
+};
|
||||
+
|
||||
+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
|
||||
@@ -90,6 +90,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_RT286 if I2C
|
||||
select SND_SOC_RT298 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
|
||||
@@ -550,6 +551,14 @@ config SND_SOC_RT298
|
||||
tristate
|
||||
depends on I2C
|
||||
|
||||
+config SND_SOC_RT298
|
||||
+ tristate
|
||||
+ depends on I2C
|
||||
+
|
||||
+config SND_SOC_PCM1794A
|
||||
+ tristate
|
||||
+ depends on I2C
|
||||
+
|
||||
config SND_SOC_PCM5102A
|
||||
tristate
|
||||
depends on I2C
|
||||
--- a/sound/soc/codecs/Makefile
|
||||
+++ b/sound/soc/codecs/Makefile
|
||||
@@ -85,6 +85,7 @@ snd-soc-rl6231-objs := rl6231.o
|
||||
snd-soc-rl6347a-objs := rl6347a.o
|
||||
snd-soc-rt286-objs := rt286.o
|
||||
snd-soc-rt298-objs := rt298.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
|
||||
@@ -281,6 +282,7 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-
|
||||
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
|
||||
obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
|
||||
obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.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,69 @@
|
||||
+/*
|
||||
+ * 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 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),
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(pcm1794a_codec_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
|
||||
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,40 @@
|
|||
From 10534ba846800325cf08f6e2479dbebecda00d2d 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 066/127] 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 | \
|
|
@ -0,0 +1,282 @@
|
|||
From bbeffde8da0be5674342d1f2301d8d9bdc56d2d5 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 067/127] 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 | 223 +++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 232 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/hifiberry_digi.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -15,6 +15,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
|
||||
@@ -5,7 +5,9 @@ obj-$(CONFIG_SND_BCM2835_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,223 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ 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,
|
||||
+};
|
||||
+
|
||||
+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");
|
|
@ -0,0 +1,22 @@
|
|||
From 931556f39a5c08c682d31b0b8c25bf1c712a909f 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 068/127] 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),
|
|
@ -0,0 +1,178 @@
|
|||
From 288238307a79e6978bb475bac7098832ca3de373 Mon Sep 17 00:00:00 2001
|
||||
From: Gordon Garrity <gordon@iqaudio.com>
|
||||
Date: Sat, 8 Mar 2014 16:56:57 +0000
|
||||
Subject: [PATCH 069/127] 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.
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 7 +++
|
||||
sound/soc/bcm/Makefile | 2 +
|
||||
sound/soc/bcm/iqaudio-dac.c | 132 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 141 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/iqaudio-dac.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -28,3 +28,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
|
||||
@@ -7,7 +7,9 @@ obj-$(CONFIG_SND_BCM2835_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,132 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "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;
|
||||
+
|
||||
+ 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,
|
||||
+ "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", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, iqaudio_of_match);
|
||||
+
|
||||
+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");
|
|
@ -0,0 +1,36 @@
|
|||
From 7f78dfe7e00d426d90be5f98ac9683c83c024b28 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 22:02:09 +0100
|
||||
Subject: [PATCH 070/127] 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");
|
||||
|
||||
@@ -1091,8 +1091,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)) {
|
|
@ -0,0 +1,190 @@
|
|||
From 21d1427a7563d56ca1fdcee66cb80e7f2879c6b8 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 071/127] 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.
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 7 ++
|
||||
sound/soc/bcm/Makefile | 2 +
|
||||
sound/soc/bcm/hifiberry_dacplus.c | 141 ++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 150 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/hifiberry_dacplus.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -15,6 +15,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
|
||||
@@ -5,11 +5,13 @@ obj-$(CONFIG_SND_BCM2835_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,141 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+
|
||||
+ 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,
|
||||
+ "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 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,
|
||||
+};
|
||||
+
|
||||
+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");
|
|
@ -0,0 +1,816 @@
|
|||
From f9201b45dcaa09fc1e85ca9fe011db801c0c12b5 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 072/127] 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.
|
||||
---
|
||||
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 ++++++++++++++++++++++++
|
||||
7 files changed, 721 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/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -29,6 +29,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
|
||||
@@ -7,11 +7,13 @@ obj-$(CONFIG_SND_BCM2835_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
|
||||
@@ -117,6 +117,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
|
||||
@@ -674,6 +675,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
|
||||
@@ -118,6 +118,7 @@ snd-soc-sti-sas-objs := sti-sas.o
|
||||
snd-soc-tas5086-objs := tas5086.o
|
||||
snd-soc-tas571x-objs := tas571x.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
|
||||
@@ -312,6 +313,7 @@ obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc
|
||||
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
|
||||
obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.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 */
|
|
@ -0,0 +1,27 @@
|
|||
From 0a44043b0586ca2ea7f4af174ba18188c8dced82 Mon Sep 17 00:00:00 2001
|
||||
From: Ryan Coe <bluemrp9@gmail.com>
|
||||
Date: Sat, 31 Jan 2015 18:25:49 -0700
|
||||
Subject: [PATCH 073/127] 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
|
||||
@@ -1207,6 +1207,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",
|
|
@ -0,0 +1,170 @@
|
|||
From 8629cfc983fbca391421dec0644a34ffe29b5c9e Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 6 Feb 2015 13:50:57 +0000
|
||||
Subject: [PATCH 074/127] 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.
|
||||
|
||||
leds-gpio: Implement the brightness_get method
|
||||
|
||||
The power LED uses some clever logic that means it is driven
|
||||
by a voltage measuring circuit when configured as input, otherwise
|
||||
it is driven by the GPIO output value. This patch wires up the
|
||||
brightness_get method for leds-gpio so that user-space can monitor
|
||||
the LED value via /sys/class/gpio/led1/brightness. Using the input
|
||||
trigger this returns an indication of the system power health,
|
||||
otherwise it is just whatever value the trigger has written most
|
||||
recently.
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1064
|
||||
---
|
||||
drivers/leds/leds-gpio.c | 18 +++++++++++-
|
||||
drivers/leds/trigger/Kconfig | 7 +++++
|
||||
drivers/leds/trigger/Makefile | 1 +
|
||||
drivers/leds/trigger/ledtrig-input.c | 54 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/leds.h | 3 ++
|
||||
5 files changed, 82 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/leds/trigger/ledtrig-input.c
|
||||
|
||||
--- a/drivers/leds/leds-gpio.c
|
||||
+++ b/drivers/leds/leds-gpio.c
|
||||
@@ -42,6 +42,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);
|
||||
}
|
||||
@@ -62,7 +69,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 {
|
||||
@@ -75,6 +83,13 @@ static void gpio_led_set(struct led_clas
|
||||
}
|
||||
}
|
||||
|
||||
+static enum led_brightness gpio_led_get(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct gpio_led_data *led_dat =
|
||||
+ container_of(led_cdev, struct gpio_led_data, cdev);
|
||||
+ return gpiod_get_value_cansleep(led_dat->gpiod) ? LED_FULL : LED_OFF;
|
||||
+}
|
||||
+
|
||||
static int gpio_blink_set(struct led_classdev *led_cdev,
|
||||
unsigned long *delay_on, unsigned long *delay_off)
|
||||
{
|
||||
@@ -131,6 +146,7 @@ static int create_gpio_led(const struct
|
||||
led_dat->cdev.blink_set = gpio_blink_set;
|
||||
}
|
||||
led_dat->cdev.brightness_set = gpio_led_set;
|
||||
+ led_dat->cdev.brightness_get = gpio_led_get;
|
||||
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
|
||||
state = !!gpiod_get_value_cansleep(led_dat->gpiod);
|
||||
else
|
||||
--- 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,54 @@
|
||||
+/*
|
||||
+ * 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"
|
||||
+
|
||||
+static void input_trig_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ led_cdev->flags |= SET_GPIO_INPUT;
|
||||
+ led_set_brightness_async(led_cdev, 0);
|
||||
+}
|
||||
+
|
||||
+static void input_trig_deactivate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ led_cdev->flags |= SET_GPIO_OUTPUT;
|
||||
+ led_set_brightness_async(led_cdev, 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");
|
||||
--- a/include/linux/leds.h
|
||||
+++ b/include/linux/leds.h
|
||||
@@ -48,6 +48,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 */
|
|
@ -0,0 +1,29 @@
|
|||
From 5bdfbb8eafe9c92e60031502980207f55c0092ce Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 27 Feb 2015 15:10:24 +0000
|
||||
Subject: [PATCH 075/127] enc28j60: Add device tree compatible string and an
|
||||
overlay
|
||||
|
||||
---
|
||||
drivers/net/ethernet/microchip/enc28j60.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/microchip/enc28j60.c
|
||||
+++ b/drivers/net/ethernet/microchip/enc28j60.c
|
||||
@@ -1630,9 +1630,16 @@ static int enc28j60_remove(struct spi_de
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const struct of_device_id enc28j60_of_match[] = {
|
||||
+ { .compatible = "microchip,enc28j60", },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, enc28j60_of_match);
|
||||
+
|
||||
static struct spi_driver enc28j60_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
+ .of_match_table = enc28j60_of_match,
|
||||
},
|
||||
.probe = enc28j60_probe,
|
||||
.remove = enc28j60_remove,
|
|
@ -0,0 +1,210 @@
|
|||
From e3dc96afd80658ed5ad61c6f58dd45979abdcc61 Mon Sep 17 00:00:00 2001
|
||||
From: Waldemar Brodkorb <wbrodkorb@conet.de>
|
||||
Date: Wed, 25 Mar 2015 09:26:17 +0100
|
||||
Subject: [PATCH 076/127] 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
|
||||
@@ -43,6 +43,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
|
||||
@@ -9,6 +9,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
|
||||
@@ -16,4 +17,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");
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,290 @@
|
|||
From 5152e89db66a2004ebd3d1629b4c1656672c3c37 Mon Sep 17 00:00:00 2001
|
||||
From: Gordon Hollingworth <gordon@raspberrypi.org>
|
||||
Date: Tue, 12 May 2015 14:47:56 +0100
|
||||
Subject: [PATCH 079/127] rpi-ft5406: Add touchscreen driver for pi LCD display
|
||||
|
||||
Fix driver detection failure Check that the buffer response is non-zero meaning the touchscreen was detected
|
||||
|
||||
rpi-ft5406: Use firmware API
|
||||
---
|
||||
drivers/input/touchscreen/Kconfig | 7 +
|
||||
drivers/input/touchscreen/Makefile | 1 +
|
||||
drivers/input/touchscreen/rpi-ft5406.c | 246 +++++++++++++++++++++++++++++++++
|
||||
3 files changed, 254 insertions(+)
|
||||
create mode 100644 drivers/input/touchscreen/rpi-ft5406.c
|
||||
|
||||
--- a/drivers/input/touchscreen/Kconfig
|
||||
+++ b/drivers/input/touchscreen/Kconfig
|
||||
@@ -608,6 +608,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 RASPBERRYPI_FIRMWARE
|
||||
+ 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,246 @@
|
||||
+/*
|
||||
+ * 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 <soc/bcm2835/raspberrypi-firmware.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;
|
||||
+};
|
||||
+
|
||||
+/* 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_interruptible(17);
|
||||
+ memcpy_fromio(®s, 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 ft5406 * ts;
|
||||
+ struct device_node *fw_node;
|
||||
+ struct rpi_firmware *fw;
|
||||
+ u32 touchbuf;
|
||||
+
|
||||
+ dev_info(&pdev->dev, "Probing device\n");
|
||||
+
|
||||
+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
|
||||
+ if (!fw_node) {
|
||||
+ dev_err(&pdev->dev, "Missing firmware node\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ fw = rpi_firmware_get(fw_node);
|
||||
+ if (!fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ ret = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_GET_TOUCHBUF,
|
||||
+ &touchbuf, sizeof(touchbuf));
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Failed to get touch buffer\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (!touchbuf) {
|
||||
+ dev_err(&pdev->dev, "Touchscreen not detected\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ dev_dbg(&pdev->dev, "Got TS buffer 0x%x\n", touchbuf);
|
||||
+
|
||||
+ 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;
|
||||
+ }
|
||||
+
|
||||
+ // mmap the physical memory
|
||||
+ touchbuf &= ~0xc0000000;
|
||||
+ ts->ts_base = ioremap(touchbuf, 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 -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ 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");
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,35 @@
|
|||
From 5a7fddeb5dfd0dd291363dcab556006a02297d13 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 25 Jun 2015 12:16:11 +0100
|
||||
Subject: [PATCH 081/127] 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.
|
||||
---
|
||||
drivers/power/reset/gpio-poweroff.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/power/reset/gpio-poweroff.c
|
||||
+++ b/drivers/power/reset/gpio-poweroff.c
|
||||
@@ -49,9 +49,11 @@ static int gpio_poweroff_probe(struct pl
|
||||
{
|
||||
bool input = false;
|
||||
enum gpiod_flags flags;
|
||||
+ 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__);
|
|
@ -0,0 +1,21 @@
|
|||
From ab8626a92ca2308de52a1db26b10ab4ecc3a1be7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 14 Jul 2015 10:26:09 +0100
|
||||
Subject: [PATCH 082/127] spidev: Add "spidev" compatible string to silence
|
||||
warning
|
||||
|
||||
See: https://github.com/raspberrypi/linux/issues/1054
|
||||
---
|
||||
drivers/spi/spidev.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -695,6 +695,7 @@ static struct class *spidev_class;
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
{ .compatible = "lineartechnology,ltc2488" },
|
||||
+ { .compatible = "spidev" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,838 @@
|
|||
From 933c347e34871491afd9d53c7a9d0bf3c283c41f Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <pelwell@users.noreply.github.com>
|
||||
Date: Tue, 14 Jul 2015 14:32:47 +0100
|
||||
Subject: [PATCH 084/127] mfd: Add Raspberry Pi Sense HAT core driver
|
||||
|
||||
---
|
||||
drivers/input/joystick/Kconfig | 8 +
|
||||
drivers/input/joystick/Makefile | 1 +
|
||||
drivers/input/joystick/rpisense-js.c | 153 ++++++++++++++++
|
||||
drivers/mfd/Kconfig | 8 +
|
||||
drivers/mfd/Makefile | 2 +
|
||||
drivers/mfd/rpisense-core.c | 157 +++++++++++++++++
|
||||
drivers/video/fbdev/Kconfig | 13 ++
|
||||
drivers/video/fbdev/Makefile | 1 +
|
||||
drivers/video/fbdev/rpisense-fb.c | 293 +++++++++++++++++++++++++++++++
|
||||
include/linux/mfd/rpisense/core.h | 47 +++++
|
||||
include/linux/mfd/rpisense/framebuffer.h | 32 ++++
|
||||
include/linux/mfd/rpisense/joystick.h | 35 ++++
|
||||
12 files changed, 750 insertions(+)
|
||||
create mode 100644 drivers/input/joystick/rpisense-js.c
|
||||
create mode 100644 drivers/mfd/rpisense-core.c
|
||||
create mode 100644 drivers/video/fbdev/rpisense-fb.c
|
||||
create mode 100644 include/linux/mfd/rpisense/core.h
|
||||
create mode 100644 include/linux/mfd/rpisense/framebuffer.h
|
||||
create mode 100644 include/linux/mfd/rpisense/joystick.h
|
||||
|
||||
--- a/drivers/input/joystick/Kconfig
|
||||
+++ b/drivers/input/joystick/Kconfig
|
||||
@@ -330,4 +330,12 @@ config JOYSTICK_MAPLE
|
||||
To compile this as a module choose M here: the module will be called
|
||||
maplecontrol.
|
||||
|
||||
+config JOYSTICK_RPISENSE
|
||||
+ tristate "Raspberry Pi Sense HAT joystick"
|
||||
+ depends on GPIOLIB && INPUT
|
||||
+ select MFD_RPISENSE_CORE
|
||||
+
|
||||
+ help
|
||||
+ This is the joystick driver for the Raspberry Pi Sense HAT
|
||||
+
|
||||
endif
|
||||
--- a/drivers/input/joystick/Makefile
|
||||
+++ b/drivers/input/joystick/Makefile
|
||||
@@ -32,4 +32,5 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warri
|
||||
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
|
||||
obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o
|
||||
obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
|
||||
+obj-$(CONFIG_JOYSTICK_RPISENSE) += rpisense-js.o
|
||||
|
||||
--- /dev/null
|
||||
+++ b/drivers/input/joystick/rpisense-js.c
|
||||
@@ -0,0 +1,153 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT joystick driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <linux/mfd/rpisense/joystick.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+static unsigned char keymap[5] = {KEY_DOWN, KEY_RIGHT, KEY_UP, KEY_ENTER, KEY_LEFT,};
|
||||
+
|
||||
+static void keys_work_fn(struct work_struct *work)
|
||||
+{
|
||||
+ int i;
|
||||
+ static s32 prev_keys;
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+ s32 keys = rpisense_reg_read(rpisense, RPISENSE_KEYS);
|
||||
+ s32 changes = keys ^ prev_keys;
|
||||
+
|
||||
+ prev_keys = keys;
|
||||
+ for (i = 0; i < 5; i++) {
|
||||
+ if (changes & 1) {
|
||||
+ input_report_key(rpisense_js->keys_dev,
|
||||
+ keymap[i], keys & 1);
|
||||
+ }
|
||||
+ changes >>= 1;
|
||||
+ keys >>= 1;
|
||||
+ }
|
||||
+ input_sync(rpisense_js->keys_dev);
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t keys_irq_handler(int irq, void *pdev)
|
||||
+{
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ schedule_work(&rpisense_js->keys_work_s);
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_js_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+ int i;
|
||||
+ struct rpisense_js *rpisense_js;
|
||||
+
|
||||
+ rpisense = rpisense_get_dev();
|
||||
+ rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ INIT_WORK(&rpisense_js->keys_work_s, keys_work_fn);
|
||||
+
|
||||
+ rpisense_js->keys_dev = input_allocate_device();
|
||||
+ if (!rpisense_js->keys_dev) {
|
||||
+ dev_err(&pdev->dev, "Could not allocate input device.\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY);
|
||||
+ for (i = 0; i < ARRAY_SIZE(keymap); i++) {
|
||||
+ set_bit(keymap[i],
|
||||
+ rpisense_js->keys_dev->keybit);
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_dev->name = "Raspberry Pi Sense HAT Joystick";
|
||||
+ rpisense_js->keys_dev->phys = "rpi-sense-joy/input0";
|
||||
+ rpisense_js->keys_dev->id.bustype = BUS_I2C;
|
||||
+ rpisense_js->keys_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
|
||||
+ rpisense_js->keys_dev->keycode = keymap;
|
||||
+ rpisense_js->keys_dev->keycodesize = sizeof(unsigned char);
|
||||
+ rpisense_js->keys_dev->keycodemax = ARRAY_SIZE(keymap);
|
||||
+
|
||||
+ ret = input_register_device(rpisense_js->keys_dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Could not register input device.\n");
|
||||
+ goto err_keys_alloc;
|
||||
+ }
|
||||
+
|
||||
+ ret = gpiod_direction_input(rpisense_js->keys_desc);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "Could not set keys-int direction.\n");
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+
|
||||
+ rpisense_js->keys_irq = gpiod_to_irq(rpisense_js->keys_desc);
|
||||
+ if (rpisense_js->keys_irq < 0) {
|
||||
+ dev_err(&pdev->dev, "Could not determine keys-int IRQ.\n");
|
||||
+ ret = rpisense_js->keys_irq;
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_request_irq(&pdev->dev, rpisense_js->keys_irq,
|
||||
+ keys_irq_handler, IRQF_TRIGGER_RISING,
|
||||
+ "keys", &pdev->dev);
|
||||
+ if (ret) {
|
||||
+ dev_err(&pdev->dev, "IRQ request failed.\n");
|
||||
+ goto err_keys_reg;
|
||||
+ }
|
||||
+ return 0;
|
||||
+err_keys_reg:
|
||||
+ input_unregister_device(rpisense_js->keys_dev);
|
||||
+err_keys_alloc:
|
||||
+ input_free_device(rpisense_js->keys_dev);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_js_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rpisense_js *rpisense_js = &rpisense->joystick;
|
||||
+
|
||||
+ input_unregister_device(rpisense_js->keys_dev);
|
||||
+ input_free_device(rpisense_js->keys_dev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id rpisense_js_id[] = {
|
||||
+ { .compatible = "rpi,rpi-sense-js" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpisense_js_id);
|
||||
+#endif
|
||||
+
|
||||
+static struct platform_device_id rpisense_js_device_id[] = {
|
||||
+ { .name = "rpi-sense-js" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, rpisense_js_device_id);
|
||||
+
|
||||
+static struct platform_driver rpisense_js_driver = {
|
||||
+ .probe = rpisense_js_probe,
|
||||
+ .remove = rpisense_js_remove,
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense-js",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpisense_js_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT joystick driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/drivers/mfd/Kconfig
|
||||
+++ b/drivers/mfd/Kconfig
|
||||
@@ -10,6 +10,14 @@ config MFD_CORE
|
||||
select IRQ_DOMAIN
|
||||
default n
|
||||
|
||||
+config MFD_RPISENSE_CORE
|
||||
+ tristate "Raspberry Pi Sense HAT core functions"
|
||||
+ depends on I2C
|
||||
+ select MFD_CORE
|
||||
+ help
|
||||
+ This is the core driver for the Raspberry Pi Sense HAT. This provides
|
||||
+ the necessary functions to communicate with the hardware.
|
||||
+
|
||||
config MFD_CS5535
|
||||
tristate "AMD CS5535 and CS5536 southbridge core functions"
|
||||
select MFD_CORE
|
||||
--- a/drivers/mfd/Makefile
|
||||
+++ b/drivers/mfd/Makefile
|
||||
@@ -194,3 +194,5 @@ intel-soc-pmic-objs := intel_soc_pmic_c
|
||||
intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o
|
||||
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
|
||||
obj-$(CONFIG_MFD_MT6397) += mt6397-core.o
|
||||
+
|
||||
+obj-$(CONFIG_MFD_RPISENSE_CORE) += rpisense-core.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mfd/rpisense-core.c
|
||||
@@ -0,0 +1,157 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT core driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * 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 driver is based on wm8350 implementation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/moduleparam.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+
|
||||
+static void rpisense_client_dev_register(struct rpisense *rpisense,
|
||||
+ const char *name,
|
||||
+ struct platform_device **pdev)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ *pdev = platform_device_alloc(name, -1);
|
||||
+ if (*pdev == NULL) {
|
||||
+ dev_err(rpisense->dev, "Failed to allocate %s\n", name);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ (*pdev)->dev.parent = rpisense->dev;
|
||||
+ platform_set_drvdata(*pdev, rpisense);
|
||||
+ ret = platform_device_add(*pdev);
|
||||
+ if (ret != 0) {
|
||||
+ dev_err(rpisense->dev, "Failed to register %s: %d\n",
|
||||
+ name, ret);
|
||||
+ platform_device_put(*pdev);
|
||||
+ *pdev = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int rpisense_probe(struct i2c_client *i2c,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct rpisense_js *rpisense_js;
|
||||
+
|
||||
+ rpisense = devm_kzalloc(&i2c->dev, sizeof(struct rpisense), GFP_KERNEL);
|
||||
+ if (rpisense == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ i2c_set_clientdata(i2c, rpisense);
|
||||
+ rpisense->dev = &i2c->dev;
|
||||
+ rpisense->i2c_client = i2c;
|
||||
+
|
||||
+ ret = rpisense_reg_read(rpisense, RPISENSE_WAI);
|
||||
+ if (ret > 0) {
|
||||
+ if (ret != 's')
|
||||
+ return -EINVAL;
|
||||
+ } else {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = rpisense_reg_read(rpisense, RPISENSE_VER);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ dev_info(rpisense->dev,
|
||||
+ "Raspberry Pi Sense HAT firmware version %i\n", ret);
|
||||
+
|
||||
+ rpisense_js = &rpisense->joystick;
|
||||
+ rpisense_js->keys_desc = devm_gpiod_get(&i2c->dev,
|
||||
+ "keys-int", GPIOD_IN);
|
||||
+ if (IS_ERR(rpisense_js->keys_desc)) {
|
||||
+ dev_warn(&i2c->dev, "Failed to get keys-int descriptor.\n");
|
||||
+ rpisense_js->keys_desc = gpio_to_desc(23);
|
||||
+ if (rpisense_js->keys_desc == NULL) {
|
||||
+ dev_err(&i2c->dev, "GPIO23 fallback failed.\n");
|
||||
+ return PTR_ERR(rpisense_js->keys_desc);
|
||||
+ }
|
||||
+ }
|
||||
+ rpisense_client_dev_register(rpisense, "rpi-sense-js",
|
||||
+ &(rpisense->joystick.pdev));
|
||||
+ rpisense_client_dev_register(rpisense, "rpi-sense-fb",
|
||||
+ &(rpisense->framebuffer.pdev));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_remove(struct i2c_client *i2c)
|
||||
+{
|
||||
+ struct rpisense *rpisense = i2c_get_clientdata(i2c);
|
||||
+
|
||||
+ platform_device_unregister(rpisense->joystick.pdev);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct rpisense *rpisense_get_dev(void)
|
||||
+{
|
||||
+ return rpisense;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_get_dev);
|
||||
+
|
||||
+s32 rpisense_reg_read(struct rpisense *rpisense, int reg)
|
||||
+{
|
||||
+ int ret = i2c_smbus_read_byte_data(rpisense->i2c_client, reg);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ dev_err(rpisense->dev, "Read from reg %d failed\n", reg);
|
||||
+ /* Due to the BCM270x I2C clock stretching bug, some values
|
||||
+ * may have MSB set. Clear it to avoid incorrect values.
|
||||
+ * */
|
||||
+ return ret & 0x7F;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_reg_read);
|
||||
+
|
||||
+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count)
|
||||
+{
|
||||
+ int ret = i2c_master_send(rpisense->i2c_client, buf, count);
|
||||
+
|
||||
+ if (ret < 0)
|
||||
+ dev_err(rpisense->dev, "Block write failed\n");
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(rpisense_block_write);
|
||||
+
|
||||
+static const struct i2c_device_id rpisense_i2c_id[] = {
|
||||
+ { "rpi-sense", 0 },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, rpisense_i2c_id);
|
||||
+
|
||||
+
|
||||
+static struct i2c_driver rpisense_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+ .probe = rpisense_probe,
|
||||
+ .remove = rpisense_remove,
|
||||
+ .id_table = rpisense_i2c_id,
|
||||
+};
|
||||
+
|
||||
+module_i2c_driver(rpisense_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT core driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
--- a/drivers/video/fbdev/Kconfig
|
||||
+++ b/drivers/video/fbdev/Kconfig
|
||||
@@ -2506,3 +2506,16 @@ config FB_SM712
|
||||
This driver is also available as a module. The module will be
|
||||
called sm712fb. If you want to compile it as a module, say M
|
||||
here and read <file:Documentation/kbuild/modules.txt>.
|
||||
+
|
||||
+config FB_RPISENSE
|
||||
+ tristate "Raspberry Pi Sense HAT framebuffer"
|
||||
+ depends on FB
|
||||
+ select MFD_RPISENSE_CORE
|
||||
+ select FB_SYS_FOPS
|
||||
+ select FB_SYS_FILLRECT
|
||||
+ select FB_SYS_COPYAREA
|
||||
+ select FB_SYS_IMAGEBLIT
|
||||
+ select FB_DEFERRED_IO
|
||||
+
|
||||
+ help
|
||||
+ This is the framebuffer driver for the Raspberry Pi Sense HAT
|
||||
--- a/drivers/video/fbdev/Makefile
|
||||
+++ b/drivers/video/fbdev/Makefile
|
||||
@@ -150,6 +150,7 @@ obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
|
||||
obj-$(CONFIG_FB_MXS) += mxsfb.o
|
||||
obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o
|
||||
obj-$(CONFIG_FB_SIMPLE) += simplefb.o
|
||||
+obj-$(CONFIG_FB_RPISENSE) += rpisense-fb.o
|
||||
|
||||
# the test framebuffer is last
|
||||
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/fbdev/rpisense-fb.c
|
||||
@@ -0,0 +1,293 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT framebuffer driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/string.h>
|
||||
+#include <linux/mm.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/uaccess.h>
|
||||
+#include <linux/delay.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/init.h>
|
||||
+
|
||||
+#include <linux/mfd/rpisense/framebuffer.h>
|
||||
+#include <linux/mfd/rpisense/core.h>
|
||||
+
|
||||
+static bool lowlight;
|
||||
+module_param(lowlight, bool, 0);
|
||||
+MODULE_PARM_DESC(lowlight, "Reduce LED matrix brightness to one third");
|
||||
+
|
||||
+static struct rpisense *rpisense;
|
||||
+
|
||||
+struct rpisense_fb_param {
|
||||
+ char __iomem *vmem;
|
||||
+ u8 *vmem_work;
|
||||
+ u32 vmemsize;
|
||||
+ u8 *gamma;
|
||||
+};
|
||||
+
|
||||
+static u8 gamma_default[32] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
+ 0x02, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0E, 0x0F, 0x11,
|
||||
+ 0x12, 0x14, 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F,};
|
||||
+
|
||||
+static u8 gamma_low[32] = {0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02,
|
||||
+ 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06,
|
||||
+ 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x0A, 0x0A,};
|
||||
+
|
||||
+static u8 gamma_user[32];
|
||||
+
|
||||
+static struct rpisense_fb_param rpisense_fb_param = {
|
||||
+ .vmem = NULL,
|
||||
+ .vmemsize = 128,
|
||||
+ .gamma = gamma_default,
|
||||
+};
|
||||
+
|
||||
+static struct fb_deferred_io rpisense_fb_defio;
|
||||
+
|
||||
+static struct fb_fix_screeninfo rpisense_fb_fix = {
|
||||
+ .id = "RPi-Sense FB",
|
||||
+ .type = FB_TYPE_PACKED_PIXELS,
|
||||
+ .visual = FB_VISUAL_TRUECOLOR,
|
||||
+ .xpanstep = 0,
|
||||
+ .ypanstep = 0,
|
||||
+ .ywrapstep = 0,
|
||||
+ .accel = FB_ACCEL_NONE,
|
||||
+ .line_length = 16,
|
||||
+};
|
||||
+
|
||||
+static struct fb_var_screeninfo rpisense_fb_var = {
|
||||
+ .xres = 8,
|
||||
+ .yres = 8,
|
||||
+ .xres_virtual = 8,
|
||||
+ .yres_virtual = 8,
|
||||
+ .bits_per_pixel = 16,
|
||||
+ .red = {11, 5, 0},
|
||||
+ .green = {5, 6, 0},
|
||||
+ .blue = {0, 5, 0},
|
||||
+};
|
||||
+
|
||||
+static ssize_t rpisense_fb_write(struct fb_info *info,
|
||||
+ const char __user *buf, size_t count,
|
||||
+ loff_t *ppos)
|
||||
+{
|
||||
+ ssize_t res = fb_sys_write(info, buf, count, ppos);
|
||||
+
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_fillrect(struct fb_info *info,
|
||||
+ const struct fb_fillrect *rect)
|
||||
+{
|
||||
+ sys_fillrect(info, rect);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_copyarea(struct fb_info *info,
|
||||
+ const struct fb_copyarea *area)
|
||||
+{
|
||||
+ sys_copyarea(info, area);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_imageblit(struct fb_info *info,
|
||||
+ const struct fb_image *image)
|
||||
+{
|
||||
+ sys_imageblit(info, image);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+}
|
||||
+
|
||||
+static void rpisense_fb_deferred_io(struct fb_info *info,
|
||||
+ struct list_head *pagelist)
|
||||
+{
|
||||
+ int i;
|
||||
+ int j;
|
||||
+ u8 *vmem_work = rpisense_fb_param.vmem_work;
|
||||
+ u16 *mem = (u16 *)rpisense_fb_param.vmem;
|
||||
+ u8 *gamma = rpisense_fb_param.gamma;
|
||||
+
|
||||
+ vmem_work[0] = 0;
|
||||
+ for (j = 0; j < 8; j++) {
|
||||
+ for (i = 0; i < 8; i++) {
|
||||
+ vmem_work[(j * 24) + i + 1] =
|
||||
+ gamma[(mem[(j * 8) + i] >> 11) & 0x1F];
|
||||
+ vmem_work[(j * 24) + (i + 8) + 1] =
|
||||
+ gamma[(mem[(j * 8) + i] >> 6) & 0x1F];
|
||||
+ vmem_work[(j * 24) + (i + 16) + 1] =
|
||||
+ gamma[(mem[(j * 8) + i]) & 0x1F];
|
||||
+ }
|
||||
+ }
|
||||
+ rpisense_block_write(rpisense, vmem_work, 193);
|
||||
+}
|
||||
+
|
||||
+static struct fb_deferred_io rpisense_fb_defio = {
|
||||
+ .delay = HZ/100,
|
||||
+ .deferred_io = rpisense_fb_deferred_io,
|
||||
+};
|
||||
+
|
||||
+static int rpisense_fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
+ unsigned long arg)
|
||||
+{
|
||||
+ switch (cmd) {
|
||||
+ case SENSEFB_FBIOGET_GAMMA:
|
||||
+ if (copy_to_user((void __user *) arg, rpisense_fb_param.gamma,
|
||||
+ sizeof(u8[32])))
|
||||
+ return -EFAULT;
|
||||
+ return 0;
|
||||
+ case SENSEFB_FBIOSET_GAMMA:
|
||||
+ if (copy_from_user(gamma_user, (void __user *)arg,
|
||||
+ sizeof(u8[32])))
|
||||
+ return -EFAULT;
|
||||
+ rpisense_fb_param.gamma = gamma_user;
|
||||
+ schedule_delayed_work(&info->deferred_work,
|
||||
+ rpisense_fb_defio.delay);
|
||||
+ return 0;
|
||||
+ case SENSEFB_FBIORESET_GAMMA:
|
||||
+ switch (arg) {
|
||||
+ case 0:
|
||||
+ rpisense_fb_param.gamma = gamma_default;
|
||||
+ break;
|
||||
+ case 1:
|
||||
+ rpisense_fb_param.gamma = gamma_low;
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ rpisense_fb_param.gamma = gamma_user;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ schedule_delayed_work(&info->deferred_work,
|
||||
+ rpisense_fb_defio.delay);
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct fb_ops rpisense_fb_ops = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .fb_read = fb_sys_read,
|
||||
+ .fb_write = rpisense_fb_write,
|
||||
+ .fb_fillrect = rpisense_fb_fillrect,
|
||||
+ .fb_copyarea = rpisense_fb_copyarea,
|
||||
+ .fb_imageblit = rpisense_fb_imageblit,
|
||||
+ .fb_ioctl = rpisense_fb_ioctl,
|
||||
+};
|
||||
+
|
||||
+static int rpisense_fb_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct fb_info *info;
|
||||
+ int ret = -ENOMEM;
|
||||
+ struct rpisense_fb *rpisense_fb;
|
||||
+
|
||||
+ rpisense = rpisense_get_dev();
|
||||
+ rpisense_fb = &rpisense->framebuffer;
|
||||
+
|
||||
+ rpisense_fb_param.vmem = vzalloc(rpisense_fb_param.vmemsize);
|
||||
+ if (!rpisense_fb_param.vmem)
|
||||
+ return ret;
|
||||
+
|
||||
+ rpisense_fb_param.vmem_work = devm_kmalloc(&pdev->dev, 193, GFP_KERNEL);
|
||||
+ if (!rpisense_fb_param.vmem_work)
|
||||
+ goto err_malloc;
|
||||
+
|
||||
+ info = framebuffer_alloc(0, &pdev->dev);
|
||||
+ if (!info) {
|
||||
+ dev_err(&pdev->dev, "Could not allocate framebuffer.\n");
|
||||
+ goto err_malloc;
|
||||
+ }
|
||||
+ rpisense_fb->info = info;
|
||||
+
|
||||
+ rpisense_fb_fix.smem_start = (unsigned long)rpisense_fb_param.vmem;
|
||||
+ rpisense_fb_fix.smem_len = rpisense_fb_param.vmemsize;
|
||||
+
|
||||
+ info->fbops = &rpisense_fb_ops;
|
||||
+ info->fix = rpisense_fb_fix;
|
||||
+ info->var = rpisense_fb_var;
|
||||
+ info->fbdefio = &rpisense_fb_defio;
|
||||
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
|
||||
+ info->screen_base = rpisense_fb_param.vmem;
|
||||
+ info->screen_size = rpisense_fb_param.vmemsize;
|
||||
+
|
||||
+ if (lowlight)
|
||||
+ rpisense_fb_param.gamma = gamma_low;
|
||||
+
|
||||
+ fb_deferred_io_init(info);
|
||||
+
|
||||
+ ret = register_framebuffer(info);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(&pdev->dev, "Could not register framebuffer.\n");
|
||||
+ goto err_fballoc;
|
||||
+ }
|
||||
+
|
||||
+ fb_info(info, "%s frame buffer device\n", info->fix.id);
|
||||
+ schedule_delayed_work(&info->deferred_work, rpisense_fb_defio.delay);
|
||||
+ return 0;
|
||||
+err_fballoc:
|
||||
+ framebuffer_release(info);
|
||||
+err_malloc:
|
||||
+ vfree(rpisense_fb_param.vmem);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int rpisense_fb_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct rpisense_fb *rpisense_fb = &rpisense->framebuffer;
|
||||
+ struct fb_info *info = rpisense_fb->info;
|
||||
+
|
||||
+ if (info) {
|
||||
+ unregister_framebuffer(info);
|
||||
+ fb_deferred_io_cleanup(info);
|
||||
+ framebuffer_release(info);
|
||||
+ vfree(rpisense_fb_param.vmem);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#ifdef CONFIG_OF
|
||||
+static const struct of_device_id rpisense_fb_id[] = {
|
||||
+ { .compatible = "rpi,rpi-sense-fb" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpisense_fb_id);
|
||||
+#endif
|
||||
+
|
||||
+static struct platform_device_id rpisense_fb_device_id[] = {
|
||||
+ { .name = "rpi-sense-fb" },
|
||||
+ { },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(platform, rpisense_fb_device_id);
|
||||
+
|
||||
+static struct platform_driver rpisense_fb_driver = {
|
||||
+ .probe = rpisense_fb_probe,
|
||||
+ .remove = rpisense_fb_remove,
|
||||
+ .driver = {
|
||||
+ .name = "rpi-sense-fb",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpisense_fb_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("Raspberry Pi Sense HAT framebuffer driver");
|
||||
+MODULE_AUTHOR("Serge Schneider <serge@raspberrypi.org>");
|
||||
+MODULE_LICENSE("GPL");
|
||||
+
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/core.h
|
||||
@@ -0,0 +1,47 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT core driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_MFD_RPISENSE_CORE_H_
|
||||
+#define __LINUX_MFD_RPISENSE_CORE_H_
|
||||
+
|
||||
+#include <linux/mfd/rpisense/joystick.h>
|
||||
+#include <linux/mfd/rpisense/framebuffer.h>
|
||||
+
|
||||
+/*
|
||||
+ * Register values.
|
||||
+ */
|
||||
+#define RPISENSE_FB 0x00
|
||||
+#define RPISENSE_WAI 0xF0
|
||||
+#define RPISENSE_VER 0xF1
|
||||
+#define RPISENSE_KEYS 0xF2
|
||||
+#define RPISENSE_EE_WP 0xF3
|
||||
+
|
||||
+#define RPISENSE_ID 's'
|
||||
+
|
||||
+struct rpisense {
|
||||
+ struct device *dev;
|
||||
+ struct i2c_client *i2c_client;
|
||||
+
|
||||
+ /* Client devices */
|
||||
+ struct rpisense_js joystick;
|
||||
+ struct rpisense_fb framebuffer;
|
||||
+};
|
||||
+
|
||||
+struct rpisense *rpisense_get_dev(void);
|
||||
+s32 rpisense_reg_read(struct rpisense *rpisense, int reg);
|
||||
+int rpisense_reg_write(struct rpisense *rpisense, int reg, u16 val);
|
||||
+int rpisense_block_write(struct rpisense *rpisense, const char *buf, int count);
|
||||
+
|
||||
+#endif
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/framebuffer.h
|
||||
@@ -0,0 +1,32 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT framebuffer driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_RPISENSE_FB_H_
|
||||
+#define __LINUX_RPISENSE_FB_H_
|
||||
+
|
||||
+#define SENSEFB_FBIO_IOC_MAGIC 0xF1
|
||||
+
|
||||
+#define SENSEFB_FBIOGET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 0)
|
||||
+#define SENSEFB_FBIOSET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 1)
|
||||
+#define SENSEFB_FBIORESET_GAMMA _IO(SENSEFB_FBIO_IOC_MAGIC, 2)
|
||||
+
|
||||
+struct rpisense;
|
||||
+
|
||||
+struct rpisense_fb {
|
||||
+ struct platform_device *pdev;
|
||||
+ struct fb_info *info;
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
--- /dev/null
|
||||
+++ b/include/linux/mfd/rpisense/joystick.h
|
||||
@@ -0,0 +1,35 @@
|
||||
+/*
|
||||
+ * Raspberry Pi Sense HAT joystick driver
|
||||
+ * http://raspberrypi.org
|
||||
+ *
|
||||
+ * Copyright (C) 2015 Raspberry Pi
|
||||
+ *
|
||||
+ * Author: Serge Schneider
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License as published by the
|
||||
+ * Free Software Foundation; either version 2 of the License, or (at your
|
||||
+ * option) any later version.
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+#ifndef __LINUX_RPISENSE_JOYSTICK_H_
|
||||
+#define __LINUX_RPISENSE_JOYSTICK_H_
|
||||
+
|
||||
+#include <linux/input.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+
|
||||
+struct rpisense;
|
||||
+
|
||||
+struct rpisense_js {
|
||||
+ struct platform_device *pdev;
|
||||
+ struct input_dev *keys_dev;
|
||||
+ struct gpio_desc *keys_desc;
|
||||
+ struct work_struct keys_work_s;
|
||||
+ int keys_irq;
|
||||
+};
|
||||
+
|
||||
+
|
||||
+#endif
|
|
@ -0,0 +1,243 @@
|
|||
From c0121c68fb1b9242907546191008deb49123729a Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <jan@grulich.eu>
|
||||
Date: Mon, 24 Aug 2015 16:03:47 +0100
|
||||
Subject: [PATCH 085/127] RaspiDAC3 support
|
||||
|
||||
Signed-off-by: Jan Grulich <jan@grulich.eu>
|
||||
|
||||
config: fix RaspiDAC Rev.3x dependencies
|
||||
|
||||
Change depends to SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
like the other I2S soundcard drivers.
|
||||
|
||||
Signed-off-by: Matthias Reichl <hias@horus.com>
|
||||
---
|
||||
sound/soc/bcm/Kconfig | 8 ++
|
||||
sound/soc/bcm/Makefile | 2 +
|
||||
sound/soc/bcm/raspidac3.c | 191 ++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 201 insertions(+)
|
||||
create mode 100644 sound/soc/bcm/raspidac3.c
|
||||
|
||||
--- a/sound/soc/bcm/Kconfig
|
||||
+++ b/sound/soc/bcm/Kconfig
|
||||
@@ -56,3 +56,11 @@ config SND_BCM2708_SOC_IQAUDIO_DAC
|
||||
select SND_SOC_PCM512x_I2C
|
||||
help
|
||||
Say Y or M if you want to add support for IQaudIO-DAC.
|
||||
+
|
||||
+config SND_BCM2708_SOC_RASPIDAC3
|
||||
+ tristate "Support for RaspiDAC Rev.3x"
|
||||
+ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S
|
||||
+ select SND_SOC_PCM512x_I2C
|
||||
+ select SND_SOC_TPA6130A2
|
||||
+ help
|
||||
+ Say Y or M if you want to add support for RaspiDAC Rev.3x.
|
||||
--- a/sound/soc/bcm/Makefile
|
||||
+++ b/sound/soc/bcm/Makefile
|
||||
@@ -11,6 +11,7 @@ snd-soc-hifiberry-amp-objs := hifiberry_
|
||||
snd-soc-rpi-dac-objs := rpi-dac.o
|
||||
snd-soc-rpi-proto-objs := rpi-proto.o
|
||||
snd-soc-iqaudio-dac-objs := iqaudio-dac.o
|
||||
+snd-soc-raspidac3-objs := raspidac3.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
|
||||
@@ -19,3 +20,4 @@ obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_A
|
||||
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
|
||||
+obj-$(CONFIG_SND_BCM2708_SOC_RASPIDAC3) += snd-soc-raspidac3.o
|
||||
--- /dev/null
|
||||
+++ b/sound/soc/bcm/raspidac3.c
|
||||
@@ -0,0 +1,191 @@
|
||||
+/*
|
||||
+ * ASoC Driver for RaspiDAC v3
|
||||
+ *
|
||||
+ * Author: Jan Grulich <jan@grulich.eu>
|
||||
+ * Copyright 2015
|
||||
+ * based on code by Daniel Matuschek <daniel@hifiberry.com>
|
||||
+ * 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 <sound/soc-dapm.h>
|
||||
+
|
||||
+#include "../codecs/pcm512x.h"
|
||||
+#include "../codecs/tpa6130a2.h"
|
||||
+
|
||||
+/* sound card init */
|
||||
+static int snd_rpi_raspidac3_init(struct snd_soc_pcm_runtime *rtd)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct snd_soc_card *card = rtd->card;
|
||||
+ 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,0x00);
|
||||
+
|
||||
+ ret = snd_soc_limit_volume(card, "Digital Playback Volume", 207);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set volume limit: %d\n", ret);
|
||||
+ else {
|
||||
+ struct snd_kcontrol *kctl;
|
||||
+
|
||||
+ ret = tpa6130a2_add_controls(codec);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to add TPA6130A2 controls: %d\n",
|
||||
+ ret);
|
||||
+ ret = snd_soc_limit_volume(card,
|
||||
+ "TPA6130A2 Headphone Playback Volume",
|
||||
+ 54);
|
||||
+ if (ret < 0)
|
||||
+ dev_warn(card->dev, "Failed to set TPA6130A2 volume limit: %d\n",
|
||||
+ ret);
|
||||
+ kctl = snd_soc_card_get_kcontrol(card,
|
||||
+ "TPA6130A2 Headphone Playback Volume");
|
||||
+ if (kctl) {
|
||||
+ strcpy(kctl->id.name, "Headphones Playback Volume");
|
||||
+ /* disable the volume dB scale so alsamixer works */
|
||||
+ kctl->vd[0].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
|
||||
+ }
|
||||
+
|
||||
+ kctl = snd_soc_card_get_kcontrol(card,
|
||||
+ "TPA6130A2 Headphone Playback Switch");
|
||||
+ if (kctl)
|
||||
+ strcpy(kctl->id.name, "Headphones Playback Switch");
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* set hw parameters */
|
||||
+static int snd_rpi_raspidac3_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);
|
||||
+}
|
||||
+
|
||||
+/* startup */
|
||||
+static int snd_rpi_raspidac3_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);
|
||||
+ tpa6130a2_stereo_enable(codec, 1);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* shutdown */
|
||||
+static void snd_rpi_raspidac3_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);
|
||||
+ tpa6130a2_stereo_enable(codec, 0);
|
||||
+}
|
||||
+
|
||||
+/* machine stream operations */
|
||||
+static struct snd_soc_ops snd_rpi_raspidac3_ops = {
|
||||
+ .hw_params = snd_rpi_raspidac3_hw_params,
|
||||
+ .startup = snd_rpi_raspidac3_startup,
|
||||
+ .shutdown = snd_rpi_raspidac3_shutdown,
|
||||
+};
|
||||
+
|
||||
+/* interface setup */
|
||||
+static struct snd_soc_dai_link snd_rpi_raspidac3_dai[] = {
|
||||
+{
|
||||
+ .name = "RaspiDAC Rev.3x",
|
||||
+ .stream_name = "RaspiDAC 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_raspidac3_ops,
|
||||
+ .init = snd_rpi_raspidac3_init,
|
||||
+},
|
||||
+};
|
||||
+
|
||||
+/* audio machine driver */
|
||||
+static struct snd_soc_card snd_rpi_raspidac3 = {
|
||||
+ .name = "RaspiDAC Rev.3x HiFi Audio Card",
|
||||
+ .dai_link = snd_rpi_raspidac3_dai,
|
||||
+ .num_links = ARRAY_SIZE(snd_rpi_raspidac3_dai),
|
||||
+};
|
||||
+
|
||||
+/* sound card test */
|
||||
+static int snd_rpi_raspidac3_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ snd_rpi_raspidac3.dev = &pdev->dev;
|
||||
+
|
||||
+ if (pdev->dev.of_node) {
|
||||
+ struct device_node *i2s_node;
|
||||
+ struct snd_soc_dai_link *dai = &snd_rpi_raspidac3_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_raspidac3);
|
||||
+ if (ret)
|
||||
+ dev_err(&pdev->dev,
|
||||
+ "snd_soc_register_card() failed: %d\n", ret);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/* sound card disconnect */
|
||||
+static int snd_rpi_raspidac3_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ return snd_soc_unregister_card(&snd_rpi_raspidac3);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id raspidac3_of_match[] = {
|
||||
+ { .compatible = "jg,raspidacv3", },
|
||||
+ {},
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, raspidac3_of_match);
|
||||
+
|
||||
+/* sound card platform driver */
|
||||
+static struct platform_driver snd_rpi_raspidac3_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "snd-rpi-raspidac3",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = raspidac3_of_match,
|
||||
+ },
|
||||
+ .probe = snd_rpi_raspidac3_probe,
|
||||
+ .remove = snd_rpi_raspidac3_remove,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(snd_rpi_raspidac3_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Jan Grulich <jan@grulich.eu>");
|
||||
+MODULE_DESCRIPTION("ASoC Driver for RaspiDAC Rev.3x");
|
||||
+MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,91 @@
|
|||
From a7c37b3c36ccec8a089d576c55ad9ba1721cb0ef Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <jan@grulich.eu>
|
||||
Date: Mon, 24 Aug 2015 16:02:34 +0100
|
||||
Subject: [PATCH 086/127] tpa6130a2: Add headphone switch control
|
||||
|
||||
Signed-off-by: Jan Grulich <jan@grulich.eu>
|
||||
---
|
||||
sound/soc/codecs/tpa6130a2.c | 29 ++++++++++++++++++++++++++---
|
||||
1 file changed, 26 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/sound/soc/codecs/tpa6130a2.c
|
||||
+++ b/sound/soc/codecs/tpa6130a2.c
|
||||
@@ -4,6 +4,7 @@
|
||||
* Copyright (C) Nokia Corporation
|
||||
*
|
||||
* Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
+ * Modified: Jan Grulich <jan@grulich.eu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
@@ -52,6 +53,8 @@ struct tpa6130a2_data {
|
||||
enum tpa_model id;
|
||||
};
|
||||
|
||||
+static void tpa6130a2_channel_enable(u8 channel, int enable);
|
||||
+
|
||||
static int tpa6130a2_i2c_read(int reg)
|
||||
{
|
||||
struct tpa6130a2_data *data;
|
||||
@@ -189,7 +192,7 @@ exit:
|
||||
}
|
||||
|
||||
static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
|
||||
- struct snd_ctl_elem_value *ucontrol)
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
@@ -218,7 +221,7 @@ static int tpa6130a2_get_volsw(struct sn
|
||||
}
|
||||
|
||||
static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
|
||||
- struct snd_ctl_elem_value *ucontrol)
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
@@ -255,8 +258,22 @@ static int tpa6130a2_put_volsw(struct sn
|
||||
return 1;
|
||||
}
|
||||
|
||||
+static int tpa6130a2_put_hp_sw(struct snd_kcontrol *kcontrol,
|
||||
+ struct snd_ctl_elem_value *ucontrol)
|
||||
+{
|
||||
+ int enable = ucontrol->value.integer.value[0];
|
||||
+ unsigned int state;
|
||||
+
|
||||
+ state = (tpa6130a2_read(TPA6130A2_REG_VOL_MUTE) & 0x80) == 0;
|
||||
+ if (state == enable)
|
||||
+ return 0; /* No change */
|
||||
+
|
||||
+ tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, enable);
|
||||
+ return 1; /* Changed */
|
||||
+}
|
||||
+
|
||||
/*
|
||||
- * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
|
||||
+ * TPA6130 volume. From -59.5 to +4.0 dB with increasing step size when going
|
||||
* down in gain.
|
||||
*/
|
||||
static const DECLARE_TLV_DB_RANGE(tpa6130_tlv,
|
||||
@@ -277,6 +294,9 @@ static const struct snd_kcontrol_new tpa
|
||||
TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
|
||||
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
|
||||
tpa6130_tlv),
|
||||
+ SOC_SINGLE_EXT("TPA6130A2 Headphone Playback Switch",
|
||||
+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
|
||||
+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
|
||||
};
|
||||
|
||||
static const DECLARE_TLV_DB_RANGE(tpa6140_tlv,
|
||||
@@ -290,6 +310,9 @@ static const struct snd_kcontrol_new tpa
|
||||
TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
|
||||
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
|
||||
tpa6140_tlv),
|
||||
+ SOC_SINGLE_EXT("TPA6140A2 Headphone Playback Switch",
|
||||
+ TPA6130A2_REG_VOL_MUTE, 7, 1, 1,
|
||||
+ tpa6130a2_get_volsw, tpa6130a2_put_hp_sw),
|
||||
};
|
||||
|
||||
/*
|
|
@ -0,0 +1,28 @@
|
|||
From d4df36c7243c7fcf016278309a7fcf1e07bf8b7f Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Mon, 28 Sep 2015 23:38:59 +0100
|
||||
Subject: [PATCH 087/127] irq-bcm2835: Fix building with 2708
|
||||
|
||||
---
|
||||
drivers/irqchip/irq-bcm2835.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/irqchip/irq-bcm2835.c
|
||||
+++ b/drivers/irqchip/irq-bcm2835.c
|
||||
@@ -82,6 +82,7 @@
|
||||
#define NR_BANKS 3
|
||||
#define IRQS_PER_BANK 32
|
||||
#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0)
|
||||
+#undef FIQ_START
|
||||
#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0))
|
||||
|
||||
static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 };
|
||||
@@ -256,7 +257,7 @@ static int __init armctrl_of_init(struct
|
||||
MAKE_HWIRQ(b, i) + NUMBER_IRQS);
|
||||
BUG_ON(irq <= 0);
|
||||
irq_set_chip(irq, &armctrl_chip);
|
||||
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
|
||||
+ irq_set_probe(irq);
|
||||
}
|
||||
}
|
||||
init_FIQ(FIQ_START);
|
|
@ -0,0 +1,250 @@
|
|||
From 356081aede8e5bd1b9503c4510e1d4fc0d85b026 Mon Sep 17 00:00:00 2001
|
||||
From: P33M <P33M@github.com>
|
||||
Date: Wed, 21 Oct 2015 14:55:21 +0100
|
||||
Subject: [PATCH 088/127] rpi_display: add backlight driver and overlay
|
||||
|
||||
Add a mailbox-driven backlight controller for the Raspberry Pi DSI
|
||||
touchscreen display. Requires updated GPU firmware to recognise the
|
||||
mailbox request.
|
||||
|
||||
Signed-off-by: Gordon Hollingworth <gordon@raspberrypi.org>
|
||||
---
|
||||
arch/arm/boot/dts/overlays/Makefile | 1 +
|
||||
arch/arm/boot/dts/overlays/README | 6 ++
|
||||
.../boot/dts/overlays/rpi-backlight-overlay.dts | 21 ++++
|
||||
arch/arm/configs/bcm2709_defconfig | 1 +
|
||||
arch/arm/configs/bcmrpi_defconfig | 1 +
|
||||
drivers/video/backlight/Kconfig | 6 ++
|
||||
drivers/video/backlight/Makefile | 1 +
|
||||
drivers/video/backlight/rpi_backlight.c | 119 +++++++++++++++++++++
|
||||
include/soc/bcm2835/raspberrypi-firmware.h | 1 +
|
||||
9 files changed, 157 insertions(+)
|
||||
create mode 100644 arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
|
||||
create mode 100644 drivers/video/backlight/rpi_backlight.c
|
||||
|
||||
--- a/arch/arm/boot/dts/overlays/Makefile
|
||||
+++ b/arch/arm/boot/dts/overlays/Makefile
|
||||
@@ -38,6 +38,7 @@ dtb-$(RPI_DT_OVERLAYS) += pps-gpio-overl
|
||||
dtb-$(RPI_DT_OVERLAYS) += pwm-overlay.dtb
|
||||
dtb-$(RPI_DT_OVERLAYS) += pwm-2chan-overlay.dtb
|
||||
dtb-$(RPI_DT_OVERLAYS) += raspidac3-overlay.dtb
|
||||
+dtb-$(RPI_DT_OVERLAYS) += rpi-backlight-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
|
||||
--- a/arch/arm/boot/dts/overlays/README
|
||||
+++ b/arch/arm/boot/dts/overlays/README
|
||||
@@ -462,6 +462,12 @@ Load: dtoverlay=raspidac3
|
||||
Params: <None>
|
||||
|
||||
|
||||
+Name: rpi-backlight
|
||||
+Info: Raspberry Pi official display backlight driver
|
||||
+Load: dtoverlay=rpi-backlight
|
||||
+Params: <None>
|
||||
+
|
||||
+
|
||||
Name: rpi-dac
|
||||
Info: Configures the RPi DAC audio card
|
||||
Load: dtoverlay=rpi-dac
|
||||
--- /dev/null
|
||||
+++ b/arch/arm/boot/dts/overlays/rpi-backlight-overlay.dts
|
||||
@@ -0,0 +1,21 @@
|
||||
+/*
|
||||
+ * Devicetree overlay for mailbox-driven Raspberry Pi DSI Display
|
||||
+ * backlight controller
|
||||
+ */
|
||||
+/dts-v1/;
|
||||
+/plugin/;
|
||||
+
|
||||
+/ {
|
||||
+ compatible = "brcm,bcm2708";
|
||||
+
|
||||
+ fragment@0 {
|
||||
+ target-path = "/";
|
||||
+ __overlay__ {
|
||||
+ rpi_backlight: rpi_backlight {
|
||||
+ compatible = "raspberrypi,rpi-backlight";
|
||||
+ firmware = <&firmware>;
|
||||
+ status = "okay";
|
||||
+ };
|
||||
+ };
|
||||
+ };
|
||||
+};
|
||||
--- a/arch/arm/configs/bcm2709_defconfig
|
||||
+++ b/arch/arm/configs/bcm2709_defconfig
|
||||
@@ -808,6 +808,7 @@ CONFIG_FB_UDL=m
|
||||
CONFIG_FB_SSD1307=m
|
||||
CONFIG_FB_RPISENSE=m
|
||||
# CONFIG_BACKLIGHT_GENERIC is not set
|
||||
+CONFIG_BACKLIGHT_RPI=m
|
||||
CONFIG_BACKLIGHT_GPIO=m
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
CONFIG_LOGO=y
|
||||
--- a/arch/arm/configs/bcmrpi_defconfig
|
||||
+++ b/arch/arm/configs/bcmrpi_defconfig
|
||||
@@ -801,6 +801,7 @@ CONFIG_FB_UDL=m
|
||||
CONFIG_FB_SSD1307=m
|
||||
CONFIG_FB_RPISENSE=m
|
||||
# CONFIG_BACKLIGHT_GENERIC is not set
|
||||
+CONFIG_BACKLIGHT_RPI=m
|
||||
CONFIG_BACKLIGHT_GPIO=m
|
||||
CONFIG_FRAMEBUFFER_CONSOLE=y
|
||||
CONFIG_LOGO=y
|
||||
--- a/drivers/video/backlight/Kconfig
|
||||
+++ b/drivers/video/backlight/Kconfig
|
||||
@@ -265,6 +265,12 @@ config BACKLIGHT_PWM
|
||||
If you have a LCD backlight adjustable by PWM, say Y to enable
|
||||
this driver.
|
||||
|
||||
+config BACKLIGHT_RPI
|
||||
+ tristate "Raspberry Pi display firmware driven backlight"
|
||||
+ help
|
||||
+ If you have the Raspberry Pi DSI touchscreen display, say Y to
|
||||
+ enable the mailbox-controlled backlight driver.
|
||||
+
|
||||
config BACKLIGHT_DA903X
|
||||
tristate "Backlight Driver for DA9030/DA9034 using WLED"
|
||||
depends on PMIC_DA903X
|
||||
--- a/drivers/video/backlight/Makefile
|
||||
+++ b/drivers/video/backlight/Makefile
|
||||
@@ -50,6 +50,7 @@ obj-$(CONFIG_BACKLIGHT_PANDORA) += pand
|
||||
obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o
|
||||
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
|
||||
+obj-$(CONFIG_BACKLIGHT_RPI) += rpi_backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o
|
||||
obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
|
||||
obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/video/backlight/rpi_backlight.c
|
||||
@@ -0,0 +1,119 @@
|
||||
+/*
|
||||
+ * rpi_bl.c - Backlight controller through VPU
|
||||
+ *
|
||||
+ * 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/backlight.h>
|
||||
+#include <linux/err.h>
|
||||
+#include <linux/fb.h>
|
||||
+#include <linux/gpio.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_gpio.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <soc/bcm2835/raspberrypi-firmware.h>
|
||||
+
|
||||
+struct rpi_backlight {
|
||||
+ struct device *dev;
|
||||
+ struct device *fbdev;
|
||||
+ struct rpi_firmware *fw;
|
||||
+};
|
||||
+
|
||||
+static int rpi_backlight_update_status(struct backlight_device *bl)
|
||||
+{
|
||||
+ struct rpi_backlight *gbl = bl_get_data(bl);
|
||||
+ int brightness = bl->props.brightness;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (bl->props.power != FB_BLANK_UNBLANK ||
|
||||
+ bl->props.fb_blank != FB_BLANK_UNBLANK ||
|
||||
+ bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
|
||||
+ brightness = 0;
|
||||
+
|
||||
+ ret = rpi_firmware_property(gbl->fw,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT,
|
||||
+ &brightness, sizeof(brightness));
|
||||
+ if (ret) {
|
||||
+ dev_err(gbl->dev, "Failed to set brightness\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (brightness < 0) {
|
||||
+ dev_err(gbl->dev, "Backlight change failed\n");
|
||||
+ return -EAGAIN;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct backlight_ops rpi_backlight_ops = {
|
||||
+ .options = BL_CORE_SUSPENDRESUME,
|
||||
+ .update_status = rpi_backlight_update_status,
|
||||
+};
|
||||
+
|
||||
+static int rpi_backlight_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct backlight_properties props;
|
||||
+ struct backlight_device *bl;
|
||||
+ struct rpi_backlight *gbl;
|
||||
+ struct device_node *fw_node;
|
||||
+
|
||||
+ gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL);
|
||||
+ if (gbl == NULL)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ gbl->dev = &pdev->dev;
|
||||
+
|
||||
+ fw_node = of_parse_phandle(pdev->dev.of_node, "firmware", 0);
|
||||
+ if (!fw_node) {
|
||||
+ dev_err(&pdev->dev, "Missing firmware node\n");
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ gbl->fw = rpi_firmware_get(fw_node);
|
||||
+ if (!gbl->fw)
|
||||
+ return -EPROBE_DEFER;
|
||||
+
|
||||
+ memset(&props, 0, sizeof(props));
|
||||
+ props.type = BACKLIGHT_RAW;
|
||||
+ props.max_brightness = 255;
|
||||
+ bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev),
|
||||
+ &pdev->dev, gbl, &rpi_backlight_ops,
|
||||
+ &props);
|
||||
+ if (IS_ERR(bl)) {
|
||||
+ dev_err(&pdev->dev, "failed to register backlight\n");
|
||||
+ return PTR_ERR(bl);
|
||||
+ }
|
||||
+
|
||||
+ bl->props.brightness = 255;
|
||||
+ backlight_update_status(bl);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, bl);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id rpi_backlight_of_match[] = {
|
||||
+ { .compatible = "raspberrypi,rpi-backlight" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, rpi_backlight_of_match);
|
||||
+
|
||||
+static struct platform_driver rpi_backlight_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "rpi-backlight",
|
||||
+ .of_match_table = of_match_ptr(rpi_backlight_of_match),
|
||||
+ },
|
||||
+ .probe = rpi_backlight_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(rpi_backlight_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Gordon Hollingworth <gordon@raspberrypi.org>");
|
||||
+MODULE_DESCRIPTION("Raspberry Pi mailbox based Backlight Driver");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
|
||||
@@ -112,6 +112,7 @@ enum rpi_firmware_property_tag {
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
|
||||
RPI_FIRMWARE_FRAMEBUFFER_SET_VSYNC = 0x0004800e,
|
||||
+ RPI_FIRMWARE_FRAMEBUFFER_SET_BACKLIGHT = 0x0004800f,
|
||||
|
||||
RPI_FIRMWARE_VCHIQ_INIT = 0x00048010,
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
From 83a58ceb78952a15b2a14716e2099cb548cd9081 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Mon, 16 Nov 2015 14:05:35 +0000
|
||||
Subject: [PATCH 089/127] bcm2835-dma: Fix up convert to DMA pool
|
||||
|
||||
---
|
||||
drivers/dma/bcm2835-dma.c | 36 ++++++++++++++++++++++++++----------
|
||||
1 file changed, 26 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/dma/bcm2835-dma.c
|
||||
+++ b/drivers/dma/bcm2835-dma.c
|
||||
@@ -488,6 +488,17 @@ static struct dma_async_tx_descriptor *b
|
||||
c->cyclic = true;
|
||||
|
||||
return vchan_tx_prep(&c->vc, &d->vd, flags);
|
||||
+error_cb:
|
||||
+ i--;
|
||||
+ for (; i >= 0; i--) {
|
||||
+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
|
||||
+
|
||||
+ dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr);
|
||||
+ }
|
||||
+
|
||||
+ kfree(d->cb_list);
|
||||
+ kfree(d);
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *
|
||||
@@ -534,6 +545,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
+ d->c = c;
|
||||
d->dir = direction;
|
||||
|
||||
if (c->ch >= 8) /* LITE channel */
|
||||
@@ -553,15 +565,21 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
|
||||
d->frames += len / max_size + 1;
|
||||
}
|
||||
|
||||
- /* Allocate memory for control blocks */
|
||||
- d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
|
||||
- d->control_block_base = dma_zalloc_coherent(chan->device->dev,
|
||||
- d->control_block_size, &d->control_block_base_phys,
|
||||
- GFP_NOWAIT);
|
||||
- if (!d->control_block_base) {
|
||||
+ d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
|
||||
+ if (!d->cb_list) {
|
||||
kfree(d);
|
||||
return NULL;
|
||||
}
|
||||
+ /* Allocate memory for control blocks */
|
||||
+ for (i = 0; i < d->frames; i++) {
|
||||
+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
|
||||
+
|
||||
+ cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC,
|
||||
+ &cb_entry->paddr);
|
||||
+
|
||||
+ if (!cb_entry->cb)
|
||||
+ goto error_cb;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* Iterate over all SG entries, create a control block
|
||||
@@ -578,7 +596,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
|
||||
|
||||
for (j = 0; j < len; j += max_size) {
|
||||
struct bcm2835_dma_cb *control_block =
|
||||
- &d->control_block_base[i + split_cnt];
|
||||
+ d->cb_list[i + split_cnt].cb;
|
||||
|
||||
/* Setup addresses */
|
||||
if (d->dir == DMA_DEV_TO_MEM) {
|
||||
@@ -620,9 +638,7 @@ bcm2835_dma_prep_slave_sg(struct dma_cha
|
||||
if (i < sg_len - 1 || len - j > max_size) {
|
||||
/* Next block is the next frame. */
|
||||
control_block->next =
|
||||
- d->control_block_base_phys +
|
||||
- sizeof(struct bcm2835_dma_cb) *
|
||||
- (i + split_cnt + 1);
|
||||
+ d->cb_list[i + split_cnt + 1].paddr;
|
||||
} else {
|
||||
/* Next block is empty. */
|
||||
control_block->next = 0;
|
|
@ -0,0 +1,247 @@
|
|||
From 7740825fc5e8324d362566ecc61f95fbdc38370a Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 11 Nov 2015 11:38:59 +0000
|
||||
Subject: [PATCH 090/127] scripts: Multi-platform support for mkknlimg and
|
||||
knlinfo
|
||||
|
||||
The firmware uses tags in the kernel trailer to choose which dtb file
|
||||
to load. Current firmware loads bcm2835-*.dtb if the '283x' tag is true,
|
||||
otherwise it loads bcm270*.dtb. This scheme breaks if an image supports
|
||||
multiple platforms.
|
||||
|
||||
This patch adds '270X' and '283X' tags to indicate support for RPi and
|
||||
upstream platforms, respectively. '283x' (note lower case 'x') is left
|
||||
for old firmware, and is only set if the image only supports upstream
|
||||
builds.
|
||||
---
|
||||
scripts/knlinfo | 2 +
|
||||
scripts/mkknlimg | 136 +++++++++++++++++++++++++++++++------------------------
|
||||
2 files changed, 80 insertions(+), 58 deletions(-)
|
||||
|
||||
--- a/scripts/knlinfo
|
||||
+++ b/scripts/knlinfo
|
||||
@@ -18,6 +18,8 @@ my %atom_formats =
|
||||
(
|
||||
'DTOK' => \&format_bool,
|
||||
'KVer' => \&format_string,
|
||||
+ '270X' => \&format_bool,
|
||||
+ '283X' => \&format_bool,
|
||||
'283x' => \&format_bool,
|
||||
);
|
||||
|
||||
--- a/scripts/mkknlimg
|
||||
+++ b/scripts/mkknlimg
|
||||
@@ -13,12 +13,20 @@ use strict;
|
||||
use warnings;
|
||||
use integer;
|
||||
|
||||
+use constant FLAG_PI => 0x01;
|
||||
+use constant FLAG_DTOK => 0x02;
|
||||
+use constant FLAG_DDTK => 0x04;
|
||||
+use constant FLAG_270X => 0x08;
|
||||
+use constant FLAG_283X => 0x10;
|
||||
+
|
||||
my $trailer_magic = 'RPTL';
|
||||
|
||||
my $tmpfile1 = "/tmp/mkknlimg_$$.1";
|
||||
my $tmpfile2 = "/tmp/mkknlimg_$$.2";
|
||||
|
||||
my $dtok = 0;
|
||||
+my $ddtk = 0;
|
||||
+my $is_270x = 0;
|
||||
my $is_283x = 0;
|
||||
|
||||
while (@ARGV && ($ARGV[0] =~ /^-/))
|
||||
@@ -28,6 +36,14 @@ while (@ARGV && ($ARGV[0] =~ /^-/))
|
||||
{
|
||||
$dtok = 1;
|
||||
}
|
||||
+ elsif ($arg eq '--ddtk')
|
||||
+ {
|
||||
+ $ddtk = 1;
|
||||
+ }
|
||||
+ elsif ($arg eq '--270x')
|
||||
+ {
|
||||
+ $is_270x = 1;
|
||||
+ }
|
||||
elsif ($arg eq '--283x')
|
||||
{
|
||||
$is_283x = 1;
|
||||
@@ -50,30 +66,33 @@ if (! -r $kernel_file)
|
||||
usage();
|
||||
}
|
||||
|
||||
-my @wanted_strings =
|
||||
-(
|
||||
- 'bcm2708_fb',
|
||||
- 'brcm,bcm2835-mmc',
|
||||
- 'brcm,bcm2835-sdhost',
|
||||
- 'brcm,bcm2708-pinctrl',
|
||||
- 'brcm,bcm2835-gpio',
|
||||
- 'brcm,bcm2835',
|
||||
- 'brcm,bcm2836'
|
||||
-);
|
||||
+my $wanted_strings =
|
||||
+{
|
||||
+ 'bcm2708_fb' => FLAG_PI,
|
||||
+ 'brcm,bcm2835-mmc' => FLAG_PI,
|
||||
+ 'brcm,bcm2835-sdhost' => FLAG_PI,
|
||||
+ 'brcm,bcm2708-pinctrl' => FLAG_PI | FLAG_DTOK,
|
||||
+ 'brcm,bcm2835-gpio' => FLAG_PI | FLAG_DTOK,
|
||||
+ 'brcm,bcm2708' => FLAG_PI | FLAG_DTOK | FLAG_270X,
|
||||
+ 'brcm,bcm2709' => FLAG_PI | FLAG_DTOK | FLAG_270X,
|
||||
+ 'brcm,bcm2835' => FLAG_PI | FLAG_DTOK | FLAG_283X,
|
||||
+ 'brcm,bcm2836' => FLAG_PI | FLAG_DTOK | FLAG_283X,
|
||||
+ 'of_overlay_apply' => FLAG_DTOK | FLAG_DDTK,
|
||||
+};
|
||||
|
||||
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);
|
||||
+$res ||= try_decompress('\037\213\010', 'xy', 'gunzip', 0,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
+$res ||= try_decompress('\3757zXZ\000', 'abcde', 'unxz --single-stream', -1,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
+$res ||= try_decompress('BZh', 'xy', 'bunzip2', 0,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
+$res ||= try_decompress('\135\0\0\0', 'xxx', 'unlzma', 0,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
+$res ||= try_decompress('\211\114\132', 'xy', 'lzop -d', 0,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
+$res ||= try_decompress('\002\041\114\030', 'xy', 'lz4 -d', 1,
|
||||
+ $kernel_file, $tmpfile1, $tmpfile2);
|
||||
|
||||
my $append_trailer;
|
||||
my $trailer;
|
||||
@@ -83,27 +102,21 @@ $append_trailer = $dtok;
|
||||
|
||||
if ($res)
|
||||
{
|
||||
- $kver = $res->{''} || '?';
|
||||
+ $kver = $res->{'kver'} || '?';
|
||||
+ my $flags = $res->{'flags'};
|
||||
print("Version: $kver\n");
|
||||
|
||||
- $append_trailer = $dtok;
|
||||
- if (!$dtok)
|
||||
+ if ($flags & FLAG_PI)
|
||||
{
|
||||
- if (config_bool($res, 'bcm2708_fb') ||
|
||||
- config_bool($res, 'brcm,bcm2835-mmc') ||
|
||||
- config_bool($res, 'brcm,bcm2835-sdhost'))
|
||||
- {
|
||||
- $dtok ||= config_bool($res, 'brcm,bcm2708-pinctrl');
|
||||
- $dtok ||= config_bool($res, 'brcm,bcm2835-gpio');
|
||||
- $is_283x ||= config_bool($res, 'brcm,bcm2835');
|
||||
- $is_283x ||= config_bool($res, 'brcm,bcm2836');
|
||||
- $dtok ||= $is_283x;
|
||||
- $append_trailer = 1;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
|
||||
- }
|
||||
+ $append_trailer = 1;
|
||||
+ $dtok ||= ($flags & FLAG_DTOK) != 0;
|
||||
+ $is_270x ||= ($flags & FLAG_270X) != 0;
|
||||
+ $is_283x ||= ($flags & FLAG_283X) != 0;
|
||||
+ $ddtk ||= ($flags & FLAG_DDTK) != 0;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ print ("* This doesn't look like a Raspberry Pi kernel. In pass-through mode.\n");
|
||||
}
|
||||
}
|
||||
elsif (!$dtok)
|
||||
@@ -114,6 +127,8 @@ elsif (!$dtok)
|
||||
if ($append_trailer)
|
||||
{
|
||||
printf("DT: %s\n", $dtok ? "y" : "n");
|
||||
+ printf("DDT: %s\n", $ddtk ? "y" : "n") if ($ddtk);
|
||||
+ printf("270x: %s\n", $is_270x ? "y" : "n");
|
||||
printf("283x: %s\n", $is_283x ? "y" : "n");
|
||||
|
||||
my @atoms;
|
||||
@@ -121,7 +136,10 @@ if ($append_trailer)
|
||||
push @atoms, [ $trailer_magic, pack('V', 0) ];
|
||||
push @atoms, [ 'KVer', $kver ];
|
||||
push @atoms, [ 'DTOK', pack('V', $dtok) ];
|
||||
- push @atoms, [ '283x', pack('V', $is_283x) ];
|
||||
+ push @atoms, [ 'DDTK', pack('V', $ddtk) ] if ($ddtk);
|
||||
+ push @atoms, [ '270X', pack('V', $is_270x) ];
|
||||
+ push @atoms, [ '283X', pack('V', $is_283x) ];
|
||||
+ push @atoms, [ '283x', pack('V', $is_283x && !$is_270x) ];
|
||||
|
||||
$trailer = pack_trailer(\@atoms);
|
||||
$atoms[0]->[1] = pack('V', length($trailer));
|
||||
@@ -175,7 +193,7 @@ END {
|
||||
|
||||
sub usage
|
||||
{
|
||||
- print ("Usage: mkknlimg [--dtok] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
|
||||
+ print ("Usage: mkknlimg [--dtok] [--270x] [--283x] <vmlinux|zImage|bzImage> <outfile>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@@ -189,15 +207,8 @@ sub try_extract
|
||||
|
||||
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 $res = { 'kver'=>$ver };
|
||||
+ $res->{'flags'} = strings_to_flags($knl, $wanted_strings);
|
||||
|
||||
return $res;
|
||||
}
|
||||
@@ -224,6 +235,22 @@ sub try_decompress
|
||||
return undef;
|
||||
}
|
||||
|
||||
+sub strings_to_flags
|
||||
+{
|
||||
+ my ($knl, $strings) = @_;
|
||||
+ my $string_pattern = '^('.join('|', keys(%$strings)).')$';
|
||||
+ my $flags = 0;
|
||||
+
|
||||
+ my @matches = `strings \"$knl\" | grep -E \"$string_pattern\"`;
|
||||
+ foreach my $match (@matches)
|
||||
+ {
|
||||
+ chomp($match);
|
||||
+ $flags |= $strings->{$match};
|
||||
+ }
|
||||
+
|
||||
+ return $flags;
|
||||
+}
|
||||
+
|
||||
sub pack_trailer
|
||||
{
|
||||
my ($atoms) = @_;
|
||||
@@ -235,10 +262,3 @@ sub pack_trailer
|
||||
}
|
||||
return $trailer;
|
||||
}
|
||||
-
|
||||
-sub config_bool
|
||||
-{
|
||||
- my ($configs, $wanted) = @_;
|
||||
- my $val = $configs->{$wanted} || 'n';
|
||||
- return (($val eq 'y') || ($val eq '1'));
|
||||
-}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,23 @@
|
|||
From c2b464e766dc1fa6fe28f2292f8258b64f468d7f Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 14 Oct 2015 11:32:14 -0700
|
||||
Subject: [PATCH 092/127] drm/vc4: Force HDMI to connected.
|
||||
|
||||
For some reason on the downstream tree, the HPD GPIO isn't working.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_hdmi.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||||
@@ -164,6 +164,8 @@ vc4_hdmi_connector_detect(struct drm_con
|
||||
struct drm_device *dev = connector->dev;
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
+ return connector_status_connected;
|
||||
+
|
||||
if (vc4->hdmi->hpd_gpio) {
|
||||
if (gpio_get_value(vc4->hdmi->hpd_gpio))
|
||||
return connector_status_connected;
|
|
@ -0,0 +1,147 @@
|
|||
From 084567d656e2876ed867c0a030dab0c2c4e38522 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:23:18 -0700
|
||||
Subject: [PATCH 093/127] drm/vc4: bo cache locking fixes.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_bo.c | 32 ++++++++++++++++++--------------
|
||||
drivers/gpu/drm/vc4/vc4_drv.h | 2 +-
|
||||
2 files changed, 19 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_bo.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
|
||||
@@ -112,14 +112,14 @@ void vc4_bo_cache_purge(struct drm_devic
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- spin_lock(&vc4->bo_lock);
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
while (!list_empty(&vc4->bo_cache.time_list)) {
|
||||
struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
|
||||
struct vc4_bo, unref_head);
|
||||
vc4_bo_remove_from_cache(bo);
|
||||
vc4_bo_destroy(bo);
|
||||
}
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
}
|
||||
|
||||
struct vc4_bo *vc4_bo_create(struct drm_device *dev, size_t unaligned_size)
|
||||
@@ -134,18 +134,18 @@ struct vc4_bo *vc4_bo_create(struct drm_
|
||||
return NULL;
|
||||
|
||||
/* First, try to get a vc4_bo from the kernel BO cache. */
|
||||
- spin_lock(&vc4->bo_lock);
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
if (page_index < vc4->bo_cache.size_list_size &&
|
||||
!list_empty(&vc4->bo_cache.size_list[page_index])) {
|
||||
struct vc4_bo *bo =
|
||||
list_first_entry(&vc4->bo_cache.size_list[page_index],
|
||||
struct vc4_bo, size_head);
|
||||
vc4_bo_remove_from_cache(bo);
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
kref_init(&bo->base.base.refcount);
|
||||
return bo;
|
||||
}
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
|
||||
/* Otherwise, make a new BO. */
|
||||
for (pass = 0; ; pass++) {
|
||||
@@ -215,7 +215,7 @@ vc4_bo_cache_free_old(struct drm_device
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
|
||||
|
||||
- spin_lock(&vc4->bo_lock);
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
while (!list_empty(&vc4->bo_cache.time_list)) {
|
||||
struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
|
||||
struct vc4_bo, unref_head);
|
||||
@@ -223,14 +223,14 @@ vc4_bo_cache_free_old(struct drm_device
|
||||
mod_timer(&vc4->bo_cache.time_timer,
|
||||
round_jiffies_up(jiffies +
|
||||
msecs_to_jiffies(1000)));
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
vc4_bo_remove_from_cache(bo);
|
||||
vc4_bo_destroy(bo);
|
||||
}
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
}
|
||||
|
||||
/* Called on the last userspace/kernel unreference of the BO. Returns
|
||||
@@ -248,21 +248,25 @@ void vc4_free_object(struct drm_gem_obje
|
||||
/* If the object references someone else's memory, we can't cache it.
|
||||
*/
|
||||
if (gem_bo->import_attach) {
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
vc4_bo_destroy(bo);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Don't cache if it was publicly named. */
|
||||
if (gem_bo->name) {
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
vc4_bo_destroy(bo);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
- spin_lock(&vc4->bo_lock);
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
|
||||
if (!cache_list) {
|
||||
vc4_bo_destroy(bo);
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,7 +282,7 @@ void vc4_free_object(struct drm_gem_obje
|
||||
|
||||
vc4->bo_stats.num_cached++;
|
||||
vc4->bo_stats.size_cached += gem_bo->size;
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
|
||||
vc4_bo_cache_free_old(dev);
|
||||
}
|
||||
@@ -465,7 +469,7 @@ void vc4_bo_cache_init(struct drm_device
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- spin_lock_init(&vc4->bo_lock);
|
||||
+ mutex_init(&vc4->bo_lock);
|
||||
|
||||
INIT_LIST_HEAD(&vc4->bo_cache.time_list);
|
||||
|
||||
@@ -498,9 +502,9 @@ int vc4_bo_stats_debugfs(struct seq_file
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
struct vc4_bo_stats stats;
|
||||
|
||||
- spin_lock(&vc4->bo_lock);
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
stats = vc4->bo_stats;
|
||||
- spin_unlock(&vc4->bo_lock);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
|
||||
seq_printf(m, "num bos allocated: %d\n", stats.num_allocated);
|
||||
seq_printf(m, "size bos allocated: %dkb\n", stats.size_allocated / 1024);
|
||||
--- a/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
|
||||
@@ -49,7 +49,7 @@ struct vc4_dev {
|
||||
} bo_stats;
|
||||
|
||||
/* Protects bo_cache and the BO stats. */
|
||||
- spinlock_t bo_lock;
|
||||
+ struct mutex bo_lock;
|
||||
|
||||
/* Sequence number for the last job queued in job_list.
|
||||
* Starts at 0 (no jobs emitted).
|
|
@ -0,0 +1,92 @@
|
|||
From a62d7adb16fdd9c450a0a255a3e0946c62b30b20 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:29:41 -0700
|
||||
Subject: [PATCH 094/127] drm/vc4: bo cache locking cleanup.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_bo.c | 22 +++++++++-------------
|
||||
1 file changed, 9 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_bo.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_bo.c
|
||||
@@ -215,7 +215,6 @@ vc4_bo_cache_free_old(struct drm_device
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
unsigned long expire_time = jiffies - msecs_to_jiffies(1000);
|
||||
|
||||
- mutex_lock(&vc4->bo_lock);
|
||||
while (!list_empty(&vc4->bo_cache.time_list)) {
|
||||
struct vc4_bo *bo = list_last_entry(&vc4->bo_cache.time_list,
|
||||
struct vc4_bo, unref_head);
|
||||
@@ -223,14 +222,12 @@ vc4_bo_cache_free_old(struct drm_device
|
||||
mod_timer(&vc4->bo_cache.time_timer,
|
||||
round_jiffies_up(jiffies +
|
||||
msecs_to_jiffies(1000)));
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
vc4_bo_remove_from_cache(bo);
|
||||
vc4_bo_destroy(bo);
|
||||
}
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
}
|
||||
|
||||
/* Called on the last userspace/kernel unreference of the BO. Returns
|
||||
@@ -245,29 +242,24 @@ void vc4_free_object(struct drm_gem_obje
|
||||
struct vc4_bo *bo = to_vc4_bo(gem_bo);
|
||||
struct list_head *cache_list;
|
||||
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
/* If the object references someone else's memory, we can't cache it.
|
||||
*/
|
||||
if (gem_bo->import_attach) {
|
||||
- mutex_lock(&vc4->bo_lock);
|
||||
vc4_bo_destroy(bo);
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
/* Don't cache if it was publicly named. */
|
||||
if (gem_bo->name) {
|
||||
- mutex_lock(&vc4->bo_lock);
|
||||
vc4_bo_destroy(bo);
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
- mutex_lock(&vc4->bo_lock);
|
||||
cache_list = vc4_get_cache_list_for_size(dev, gem_bo->size);
|
||||
if (!cache_list) {
|
||||
vc4_bo_destroy(bo);
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
- return;
|
||||
+ goto out;
|
||||
}
|
||||
|
||||
if (bo->validated_shader) {
|
||||
@@ -282,9 +274,11 @@ void vc4_free_object(struct drm_gem_obje
|
||||
|
||||
vc4->bo_stats.num_cached++;
|
||||
vc4->bo_stats.size_cached += gem_bo->size;
|
||||
- mutex_unlock(&vc4->bo_lock);
|
||||
|
||||
vc4_bo_cache_free_old(dev);
|
||||
+
|
||||
+out:
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
}
|
||||
|
||||
static void vc4_bo_cache_time_work(struct work_struct *work)
|
||||
@@ -293,7 +287,9 @@ static void vc4_bo_cache_time_work(struc
|
||||
container_of(work, struct vc4_dev, bo_cache.time_work);
|
||||
struct drm_device *dev = vc4->dev;
|
||||
|
||||
+ mutex_lock(&vc4->bo_lock);
|
||||
vc4_bo_cache_free_old(dev);
|
||||
+ mutex_unlock(&vc4->bo_lock);
|
||||
}
|
||||
|
||||
static void vc4_bo_cache_time_timer(unsigned long data)
|
|
@ -0,0 +1,54 @@
|
|||
From c5200dcf1298dc6789a88640ab581e364d92282b Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:32:24 -0700
|
||||
Subject: [PATCH 095/127] drm/vc4: Use job_lock to protect seqno_cb_list.
|
||||
|
||||
We're (mostly) not supposed to be using struct_mutex in drivers these
|
||||
days.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -474,7 +474,6 @@ vc4_job_handle_completed(struct vc4_dev
|
||||
vc4_complete_exec(exec);
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
}
|
||||
- spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
|
||||
list_for_each_entry_safe(cb, cb_temp, &vc4->seqno_cb_list, work.entry) {
|
||||
if (cb->seqno <= vc4->finished_seqno) {
|
||||
@@ -482,6 +481,8 @@ vc4_job_handle_completed(struct vc4_dev
|
||||
schedule_work(&cb->work);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
}
|
||||
|
||||
static void vc4_seqno_cb_work(struct work_struct *work)
|
||||
@@ -496,18 +497,19 @@ int vc4_queue_seqno_cb(struct drm_device
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
int ret = 0;
|
||||
+ unsigned long irqflags;
|
||||
|
||||
cb->func = func;
|
||||
INIT_WORK(&cb->work, vc4_seqno_cb_work);
|
||||
|
||||
- mutex_lock(&dev->struct_mutex);
|
||||
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
if (seqno > vc4->finished_seqno) {
|
||||
cb->seqno = seqno;
|
||||
list_add_tail(&cb->work.entry, &vc4->seqno_cb_list);
|
||||
} else {
|
||||
schedule_work(&cb->work);
|
||||
}
|
||||
- mutex_unlock(&dev->struct_mutex);
|
||||
+ spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
From 6a9940a2bde49eda470e58f19a6bde3ded87d7fb Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:44:35 -0700
|
||||
Subject: [PATCH 096/127] drm/vc4: Drop struct_mutex around CL validation.
|
||||
|
||||
We were using it so that we could make sure that shader validation
|
||||
state didn't change while we were validating, but now shader
|
||||
validation state is immutable. The bcl/rcl generation doesn't do any
|
||||
other BO dereferencing, and seems to have no other global state
|
||||
dependency not covered by job_lock / bo_lock.
|
||||
|
||||
Fixes a lock order reversal between mmap_sem and struct_mutex.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 12 ++++--------
|
||||
1 file changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -244,13 +244,15 @@ static void
|
||||
vc4_queue_submit(struct drm_device *dev, struct vc4_exec_info *exec)
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
- uint64_t seqno = ++vc4->emit_seqno;
|
||||
+ uint64_t seqno;
|
||||
unsigned long irqflags;
|
||||
|
||||
+ spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
+
|
||||
+ seqno = ++vc4->emit_seqno;
|
||||
exec->seqno = seqno;
|
||||
vc4_update_bo_seqnos(exec, seqno);
|
||||
|
||||
- spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
list_add_tail(&exec->head, &vc4->job_list);
|
||||
|
||||
/* If no job was executing, kick ours off. Otherwise, it'll
|
||||
@@ -608,8 +610,6 @@ vc4_submit_cl_ioctl(struct drm_device *d
|
||||
exec->args = args;
|
||||
INIT_LIST_HEAD(&exec->unref_list);
|
||||
|
||||
- mutex_lock(&dev->struct_mutex);
|
||||
-
|
||||
ret = vc4_cl_lookup_bos(dev, file_priv, exec);
|
||||
if (ret)
|
||||
goto fail;
|
||||
@@ -636,15 +636,11 @@ vc4_submit_cl_ioctl(struct drm_device *d
|
||||
/* Return the seqno for our job. */
|
||||
args->seqno = vc4->emit_seqno;
|
||||
|
||||
- mutex_unlock(&dev->struct_mutex);
|
||||
-
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
vc4_complete_exec(exec);
|
||||
|
||||
- mutex_unlock(&dev->struct_mutex);
|
||||
-
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
From 4cc42228e828c8cba5e2f712fd92fe3e0bb8b09d Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:44:35 -0700
|
||||
Subject: [PATCH 097/127] drm/vc4: Drop struct_mutex around CL validation.
|
||||
|
||||
We were using it so that we could make sure that shader validation
|
||||
state didn't change while we were validating, but now shader
|
||||
validation state is immutable. The bcl/rcl generation doesn't do any
|
||||
other BO dereferencing, and seems to have no other global state
|
||||
dependency not covered by job_lock / bo_lock. We only need to hold
|
||||
struct_mutex for object unreferencing.
|
||||
|
||||
Fixes a lock order reversal between mmap_sem and struct_mutex.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 13 ++++++-------
|
||||
1 file changed, 6 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -439,10 +439,12 @@ fail:
|
||||
}
|
||||
|
||||
static void
|
||||
-vc4_complete_exec(struct vc4_exec_info *exec)
|
||||
+vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
+ /* Need the struct lock for drm_gem_object_unreference(). */
|
||||
+ mutex_lock(&dev->struct_mutex);
|
||||
if (exec->bo) {
|
||||
for (i = 0; i < exec->bo_count; i++)
|
||||
drm_gem_object_unreference(&exec->bo[i].bo->base);
|
||||
@@ -455,6 +457,7 @@ vc4_complete_exec(struct vc4_exec_info *
|
||||
list_del(&bo->unref_head);
|
||||
drm_gem_object_unreference(&bo->base.base);
|
||||
}
|
||||
+ mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
kfree(exec);
|
||||
}
|
||||
@@ -473,7 +476,7 @@ vc4_job_handle_completed(struct vc4_dev
|
||||
list_del(&exec->head);
|
||||
|
||||
spin_unlock_irqrestore(&vc4->job_lock, irqflags);
|
||||
- vc4_complete_exec(exec);
|
||||
+ vc4_complete_exec(vc4->dev, exec);
|
||||
spin_lock_irqsave(&vc4->job_lock, irqflags);
|
||||
}
|
||||
|
||||
@@ -525,12 +528,8 @@ vc4_job_done_work(struct work_struct *wo
|
||||
{
|
||||
struct vc4_dev *vc4 =
|
||||
container_of(work, struct vc4_dev, job_done_work);
|
||||
- struct drm_device *dev = vc4->dev;
|
||||
|
||||
- /* Need the struct lock for drm_gem_object_unreference(). */
|
||||
- mutex_lock(&dev->struct_mutex);
|
||||
vc4_job_handle_completed(vc4);
|
||||
- mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -639,7 +638,7 @@ vc4_submit_cl_ioctl(struct drm_device *d
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
- vc4_complete_exec(exec);
|
||||
+ vc4_complete_exec(vc4->dev, exec);
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
From 7ad1b03ccca2d3c81ee97edfd1141b31331a0076 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 20 Oct 2015 13:59:15 +0100
|
||||
Subject: [PATCH 098/127] drm/vc4: Add support for more display plane formats.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_plane.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
|
||||
@@ -59,6 +59,22 @@ static const struct hvs_format {
|
||||
.drm = DRM_FORMAT_ARGB8888, .hvs = HVS_PIXEL_FORMAT_RGBA8888,
|
||||
.pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
|
||||
},
|
||||
+ {
|
||||
+ .drm = DRM_FORMAT_RGB565, .hvs = HVS_PIXEL_FORMAT_RGB565,
|
||||
+ .pixel_order = HVS_PIXEL_ORDER_XRGB, .has_alpha = false,
|
||||
+ },
|
||||
+ {
|
||||
+ .drm = DRM_FORMAT_BGR565, .hvs = HVS_PIXEL_FORMAT_RGB565,
|
||||
+ .pixel_order = HVS_PIXEL_ORDER_XBGR, .has_alpha = false,
|
||||
+ },
|
||||
+ {
|
||||
+ .drm = DRM_FORMAT_ARGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
|
||||
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = true,
|
||||
+ },
|
||||
+ {
|
||||
+ .drm = DRM_FORMAT_XRGB1555, .hvs = HVS_PIXEL_FORMAT_RGBA5551,
|
||||
+ .pixel_order = HVS_PIXEL_ORDER_ABGR, .has_alpha = false,
|
||||
+ },
|
||||
};
|
||||
|
||||
static const struct hvs_format *vc4_get_hvs_format(u32 drm_format)
|
|
@ -0,0 +1,26 @@
|
|||
From 7fdb9332f996fbaa26eaa805ce72a6afa590a302 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 23 Oct 2015 12:31:56 +0100
|
||||
Subject: [PATCH 099/127] drm/vc4: No need to stop the stopped threads.
|
||||
|
||||
This was leftover debug code from the hackdriver. We never submit
|
||||
unless the thread is already idle.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 4 ----
|
||||
1 file changed, 4 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -104,10 +104,6 @@ submit_cl(struct drm_device *dev, uint32
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- /* Stop any existing thread and set state to "stopped at halt" */
|
||||
- V3D_WRITE(V3D_CTNCS(thread), V3D_CTRUN);
|
||||
- barrier();
|
||||
-
|
||||
V3D_WRITE(V3D_CTNCA(thread), start);
|
||||
barrier();
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
From 65854b72066317cb2896df184794890c32f5f1bb Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 23 Oct 2015 12:33:43 +0100
|
||||
Subject: [PATCH 100/127] drm/vc4: Remove extra barrier()s aroudn CTnCA/CTnEA
|
||||
setup.
|
||||
|
||||
The writel() that these expand to already does barriers.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_gem.c | 9 +++------
|
||||
1 file changed, 3 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
|
||||
@@ -104,14 +104,11 @@ submit_cl(struct drm_device *dev, uint32
|
||||
{
|
||||
struct vc4_dev *vc4 = to_vc4_dev(dev);
|
||||
|
||||
- V3D_WRITE(V3D_CTNCA(thread), start);
|
||||
- barrier();
|
||||
-
|
||||
- /* Set the end address of the control list. Writing this
|
||||
- * register is what starts the job.
|
||||
+ /* Set the current and end address of the control list.
|
||||
+ * Writing the end register is what starts the job.
|
||||
*/
|
||||
+ V3D_WRITE(V3D_CTNCA(thread), start);
|
||||
V3D_WRITE(V3D_CTNEA(thread), end);
|
||||
- barrier();
|
||||
}
|
||||
|
||||
int
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue