brcm2708: remove linux 4.4 support
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
This commit is contained in:
parent
ada91d8a24
commit
d9d090e520
564 changed files with 0 additions and 198905 deletions
|
@ -1,364 +0,0 @@
|
|||
# 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_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_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
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_BCM_VIRT is not set
|
||||
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_CONFIGFS=y
|
||||
CONFIG_OF_DYNAMIC=y
|
||||
CONFIG_OF_EARLY_FLATTREE=y
|
||||
CONFIG_OF_FLATTREE=y
|
||||
CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_NET=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_OF_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=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_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_BCM2835=y
|
||||
CONFIG_PWM_SYSFS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=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_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
|
|
@ -1,396 +0,0 @@
|
|||
# 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_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_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
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_BCM_VIRT is not set
|
||||
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_CONFIGFS=y
|
||||
CONFIG_OF_DYNAMIC=y
|
||||
CONFIG_OF_EARLY_FLATTREE=y
|
||||
CONFIG_OF_FLATTREE=y
|
||||
CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_NET=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_OF_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=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_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_BCM2835=y
|
||||
CONFIG_PWM_SYSFS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=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_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
|
|
@ -1,391 +0,0 @@
|
|||
# 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_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_DMADEVICES=y
|
||||
CONFIG_DMA_BCM2708=y
|
||||
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_BCM_VIRT=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_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_CONFIGFS=y
|
||||
CONFIG_OF_DYNAMIC=y
|
||||
CONFIG_OF_EARLY_FLATTREE=y
|
||||
CONFIG_OF_FLATTREE=y
|
||||
CONFIG_OF_GPIO=y
|
||||
CONFIG_OF_IRQ=y
|
||||
CONFIG_OF_NET=y
|
||||
CONFIG_OF_OVERLAY=y
|
||||
CONFIG_OF_RESERVED_MEM=y
|
||||
CONFIG_OF_RESOLVE=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_GENERIC_DOMAINS=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_OF=y
|
||||
CONFIG_PM_GENERIC_DOMAINS_SLEEP=y
|
||||
CONFIG_PM_SLEEP=y
|
||||
CONFIG_PM_SLEEP_SMP=y
|
||||
CONFIG_POWER_SUPPLY=y
|
||||
CONFIG_PRINTK_TIME=y
|
||||
CONFIG_PROC_PAGE_MONITOR=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_BCM2835=y
|
||||
CONFIG_PWM_SYSFS=y
|
||||
CONFIG_RASPBERRYPI_FIRMWARE=y
|
||||
CONFIG_RASPBERRYPI_POWER=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_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
|
|
@ -1,33 +0,0 @@
|
|||
From 5e0a05acf8d39aa7ad56c3c4e3fadfeb75770244 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] 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);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
From 338345265d1f5941fb7814de74213ad610256ee8 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Fri, 17 Apr 2015 16:58:45 +0100
|
||||
Subject: [PATCH] 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");
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
From dbe73fef550bcd1eedfb34be5600f9b87e7d1fe8 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 18 Jun 2014 13:42:01 +0100
|
||||
Subject: [PATCH] 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,
|
|
@ -1,50 +0,0 @@
|
|||
From 77886db55c4fcad9de44486e0e5e370d123d81bc Mon Sep 17 00:00:00 2001
|
||||
From: Robert Tiemann <rtie@gmx.de>
|
||||
Date: Mon, 20 Jul 2015 11:01:25 +0200
|
||||
Subject: [PATCH] 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>;
|
|
@ -1,30 +0,0 @@
|
|||
From c384d8900be3c3a0aba65f9538006280545264ba Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 4 Dec 2015 17:41:50 +0000
|
||||
Subject: [PATCH] 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);
|
|
@ -1,127 +0,0 @@
|
|||
From f1b936ca7898183e0777012f57c8e5cafdda8be1 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] 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;
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
From e146ad89ce6f3d12fbaea2c2256c89ef991ea94d 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] 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++) {
|
|
@ -1,20 +0,0 @@
|
|||
From 2a1cd53412d5cd5f340b2d7fcfd642231136185a Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 30 Jun 2015 14:12:42 +0100
|
||||
Subject: [PATCH] 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];
|
|
@ -1,21 +0,0 @@
|
|||
From 49cdca06e79b83f269961599d2c0b5bde9f12cfe Mon Sep 17 00:00:00 2001
|
||||
From: notro <notro@tronnes.org>
|
||||
Date: Thu, 10 Jul 2014 13:59:47 +0200
|
||||
Subject: [PATCH] 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,
|
||||
};
|
|
@ -1,146 +0,0 @@
|
|||
From c51d537a465398bcbb03851a7f1c81b5324ee819 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 24 Feb 2015 13:40:50 +0000
|
||||
Subject: [PATCH] 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,
|
||||
},
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
From 49ffb4028436ce0efce2b8dede6138fc47b2cfd2 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 26 Feb 2015 09:58:22 +0000
|
||||
Subject: [PATCH] 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;
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
From 24fb0aecbadfc9bc8ebfb0c836ef7379b8fc5888 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 24 Jun 2015 14:10:44 +0100
|
||||
Subject: [PATCH] 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",
|
|
@ -1,58 +0,0 @@
|
|||
From 36aada743a4bdc21ad36c6b039449444a4b2ab22 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] 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[] = {
|
|
@ -1,65 +0,0 @@
|
|||
From fba1570f5f2fa5a65e933db49d3fc36126561a15 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 16:44:05 +0200
|
||||
Subject: [PATCH] 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 =
|
|
@ -1,79 +0,0 @@
|
|||
From 002e593baa098b480ee0b6990ab3e43c6b36aac0 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:21:16 +0200
|
||||
Subject: [PATCH] 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,
|
|
@ -1,54 +0,0 @@
|
|||
From 2165ae346e98922f21ffe6abad1f6d4226e445b1 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:25:51 +0200
|
||||
Subject: [PATCH] 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;
|
|
@ -1,36 +0,0 @@
|
|||
From 186eb5323a8492382d30e4857a0e45c8fc80ff2d Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:49:51 +0200
|
||||
Subject: [PATCH] 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",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
From 1c6fdc37e81dcd4be3590c7130320f23ad0761df Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:35:20 +0200
|
||||
Subject: [PATCH] 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;
|
|
@ -1,44 +0,0 @@
|
|||
From 8d32cc49fa07fb95dd101b2d544ed02027982cab Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 15:55:21 +0200
|
||||
Subject: [PATCH] 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;
|
|
@ -1,320 +0,0 @@
|
|||
From 46870419f14aa3631e1269f3ac452c99b0f1a505 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] 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");
|
|
@ -1,29 +0,0 @@
|
|||
From cdc0392f43a1ef5571880aefeefd1ffbefd1a726 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] 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);
|
|
@ -1,97 +0,0 @@
|
|||
From 50e1ac1b9abaacc14f45e7ca73dc613c4d6dba99 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] 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");
|
|
@ -1,21 +0,0 @@
|
|||
From 1dd1e763873c2e19ec9cfc8134b91406c36cac30 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sat, 10 Oct 2015 12:29:18 +0200
|
||||
Subject: [PATCH] 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;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
From f0f4368b3497d129c0c4ca0565f5b6656faed474 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Sun, 11 Oct 2015 12:28:30 +0200
|
||||
Subject: [PATCH] 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);
|
|
@ -1,57 +0,0 @@
|
|||
From 877a10a2dc756e4dfc6f0183e98467259c08e753 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] 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[] = {
|
|
@ -1,62 +0,0 @@
|
|||
From 3be2b2bdb87296b858efbbf298ae568d8ce94447 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] 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
|
@ -1,138 +0,0 @@
|
|||
From fcc9c391c9244922fc3b955d7bf08c6db8b54a9c Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 11 Nov 2015 21:01:15 +0000
|
||||
Subject: [PATCH] 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
|
||||
@@ -1282,7 +1282,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
|
@ -1,612 +0,0 @@
|
|||
From 659b118206dd29242abbb2d1f889b7b9788561f3 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] 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 */
|
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
|
@ -1,991 +0,0 @@
|
|||
From 5186a4610a8ba9a485a398991c67dc4de7a6f2cd Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 17 Jun 2015 16:07:06 +0100
|
||||
Subject: [PATCH] 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
|
@ -1,306 +0,0 @@
|
|||
From f0d2dd1294f41beea8b495625f6a299a0274dae5 Mon Sep 17 00:00:00 2001
|
||||
From: Luke Wren <luke@raspberrypi.org>
|
||||
Date: Fri, 21 Aug 2015 23:14:48 +0100
|
||||
Subject: [PATCH] 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
|
@ -1,358 +0,0 @@
|
|||
From 547bbe5578accad0c4f0a7461d5f2b99674f1e51 Mon Sep 17 00:00:00 2001
|
||||
From: Luke Wren <wren6991@gmail.com>
|
||||
Date: Sat, 5 Sep 2015 01:16:10 +0100
|
||||
Subject: [PATCH] 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>");
|
|
@ -1,841 +0,0 @@
|
|||
From e39854b38284178a8c63b4dc160d5883c2ce0a42 Mon Sep 17 00:00:00 2001
|
||||
From: Aron Szabo <aron@aron.ws>
|
||||
Date: Sat, 16 Jun 2012 12:15:55 +0200
|
||||
Subject: [PATCH] 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
|
|
@ -1,257 +0,0 @@
|
|||
From 0dff3fca2aca68c342bffbcfa38101a5a24e5e85 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:49:20 +0100
|
||||
Subject: [PATCH] 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);
|
|
@ -1,193 +0,0 @@
|
|||
From a567aafda2f0d7742253f40e65dee98eeea0e18d Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 26 Mar 2013 19:24:24 +0000
|
||||
Subject: [PATCH] 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");
|
|
@ -1,635 +0,0 @@
|
|||
From 01586aecc37865acf703736232f1e399c39eea88 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 17 Jun 2015 15:44:08 +0100
|
||||
Subject: [PATCH] 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);
|
|
@ -1,221 +0,0 @@
|
|||
From df09439826fa8830d9a5c0ec21460284b72b02ce 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] 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");
|
|
@ -1,106 +0,0 @@
|
|||
From e1a2f737f401288dd86e8adef4cc492ba4c4f0d5 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] 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
|
@ -1,460 +0,0 @@
|
|||
From 3703cda20110756a6531a570a4e52b2b42d99bf9 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Mon, 11 May 2015 09:00:42 +0100
|
||||
Subject: [PATCH] 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'));
|
||||
+}
|
|
@ -1,55 +0,0 @@
|
|||
From 74d27f374a1df3d1652dccaea3d7c1a0344215ed Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 5 Dec 2014 17:26:26 +0000
|
||||
Subject: [PATCH] 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
|
||||
@@ -957,19 +957,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));
|
||||
|
||||
/*
|
||||
* 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
|
@ -1,515 +0,0 @@
|
|||
From f24cdbd260fb91b52c2b32301713f2d0de7e15bc 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] 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";
|
||||
+};
|
|
@ -1,91 +0,0 @@
|
|||
From c5faa0d81a4cace1024a0c72c164c814b22d5499 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] 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 */
|
|
@ -1,209 +0,0 @@
|
|||
From da5e26ea79aeb2adf8ed29311a62052ebe781a66 Mon Sep 17 00:00:00 2001
|
||||
From: Harm Hanemaaijer <fgenfb@yahoo.com>
|
||||
Date: Thu, 20 Jun 2013 20:21:39 +0200
|
||||
Subject: [PATCH] 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
|
|
@ -1,91 +0,0 @@
|
|||
From aa149fc2bc1501cda2a3ddbecd41bf8f3d1bf9fe Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Tue, 26 Mar 2013 17:26:38 +0000
|
||||
Subject: [PATCH] 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) {
|
|
@ -1,242 +0,0 @@
|
|||
From aff5ad81730ac8431067dc0fd530f56a32320705 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 8 May 2013 11:46:50 +0100
|
||||
Subject: [PATCH] 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;
|
|
@ -1,22 +0,0 @@
|
|||
From b0e3030168c6f3a286e10ac36b231d10268799ad Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 3 Jul 2013 00:54:08 +0100
|
||||
Subject: [PATCH] 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,
|
|
@ -1,49 +0,0 @@
|
|||
From 39fe92f88d44056587caa272d450dd5a6ecb9a4e Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Wed, 18 Dec 2013 22:16:19 +0000
|
||||
Subject: [PATCH] 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
|
||||
@@ -5310,7 +5310,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
|
||||
@@ -5806,6 +5806,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
|
|
@ -1,128 +0,0 @@
|
|||
From f3e09b361bf5b1d8174f9b0631ab586ce9214496 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] 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");
|
|
@ -1,165 +0,0 @@
|
|||
From 8d203b91f4f8f8d582eb5c382357fe1e6d1d96d1 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] 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");
|
|
@ -1,275 +0,0 @@
|
|||
From d508e0f3ad2d918c85bd034f5da216c9498a3d6a 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] 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");
|
|
@ -1,40 +0,0 @@
|
|||
From bc573ada196b56eea95c1cca6520b916ec06660a 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] 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 | \
|
|
@ -1,282 +0,0 @@
|
|||
From eeb5b47b928a485cfe3b10bd983786aaf2050ca8 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] 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");
|
|
@ -1,22 +0,0 @@
|
|||
From a388cc17079e2411e680504c6dfc292d179bdb68 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] 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),
|
|
@ -1,178 +0,0 @@
|
|||
From 969d62154904b2a99a3531a41716025f281d96c5 Mon Sep 17 00:00:00 2001
|
||||
From: Gordon Garrity <gordon@iqaudio.com>
|
||||
Date: Sat, 8 Mar 2014 16:56:57 +0000
|
||||
Subject: [PATCH] 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");
|
|
@ -1,36 +0,0 @@
|
|||
From ff383d49e71e415d8482e9300b6c3c20e098bcef Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Mon, 14 Jul 2014 22:02:09 +0100
|
||||
Subject: [PATCH] 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");
|
||||
|
||||
@@ -1083,8 +1083,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)) {
|
|
@ -1,190 +0,0 @@
|
|||
From 754ad5a8702de8e194d1fb185b451b1e39285dea 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] 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");
|
|
@ -1,816 +0,0 @@
|
|||
From e45e0b8804ee1cf5ed841c021c82bc9f9a888ed3 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] 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 */
|
|
@ -1,27 +0,0 @@
|
|||
From b2f628e980ca6ee05ec6dde093b31e40e67d9f9e Mon Sep 17 00:00:00 2001
|
||||
From: Ryan Coe <bluemrp9@gmail.com>
|
||||
Date: Sat, 31 Jan 2015 18:25:49 -0700
|
||||
Subject: [PATCH] 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",
|
|
@ -1,169 +0,0 @@
|
|||
From 7f8f07caeaaf136c786e07a6d088f10a1ec59791 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 6 Feb 2015 13:50:57 +0000
|
||||
Subject: [PATCH] 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
|
||||
@@ -115,4 +115,11 @@ config LEDS_TRIGGER_NETDEV
|
||||
This allows LEDs to be controlled by network device activity.
|
||||
If unsure, say Y.
|
||||
|
||||
+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 */
|
|
@ -1,28 +0,0 @@
|
|||
From eb20da3dea76bd4835582038015ddfee2c401ee7 Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Fri, 27 Feb 2015 15:10:24 +0000
|
||||
Subject: [PATCH] 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,
|
|
@ -1,210 +0,0 @@
|
|||
From 6860141990edff57afd01f0d73d13cc7e84dd570 Mon Sep 17 00:00:00 2001
|
||||
From: Waldemar Brodkorb <wbrodkorb@conet.de>
|
||||
Date: Wed, 25 Mar 2015 09:26:17 +0100
|
||||
Subject: [PATCH] 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
|
@ -1,290 +0,0 @@
|
|||
From 3394e57d5ca8efcb58dd23303c57b9fb734dc632 Mon Sep 17 00:00:00 2001
|
||||
From: Gordon Hollingworth <gordon@raspberrypi.org>
|
||||
Date: Tue, 12 May 2015 14:47:56 +0100
|
||||
Subject: [PATCH] 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
|
@ -1,35 +0,0 @@
|
|||
From e1bd8231e59c90e284ddfcd9380792b40f775b1d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Thu, 25 Jun 2015 12:16:11 +0100
|
||||
Subject: [PATCH] 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__);
|
|
@ -1,20 +0,0 @@
|
|||
From 7db6255f0e09c3744d39871a8b86fdf3ab94675d Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Tue, 14 Jul 2015 10:26:09 +0100
|
||||
Subject: [PATCH] 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
|
||||
@@ -696,6 +696,7 @@ static const struct of_device_id spidev_
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
{ .compatible = "lineartechnology,ltc2488" },
|
||||
{ .compatible = "siliconlabs,si3210" },
|
||||
+ { .compatible = "spidev" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
File diff suppressed because it is too large
Load diff
|
@ -1,838 +0,0 @@
|
|||
From 9a7c0060167398fa754a2b8a9b1faaac40977b6f 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] 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
|
||||
@@ -2505,3 +2505,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
|
|
@ -1,243 +0,0 @@
|
|||
From 8b344be12a4fce4565784ca77ffa55efed01cac4 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <jan@grulich.eu>
|
||||
Date: Mon, 24 Aug 2015 16:03:47 +0100
|
||||
Subject: [PATCH] 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");
|
|
@ -1,91 +0,0 @@
|
|||
From 85e81afc181bb6ae8ad75723b9f2fc40db1041f2 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Grulich <jan@grulich.eu>
|
||||
Date: Mon, 24 Aug 2015 16:02:34 +0100
|
||||
Subject: [PATCH] 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),
|
||||
};
|
||||
|
||||
/*
|
|
@ -1,28 +0,0 @@
|
|||
From e0230a20a5c53115b119b80d1332a81b61991110 Mon Sep 17 00:00:00 2001
|
||||
From: popcornmix <popcornmix@gmail.com>
|
||||
Date: Mon, 28 Sep 2015 23:38:59 +0100
|
||||
Subject: [PATCH] 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);
|
|
@ -1,250 +0,0 @@
|
|||
From bd99bf8c59e9cfa39c8237e5852c51bff853e1e9 Mon Sep 17 00:00:00 2001
|
||||
From: P33M <P33M@github.com>
|
||||
Date: Wed, 21 Oct 2015 14:55:21 +0100
|
||||
Subject: [PATCH] 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,
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
From 4c9c5dfadea113fded74c2ab29f96b2109abaa04 Mon Sep 17 00:00:00 2001
|
||||
From: Matthias Reichl <hias@horus.com>
|
||||
Date: Mon, 16 Nov 2015 14:05:35 +0000
|
||||
Subject: [PATCH] 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;
|
|
@ -1,246 +0,0 @@
|
|||
From 0fda3a1eb42445783633e477f261575222c3470b Mon Sep 17 00:00:00 2001
|
||||
From: Phil Elwell <phil@raspberrypi.org>
|
||||
Date: Wed, 11 Nov 2015 11:38:59 +0000
|
||||
Subject: [PATCH] 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
|
@ -1,23 +0,0 @@
|
|||
From 9fa2b9ffdec7f13704a7980adeb0fc0ccb2b21a9 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Wed, 14 Oct 2015 11:32:14 -0700
|
||||
Subject: [PATCH] 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;
|
|
@ -1,147 +0,0 @@
|
|||
From dd3675cffbae6a8bcd35b07efea807cf7782b257 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:23:18 -0700
|
||||
Subject: [PATCH] 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).
|
|
@ -1,92 +0,0 @@
|
|||
From 2588849ca1efc5766a36bac287b7a7754c7191e1 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:29:41 -0700
|
||||
Subject: [PATCH] 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)
|
|
@ -1,54 +0,0 @@
|
|||
From cfa018eec8227589076e45fd65f654e525349ff5 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:32:24 -0700
|
||||
Subject: [PATCH] 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;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
From 42dd8243cc7c8870c01f245dab252391375384ef Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:44:35 -0700
|
||||
Subject: [PATCH] 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;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
From 22dd367f4b6b819b4b84e0b09cd7a16f00e641a9 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Mon, 19 Oct 2015 08:44:35 -0700
|
||||
Subject: [PATCH] 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;
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
From 09487bfe004a2567c1b64420a403d352cc4385e9 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Tue, 20 Oct 2015 13:59:15 +0100
|
||||
Subject: [PATCH] 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)
|
|
@ -1,26 +0,0 @@
|
|||
From 7f9ae98f26324649817bc9c66d9cfdaa9eed825d Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 23 Oct 2015 12:31:56 +0100
|
||||
Subject: [PATCH] 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();
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
From aa3b53bc69a07d03622a65a82843ba2fa4ff7b89 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 23 Oct 2015 12:33:43 +0100
|
||||
Subject: [PATCH] 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
|
|
@ -1,33 +0,0 @@
|
|||
From 3748a60377cb3f634c7e0ef209c6d67064266f61 Mon Sep 17 00:00:00 2001
|
||||
From: Eric Anholt <eric@anholt.net>
|
||||
Date: Fri, 23 Oct 2015 14:57:22 +0100
|
||||
Subject: [PATCH] drm/vc4: Fix a typo in a V3D debug register.
|
||||
|
||||
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||||
---
|
||||
drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
|
||||
drivers/gpu/drm/vc4/vc4_v3d.c | 2 +-
|
||||
2 files changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
||||
@@ -154,7 +154,7 @@
|
||||
#define V3D_PCTRS14 0x006f4
|
||||
#define V3D_PCTR15 0x006f8
|
||||
#define V3D_PCTRS15 0x006fc
|
||||
-#define V3D_BGE 0x00f00
|
||||
+#define V3D_DBGE 0x00f00
|
||||
#define V3D_FDBGO 0x00f04
|
||||
#define V3D_FDBGB 0x00f08
|
||||
#define V3D_FDBGR 0x00f0c
|
||||
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
|
||||
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
|
||||
@@ -99,7 +99,7 @@ static const struct {
|
||||
REGDEF(V3D_PCTRS14),
|
||||
REGDEF(V3D_PCTR15),
|
||||
REGDEF(V3D_PCTRS15),
|
||||
- REGDEF(V3D_BGE),
|
||||
+ REGDEF(V3D_DBGE),
|
||||
REGDEF(V3D_FDBGO),
|
||||
REGDEF(V3D_FDBGB),
|
||||
REGDEF(V3D_FDBGR),
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue