brcm2708: add 3.14 support

Signed-off-by: Florian Fainelli <florian@openwrt.org>

SVN-Revision: 42680
master
Florian Fainelli 10 years ago
parent 04c0ef5263
commit 3f5cc1882b
  1. 250
      target/linux/brcm2708/config-3.14
  2. 8595
      target/linux/brcm2708/patches-3.14/0001-Main-bcm2708-linux-port.patch
  3. 218
      target/linux/brcm2708/patches-3.14/0002-Add-quick-config.patch
  4. 57074
      target/linux/brcm2708/patches-3.14/0003-Add-dwc_otg-driver.patch
  5. 435
      target/linux/brcm2708/patches-3.14/0004-bcm2708-watchdog-driver.patch
  6. 3049
      target/linux/brcm2708/patches-3.14/0005-bcm2708-framebuffer-driver.patch
  7. 12553
      target/linux/brcm2708/patches-3.14/0006-bcm2708-vchiq-driver.patch
  8. 166
      target/linux/brcm2708/patches-3.14/0007-vchiq-Avoid-high-load-when-blocked-and-unkillable.patch
  9. 1293
      target/linux/brcm2708/patches-3.14/0008-cma-Add-vc_cma-driver-to-enable-use-of-CMA.patch
  10. 2366
      target/linux/brcm2708/patches-3.14/0009-bcm2708-alsa-sound-driver.patch
  11. 482
      target/linux/brcm2708/patches-3.14/0010-alsa-add-mmap-support-and-some-cleanups-to-bcm2835-A.patch
  12. 183
      target/linux/brcm2708/patches-3.14/0011-Add-hwrng-hardware-random-number-generator-driver.patch
  13. 747
      target/linux/brcm2708/patches-3.14/0012-lirc-added-support-for-RaspberryPi-GPIO.patch
  14. 1276
      target/linux/brcm2708/patches-3.14/0013-Fixes-for-sdhci-bcm2708.patch
  15. 304
      target/linux/brcm2708/patches-3.14/0014-Add-cpufreq-driver.patch
  16. 510
      target/linux/brcm2708/patches-3.14/0015-Added-hwmon-thermal-driver-for-reporting-core-temper.patch
  17. 96
      target/linux/brcm2708/patches-3.14/0016-Allow-mac-address-to-be-set-in-smsc95xx.patch
  18. 1386
      target/linux/brcm2708/patches-3.14/0017-Add-Chris-Boot-s-i2c-and-spi-drivers.patch
  19. 77
      target/linux/brcm2708/patches-3.14/0018-Perform-I2C-combined-transactions-when-possible.patch
  20. 279
      target/linux/brcm2708/patches-3.14/0019-enabling-the-realtime-clock-1-wire-chip-DS1307-and-1.patch
  21. 172818
      target/linux/brcm2708/patches-3.14/0020-Add-non-mainline-source-for-rtl8192cu-wireless-drive.patch
  22. 112
      target/linux/brcm2708/patches-3.14/0021-wifi-add-patches-from-3.6.y-tree-to-make-rtl8192cu-w.patch
  23. 27
      target/linux/brcm2708/patches-3.14/0022-Added-Device-IDs-for-August-DVB-T-205.patch
  24. 1052
      target/linux/brcm2708/patches-3.14/0023-config-add-missing-options-from-3.6.y-kernel.patch
  25. 214
      target/linux/brcm2708/patches-3.14/0024-Speed-up-console-framebuffer-imageblit-function.patch
  26. 98
      target/linux/brcm2708/patches-3.14/0025-fbdev-add-FBIOCOPYAREA-ioctl.patch
  27. 460
      target/linux/brcm2708/patches-3.14/0026-bcm2708_fb-DMA-acceleration-for-fb_copyarea.patch
  28. 77
      target/linux/brcm2708/patches-3.14/0027-config-Enable-CONFIG_MEMCG-but-leave-it-disabled-due.patch
  29. 3324
      target/linux/brcm2708/patches-3.14/0028-Add-FIQ-patch-to-dwc_otg-driver.-Enable-with-dwc_otg.patch
  30. 4901
      target/linux/brcm2708/patches-3.14/0029-dwc_otg-fiq_fsm-Base-commit-for-driver-rewrite.patch
  31. 5990
      target/linux/brcm2708/patches-3.14/0030-bcm2835-add-v4l2-camera-device.patch
  32. 2377
      target/linux/brcm2708/patches-3.14/0031-V4L2-Fixes-from-6by9.patch
  33. 473
      target/linux/brcm2708/patches-3.14/0032-snd-bcm2835-Add-support-for-spdif-hdmi-passthrough.patch
  34. 642
      target/linux/brcm2708/patches-3.14/0033-dmaengine-Add-support-for-BCM2708.patch
  35. 1000
      target/linux/brcm2708/patches-3.14/0034-ASoC-Add-support-for-BCM2708.patch
  36. 47
      target/linux/brcm2708/patches-3.14/0035-BCM2708-Extend-mach-header.patch
  37. 130
      target/linux/brcm2708/patches-3.14/0036-ASoC-Add-support-for-PCM5102A-codec.patch
  38. 60
      target/linux/brcm2708/patches-3.14/0037-BCM2708-Add-I2S-support-to-board-file.patch
  39. 154
      target/linux/brcm2708/patches-3.14/0038-ASoC-Add-support-for-HifiBerry-DAC.patch
  40. 53
      target/linux/brcm2708/patches-3.14/0039-BCM2708-Add-HifiBerry-DAC-to-board-file.patch
  41. 77
      target/linux/brcm2708/patches-3.14/0040-ASoC-BCM2708-Add-24-bit-support.patch
  42. 45
      target/linux/brcm2708/patches-3.14/0041-BCM2708-Add-I2S-and-DMA-support-to-default-config.patch
  43. 316
      target/linux/brcm2708/patches-3.14/0042-ASoC-BCM2708-Add-support-for-RPi-DAC.patch
  44. 119
      target/linux/brcm2708/patches-3.14/0043-ASoC-wm8804-Implement-MCLK-configuration-options-add.patch
  45. 208
      target/linux/brcm2708/patches-3.14/0044-ASoC-BCM-Add-support-for-HiFiBerry-Digi.-Driver-is-b.patch
  46. 52
      target/linux/brcm2708/patches-3.14/0045-BCM2708-Added-support-for-HiFiBerry-Digi-board-Board.patch
  47. 30
      target/linux/brcm2708/patches-3.14/0046-BCM2708-Added-HiFiBerry-Digi-configuration-option-It.patch
  48. 27
      target/linux/brcm2708/patches-3.14/0047-ASoC-wm8804-Set-idle_bias_off-to-false-Idle-bias-has.patch
  49. 40
      target/linux/brcm2708/patches-3.14/0048-ASoc-Don-t-report-S24_LE-support-it-produces-white-n.patch
  50. 1094
      target/linux/brcm2708/patches-3.14/0049-Add-IQaudIO-Sound-Card-support-for-Raspberry-Pi.patch
  51. 78
      target/linux/brcm2708/patches-3.14/0050-Fix-volsw_range-functions-so-SOC_DOUBLE_R_RANGE_TLV-.patch
  52. 29
      target/linux/brcm2708/patches-3.14/0051-Use-a-range-macro-for-Playback-Volume.patch
  53. 56
      target/linux/brcm2708/patches-3.14/0052-fix-soc-core-s-inverse-range-and-let-IQaudIO-DAC-use.patch
  54. 101
      target/linux/brcm2708/patches-3.14/0053-Move-GPIO-setup-to-hw_params.patch
  55. 77
      target/linux/brcm2708/patches-3.14/0054-fb-distinguish-physical-and-bus-addresses.patch

@ -0,0 +1,250 @@
# CONFIG_AIO is not set
CONFIG_ALIGNMENT_TRAP=y
# CONFIG_APM_EMULATION is not set
CONFIG_ARCH_BCM2708=y
CONFIG_ARCH_BINFMT_ELF_RANDOMIZE_PIE=y
CONFIG_ARCH_HAS_CPU_IDLE_WAIT=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_SUSPEND_POSSIBLE=y
# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
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_NR_BANKS=8
# CONFIG_ARM_SP805_WATCHDOG is not set
CONFIG_ARM_THUMB=y
CONFIG_ARM_UNWIND=y
CONFIG_AVERAGE=y
# CONFIG_BACKLIGHT_ADP8860 is not set
# CONFIG_BACKLIGHT_ADP8870 is not set
CONFIG_BACKLIGHT_CLASS_DEVICE=m
CONFIG_BACKLIGHT_GENERIC=m
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BCM2708_DMAER=y
CONFIG_BCM2708_GPIO=y
# CONFIG_BCM2708_NOL2CACHE is not set
CONFIG_BCM2708_VCHIQ=y
CONFIG_BCM2708_VCMEM=y
CONFIG_BCM2708_WDT=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_CACHE_L2X0 is not set
CONFIG_CLKDEV_LOOKUP=y
CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext3 rootwait"
CONFIG_CMDLINE_FROM_BOOTLOADER=y
CONFIG_CONFIGFS_FS=y
CONFIG_CONSOLE_TRANSLATIONS=y
CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS=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_HAS_PMU=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_USE_DOMAINS=y
CONFIG_CPU_V6=y
CONFIG_CRC16=y
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_USER is not set
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DEVTMPFS=y
CONFIG_DNOTIFY=y
CONFIG_DUMMY_CONSOLE=y
CONFIG_ELF_CORE=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_WMT_GE_ROPS is not set
CONFIG_FIRMWARE_IN_KERNEL=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x16=y
CONFIG_FONT_8x8=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_ACL=y
CONFIG_GENERIC_ATOMIC64=y
CONFIG_GENERIC_BUG=y
CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_GENERIC_PCI_IOMAP=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
# CONFIG_HAMRADIO is not set
CONFIG_HARDIRQS_SW_RESEND=y
CONFIG_HAS_DMA=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAVE_AOUT=y
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_HAVE_ARCH_PFN_VALID=y
CONFIG_HAVE_CLK=y
CONFIG_HAVE_C_RECORDMCOUNT=y
CONFIG_HAVE_DMA_API_DEBUG=y
CONFIG_HAVE_DYNAMIC_FTRACE=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_GENERIC_HARDIRQS=y
CONFIG_HAVE_IRQ_WORK=y
CONFIG_HAVE_KERNEL_GZIP=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_OPROFILE=y
CONFIG_HAVE_PERF_EVENTS=y
CONFIG_HAVE_PROC_CPU=y
CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
CONFIG_HAVE_SPARSE_IRQ=y
CONFIG_HW_CONSOLE=y
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_IOSCHED_CFQ=y
CONFIG_JBD2=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_XZ is not set
CONFIG_KTIME_SCALAR=y
# CONFIG_LCD_AMS369FG06 is not set
CONFIG_LCD_CLASS_DEVICE=m
# CONFIG_LCD_L4F00242T03 is not set
# CONFIG_LCD_LD9040 is not set
# CONFIG_LCD_LMS283GF05 is not set
# CONFIG_LCD_LTV350QV is not set
# CONFIG_LCD_PLATFORM is not set
# CONFIG_LCD_S6E63M0 is not set
# CONFIG_LCD_TDO24M is not set
# CONFIG_LCD_VGG2432A4 is not set
CONFIG_LEDS_GPIO=y
# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
# CONFIG_LEDS_TRIGGER_TIMER is not set
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_MAX_RAW_DEVS=256
CONFIG_MMC=y
# CONFIG_MMC_BCM2708 is not set
CONFIG_MMC_BLOCK=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_BCM2708=y
CONFIG_MMC_SDHCI_BCM2708_DMA=y
CONFIG_MMC_SDHCI_IO_ACCESSORS=y
CONFIG_MMC_SDHCI_PLTFM=y
# CONFIG_MTD is not set
CONFIG_NEED_DMA_MAP_STATE=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_HZ=y
CONFIG_OABI_COMPAT=y
CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_PAGE_OFFSET=0xC0000000
# CONFIG_PCI_SYSCALL is not set
# CONFIG_PDA_POWER is not set
CONFIG_PERF_USE_VMALLOC=y
CONFIG_PM=y
CONFIG_PM_CLK=y
# CONFIG_PM_DEBUG is not set
CONFIG_PM_SLEEP=y
CONFIG_POWER_SUPPLY=y
# CONFIG_PREEMPT_RCU is not set
CONFIG_PRINTK_TIME=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_RAW_DRIVER=y
# CONFIG_RTL8192CU is not set
CONFIG_SCSI=y
# CONFIG_SCSI_LOWLEVEL is not set
# CONFIG_SCSI_PROC_FS is not set
# CONFIG_SENSORS_BCM2835 is not set
# CONFIG_SERIAL_8250 is not set
# CONFIG_SERIAL_AMBA_PL010 is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
# CONFIG_SND_BCM2708_SOC_I2S is not set
# CONFIG_SQUASHFS is not set
# CONFIG_STAGING is not set
# CONFIG_STRIP_ASM_SYMS is not set
CONFIG_SUSPEND=y
CONFIG_SUSPEND_FREEZER=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
# CONFIG_TEXTSEARCH is not set
CONFIG_TMPFS_POSIX_ACL=y
CONFIG_UEVENT_HELPER_PATH=""
# CONFIG_UID16 is not set
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
# CONFIG_USB_ARCH_HAS_EHCI is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
# CONFIG_USB_ARCH_HAS_XHCI is not set
CONFIG_USB_COMMON=y
# CONFIG_USB_DEVICEFS is not set
CONFIG_USB_DEVICE_CLASS=y
CONFIG_USB_DWCOTG=y
CONFIG_USB_LIBUSUAL=y
CONFIG_USB_NET_SMSC95XX=y
CONFIG_USB_STORAGE=y
CONFIG_USB_SUPPORT=y
CONFIG_USB_UAS=y
CONFIG_USB_USBNET=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_VFP=y
# CONFIG_VIDEO_BCM2835 is not set
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_VT_CONSOLE_SLEEP=y
CONFIG_VT_HW_CONSOLE_BINDING=y
CONFIG_XZ_DEC_ARM=y
CONFIG_XZ_DEC_BCJ=y
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZONE_DMA_FLAG=0

@ -0,0 +1,218 @@
From 99871c2479dd1d1eaab88f738a77ca4846906b35 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 7 May 2013 22:20:24 +0100
Subject: [PATCH 02/54] Add quick config.
This is designed for quick compiling when developing.
No modules are needed and it includes all Pi specific drivers
---
arch/arm/configs/bcmrpi_quick_defconfig | 197 ++++++++++++++++++++++++++++++++
1 file changed, 197 insertions(+)
create mode 100644 arch/arm/configs/bcmrpi_quick_defconfig
diff --git a/arch/arm/configs/bcmrpi_quick_defconfig b/arch/arm/configs/bcmrpi_quick_defconfig
new file mode 100644
index 0000000..e5efe75
--- /dev/null
+++ b/arch/arm/configs/bcmrpi_quick_defconfig
@@ -0,0 +1,197 @@
+# CONFIG_ARM_PATCH_PHYS_VIRT is not set
+CONFIG_LOCALVERSION="-quick"
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+CONFIG_PERF_EVENTS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_ARCH_BCM2708=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_UACCESS_WITH_MEMCPY=y
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_IDLE=y
+CONFIG_VFP=y
+CONFIG_BINFMT_MISC=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SCSI=y
+# CONFIG_SCSI_PROC_FS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+CONFIG_USB_NET_SMSC95XX=y
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_AMBA_PL011=y
+CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
+CONFIG_TTY_PRINTK=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_BCM2708=y
+CONFIG_RAW_DRIVER=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_BCM2835=y
+CONFIG_WATCHDOG=y
+CONFIG_BCM2708_WDT=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_DEBUG=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
+CONFIG_REGULATOR_USERSPACE_CONSUMER=y
+CONFIG_FB=y
+CONFIG_FB_BCM2708=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_BCM2835=y
+# CONFIG_SND_USB is not set
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_DWCOTG=y
+CONFIG_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_BCM2708=y
+CONFIG_MMC_SDHCI_BCM2708_DMA=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FSCACHE=y
+CONFIG_CACHEFILES=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_CONFIGFS_FS=y
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFS_FSCACHE=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_FS=y
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_FTRACE is not set
+CONFIG_KGDB=y
+CONFIG_KGDB_KDB=y
+# CONFIG_ARM_UNWIND is not set
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_LIBCRC32C=y
--
1.9.1

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

@ -0,0 +1,166 @@
From 376fdba15bcf4b106ba7d62ee350baf21099cfbf Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Mon, 12 May 2014 15:12:02 +0100
Subject: [PATCH 07/54] vchiq: Avoid high load when blocked and unkillable
---
.../interface/vchiq_arm/vchiq_2835_arm.c | 1 +
.../vc04_services/interface/vchiq_arm/vchiq_arm.c | 1 +
.../interface/vchiq_arm/vchiq_connected.c | 1 +
.../vc04_services/interface/vchiq_arm/vchiq_core.c | 1 +
.../interface/vchiq_arm/vchiq_kern_lib.c | 1 +
.../interface/vchiq_arm/vchiq_killable.h | 69 ++++++++++++++++++++++
.../vc04_services/interface/vchiq_arm/vchiq_util.c | 1 +
7 files changed, 75 insertions(+)
create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
index b3bdaa2..7e7b09f 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
@@ -56,6 +56,7 @@
#include "vchiq_arm.h"
#include "vchiq_2835.h"
#include "vchiq_connected.h"
+#include "vchiq_killable.h"
#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
index c1fb8c3..99c8967e 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_arm.c
@@ -49,6 +49,7 @@
#include "vchiq_core.h"
#include "vchiq_ioctl.h"
#include "vchiq_arm.h"
+#include "vchiq_killable.h"
#define DEVICE_NAME "vchiq"
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
index 65f4b52..5efc62f 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_connected.c
@@ -33,6 +33,7 @@
#include "vchiq_connected.h"
#include "vchiq_core.h"
+#include "vchiq_killable.h"
#include <linux/module.h>
#include <linux/mutex.h>
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
index f35ed4f..71ed0a5 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_core.c
@@ -32,6 +32,7 @@
*/
#include "vchiq_core.h"
+#include "vchiq_killable.h"
#define VCHIQ_SLOT_HANDLER_STACK 8192
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
index be9735f..5a4182e 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_kern_lib.c
@@ -39,6 +39,7 @@
#include "vchiq_core.h"
#include "vchiq_arm.h"
+#include "vchiq_killable.h"
/* ---- Public Variables ------------------------------------------------- */
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
new file mode 100644
index 0000000..505ee1a
--- /dev/null
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_killable.h
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_KILLABLE_H
+#define VCHIQ_KILLABLE_H
+
+#include <linux/mutex.h>
+#include <linux/semaphore.h>
+
+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
+
+static inline int __must_check down_interruptible_killable(struct semaphore *sem)
+{
+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
+ int ret;
+ sigset_t blocked, oldset;
+ siginitsetinv(&blocked, SHUTDOWN_SIGS);
+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
+ ret = down_interruptible(sem);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return ret;
+}
+#define down_interruptible down_interruptible_killable
+
+
+static inline int __must_check mutex_lock_interruptible_killable(struct mutex *lock)
+{
+ /* Allow interception of killable signals only. We don't want to be interrupted by harmless signals like SIGALRM */
+ int ret;
+ sigset_t blocked, oldset;
+ siginitsetinv(&blocked, SHUTDOWN_SIGS);
+ sigprocmask(SIG_SETMASK, &blocked, &oldset);
+ ret = mutex_lock_interruptible(lock);
+ sigprocmask(SIG_SETMASK, &oldset, NULL);
+ return ret;
+}
+#define mutex_lock_interruptible mutex_lock_interruptible_killable
+
+#endif
diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
index c2eefef..05e7979 100644
--- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_util.c
@@ -32,6 +32,7 @@
*/
#include "vchiq_util.h"
+#include "vchiq_killable.h"
static inline int is_pow2(int i)
{
--
1.9.1

@ -0,0 +1,482 @@
From 00d2b7bf3cd58d9735f103ff4cc6982b7dc927fe Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 26 Apr 2013 10:08:31 -0700
Subject: [PATCH 10/54] alsa: add mmap support and some cleanups to bcm2835
ALSA driver
---
sound/arm/bcm2835-pcm.c | 69 ++++++++++++++++++++++--------------
sound/arm/bcm2835-vchiq.c | 89 +++++++++++++++++++++++++++++++++--------------
sound/arm/bcm2835.c | 34 +++++++++---------
sound/arm/bcm2835.h | 2 ++
4 files changed, 124 insertions(+), 70 deletions(-)
diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
index 2e7d405..b4084bb 100755
--- a/sound/arm/bcm2835-pcm.c
+++ b/sound/arm/bcm2835-pcm.c
@@ -19,7 +19,8 @@
/* hardware definition */
static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
- .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER),
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
.rate_min = 8000,
@@ -251,6 +252,12 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
audio_info(" .. IN\n");
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+ alsa_stream->pcm_indirect.hw_buffer_size =
+ alsa_stream->pcm_indirect.sw_buffer_size =
+ snd_pcm_lib_buffer_bytes(substream);
+
alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
alsa_stream->pos = 0;
@@ -263,6 +270,32 @@ static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
return 0;
}
+static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
+ struct snd_pcm_indirect *rec, size_t bytes)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+ void *src = (void *)(substream->runtime->dma_area + rec->sw_data);
+ int err;
+
+ err = bcm2835_audio_write(alsa_stream, bytes, src);
+ if (err)
+ audio_error(" Failed to transfer to alsa device (%d)\n", err);
+
+}
+
+static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
+
+ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
+ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
+ snd_bcm2835_pcm_transfer);
+ return 0;
+}
+
/* trigger callback */
static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
@@ -279,6 +312,11 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
if (!alsa_stream->running) {
err = bcm2835_audio_start(alsa_stream);
if (err == 0) {
+ alsa_stream->pcm_indirect.hw_io =
+ alsa_stream->pcm_indirect.hw_data =
+ bytes_to_frames(runtime,
+ alsa_stream->pos);
+ substream->ops->ack(substream);
alsa_stream->running = 1;
alsa_stream->draining = 1;
} else {
@@ -327,30 +365,9 @@ snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
alsa_stream->pos);
audio_info(" .. OUT\n");
- return bytes_to_frames(runtime, alsa_stream->pos);
-}
-
-static int snd_bcm2835_pcm_copy(struct snd_pcm_substream *substream,
- int channel, snd_pcm_uframes_t pos, void *src,
- snd_pcm_uframes_t count)
-{
- int ret;
- struct snd_pcm_runtime *runtime = substream->runtime;
- bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
-
- audio_info(" .. IN\n");
- audio_debug("copy.......... (%d) hwptr=%d appl=%d pos=%d\n",
- frames_to_bytes(runtime, count), frames_to_bytes(runtime,
- runtime->
- status->
- hw_ptr),
- frames_to_bytes(runtime, runtime->control->appl_ptr),
- alsa_stream->pos);
- ret =
- bcm2835_audio_write(alsa_stream, frames_to_bytes(runtime, count),
- src);
- audio_info(" .. OUT\n");
- return ret;
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+ alsa_stream->pos);
}
static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
@@ -372,7 +389,7 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = {
.prepare = snd_bcm2835_pcm_prepare,
.trigger = snd_bcm2835_pcm_trigger,
.pointer = snd_bcm2835_pcm_pointer,
- .copy = snd_bcm2835_pcm_copy,
+ .ack = snd_bcm2835_pcm_ack,
};
/* create a pcm device */
diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c
index b9b4fe8..ee09b13 100755
--- a/sound/arm/bcm2835-vchiq.c
+++ b/sound/arm/bcm2835-vchiq.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/module.h>
+#include <linux/completion.h>
#include "bcm2835.h"
@@ -37,6 +38,10 @@
/* ---- Private Constants and Types ------------------------------------------ */
+#define BCM2835_AUDIO_STOP 0
+#define BCM2835_AUDIO_START 1
+#define BCM2835_AUDIO_WRITE 2
+
/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
#ifdef AUDIO_DEBUG_ENABLE
#define LOG_ERR( fmt, arg... ) pr_err( "%s:%d " fmt, __func__, __LINE__, ##arg)
@@ -53,7 +58,7 @@
typedef struct opaque_AUDIO_INSTANCE_T {
uint32_t num_connections;
VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
- struct semaphore msg_avail_event;
+ struct completion msg_avail_comp;
struct mutex vchi_mutex;
bcm2835_alsa_stream_t *alsa_stream;
int32_t result;
@@ -70,27 +75,35 @@ bool force_bulk = false;
static int bcm2835_audio_stop_worker(bcm2835_alsa_stream_t * alsa_stream);
static int bcm2835_audio_start_worker(bcm2835_alsa_stream_t * alsa_stream);
+static int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
+ uint32_t count, void *src);
typedef struct {
struct work_struct my_work;
bcm2835_alsa_stream_t *alsa_stream;
- int x;
+ int cmd;
+ void *src;
+ uint32_t count;
} my_work_t;
static void my_wq_function(struct work_struct *work)
{
my_work_t *w = (my_work_t *) work;
int ret = -9;
- LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->x);
- switch (w->x) {
- case 1:
+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
+ switch (w->cmd) {
+ case BCM2835_AUDIO_START:
ret = bcm2835_audio_start_worker(w->alsa_stream);
break;
- case 2:
+ case BCM2835_AUDIO_STOP:
ret = bcm2835_audio_stop_worker(w->alsa_stream);
break;
+ case BCM2835_AUDIO_WRITE:
+ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
+ w->src);
+ break;
default:
- LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->x);
+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
break;
}
kfree((void *)work);
@@ -107,7 +120,7 @@ int bcm2835_audio_start(bcm2835_alsa_stream_t * alsa_stream)
if (work) {
INIT_WORK((struct work_struct *)work, my_wq_function);
work->alsa_stream = alsa_stream;
- work->x = 1;
+ work->cmd = BCM2835_AUDIO_START;
if (queue_work
(alsa_stream->my_wq, (struct work_struct *)work))
ret = 0;
@@ -128,7 +141,31 @@ int bcm2835_audio_stop(bcm2835_alsa_stream_t * alsa_stream)
if (work) {
INIT_WORK((struct work_struct *)work, my_wq_function);
work->alsa_stream = alsa_stream;
- work->x = 2;
+ work->cmd = BCM2835_AUDIO_STOP;
+ if (queue_work
+ (alsa_stream->my_wq, (struct work_struct *)work))
+ ret = 0;
+ } else
+ LOG_ERR(" .. Error: NULL work kmalloc\n");
+ }
+ LOG_DBG(" .. OUT %d\n", ret);
+ return ret;
+}
+
+int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream,
+ uint32_t count, void *src)
+{
+ int ret = -1;
+ LOG_DBG(" .. IN\n");
+ if (alsa_stream->my_wq) {
+ my_work_t *work = kmalloc(sizeof(my_work_t), GFP_ATOMIC);
+ /*--- Queue some work (item 1) ---*/
+ if (work) {
+ INIT_WORK((struct work_struct *)work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+ work->cmd = BCM2835_AUDIO_WRITE;
+ work->src = src;
+ work->count = count;
if (queue_work
(alsa_stream->my_wq, (struct work_struct *)work))
ret = 0;
@@ -178,7 +215,7 @@ static void audio_vchi_callback(void *param,
(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
instance, m.u.result.success);
instance->result = m.u.result.success;
- up(&instance->msg_avail_event);
+ complete(&instance->msg_avail_comp);
} else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
irq_handler_t callback = (irq_handler_t) m.u.complete.callback;
LOG_DBG
@@ -435,8 +472,8 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
m.u.control.dest = chip->dest;
m.u.control.volume = chip->volume;
- /* Create the message available event */
- sema_init(&instance->msg_avail_event, 0);
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
/* Send the message to the videocore */
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -452,11 +489,10 @@ static int bcm2835_audio_set_ctls_chan(bcm2835_alsa_stream_t * alsa_stream,
}
/* We are expecting a reply from the videocore */
- if (down_interruptible(&instance->msg_avail_event)) {
+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
+ if (ret) {
LOG_ERR("%s: failed on waiting for event (status=%d)\n",
__func__, success);
-
- ret = -1;
goto unlock;
}
@@ -539,8 +575,8 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
m.u.config.samplerate = samplerate;
m.u.config.bps = bps;
- /* Create the message available event */
- sema_init(&instance->msg_avail_event, 0);
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
/* Send the message to the videocore */
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -556,11 +592,10 @@ int bcm2835_audio_set_params(bcm2835_alsa_stream_t * alsa_stream,
}
/* We are expecting a reply from the videocore */
- if (down_interruptible(&instance->msg_avail_event)) {
+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
+ if (ret) {
LOG_ERR("%s: failed on waiting for event (status=%d)\n",
__func__, success);
-
- ret = -1;
goto unlock;
}
@@ -688,8 +723,8 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
m.type = VC_AUDIO_MSG_TYPE_CLOSE;
- /* Create the message available event */
- sema_init(&instance->msg_avail_event, 0);
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
/* Send the message to the videocore */
success = vchi_msg_queue(instance->vchi_handle[0],
@@ -702,11 +737,11 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream)
ret = -1;
goto unlock;
}
- if (down_interruptible(&instance->msg_avail_event)) {
+
+ ret = wait_for_completion_interruptible(&instance->msg_avail_comp);
+ if (ret) {
LOG_ERR("%s: failed on waiting for event (status=%d)",
__func__, success);
-
- ret = -1;
goto unlock;
}
if (instance->result != 0) {
@@ -732,8 +767,8 @@ unlock:
return ret;
}
-int bcm2835_audio_write(bcm2835_alsa_stream_t * alsa_stream, uint32_t count,
- void *src)
+int bcm2835_audio_write_worker(bcm2835_alsa_stream_t *alsa_stream,
+ uint32_t count, void *src)
{
VC_AUDIO_MSG_T m;
AUDIO_INSTANCE_T *instance = alsa_stream->instance;
diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
index 317e7d9..e2047a7 100755
--- a/sound/arm/bcm2835.c
+++ b/sound/arm/bcm2835.c
@@ -110,20 +110,20 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
err = snd_bcm2835_create(g_card, pdev, &chip);
if (err < 0) {
- printk(KERN_ERR "Failed to create bcm2835 chip\n");
+ dev_err(&pdev->dev, "Failed to create bcm2835 chip\n");
goto out_bcm2835_create;
}
g_chip = chip;
err = snd_bcm2835_new_pcm(chip);
if (err < 0) {
- printk(KERN_ERR "Failed to create new BCM2835 pcm device\n");
+ dev_err(&pdev->dev, "Failed to create new BCM2835 pcm device\n");
goto out_bcm2835_new_pcm;
}
err = snd_bcm2835_new_ctl(chip);
if (err < 0) {
- printk(KERN_ERR "Failed to create new BCM2835 ctl\n");
+ dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
goto out_bcm2835_new_ctl;
}
@@ -139,14 +139,14 @@ add_register_map:
if (dev == 0) {
err = snd_card_register(card);
if (err < 0) {
- printk(KERN_ERR
- "Failed to register bcm2835 ALSA card \n");
+ dev_err(&pdev->dev,
+ "Failed to register bcm2835 ALSA card \n");
goto out_card_register;
}
platform_set_drvdata(pdev, card);
- printk(KERN_INFO "bcm2835 ALSA card created!\n");
+ audio_info("bcm2835 ALSA card created!\n");
} else {
- printk(KERN_INFO "bcm2835 ALSA chip created!\n");
+ audio_info("bcm2835 ALSA chip created!\n");
platform_set_drvdata(pdev, (void *)dev);
}
@@ -160,11 +160,11 @@ out_bcm2835_new_pcm:
out_bcm2835_create:
BUG_ON(!g_card);
if (snd_card_free(g_card))
- printk(KERN_ERR "Failed to free Registered alsa card\n");
+ dev_err(&pdev->dev, "Failed to free Registered alsa card\n");
g_card = NULL;
out:
dev = SNDRV_CARDS; /* stop more avail_substreams from being probed */
- printk(KERN_ERR "BCM2835 ALSA Probe failed !!\n");
+ dev_err(&pdev->dev, "BCM2835 ALSA Probe failed !!\n");
return err;
}
@@ -326,49 +326,49 @@ static int bcm2835_alsa_device_init(void)
int err;
err = platform_driver_register(&bcm2835_alsa0_driver);
if (err) {
- printk("Error registering bcm2835_alsa0_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto out;
}
err = platform_driver_register(&bcm2835_alsa1_driver);
if (err) {
- printk("Error registering bcm2835_alsa1_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_0;
}
err = platform_driver_register(&bcm2835_alsa2_driver);
if (err) {
- printk("Error registering bcm2835_alsa2_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_1;
}
err = platform_driver_register(&bcm2835_alsa3_driver);
if (err) {
- printk("Error registering bcm2835_alsa3_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_2;
}
err = platform_driver_register(&bcm2835_alsa4_driver);
if (err) {
- printk("Error registering bcm2835_alsa4_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_3;
}
err = platform_driver_register(&bcm2835_alsa5_driver);
if (err) {
- printk("Error registering bcm2835_alsa5_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_4;
}
err = platform_driver_register(&bcm2835_alsa6_driver);
if (err) {
- printk("Error registering bcm2835_alsa6_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_5;
}
err = platform_driver_register(&bcm2835_alsa7_driver);
if (err) {
- printk("Error registering bcm2835_alsa7_driver %d .\n", err);
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", err);
goto unregister_6;
}
diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
index 080bd5c..36afee3 100755
--- a/sound/arm/bcm2835.h
+++ b/sound/arm/bcm2835.h
@@ -23,6 +23,7 @@
#include <sound/initval.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/pcm-indirect.h>
#include <linux/workqueue.h>
/*
@@ -110,6 +111,7 @@ typedef struct bcm2835_chip {
typedef struct bcm2835_alsa_stream {
bcm2835_chip_t *chip;
struct snd_pcm_substream *substream;
+ struct snd_pcm_indirect pcm_indirect;
struct semaphore buffers_update_sem;
struct semaphore control_sem;
--
1.9.1

@ -0,0 +1,183 @@
From 2bae9a662d169ecb7d3e1c39ebbcbc80b7dc845f Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:51:55 +0100
Subject: [PATCH 11/54] Add hwrng (hardware random number generator) driver
---
arch/arm/mach-bcm2708/include/mach/platform.h | 1 +
drivers/char/hw_random/Kconfig | 11 +++
drivers/char/hw_random/Makefile | 1 +
drivers/char/hw_random/bcm2708-rng.c | 117 ++++++++++++++++++++++++++
4 files changed, 130 insertions(+)
create mode 100755 drivers/char/hw_random/bcm2708-rng.c
diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h
index 110ce07..ecd854e 100644
--- a/arch/arm/mach-bcm2708/include/mach/platform.h
+++ b/arch/arm/mach-bcm2708/include/mach/platform.h
@@ -60,6 +60,7 @@
#define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */
#define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */
#define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
+#define RNG_BASE (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */
#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
#define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 2f2b084..cfca8e9 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -341,6 +341,17 @@ config HW_RANDOM_TPM
If unsure, say Y.
+config HW_RANDOM_BCM2708
+ tristate "BCM2708 generic true random number generator support"
+ depends on HW_RANDOM && ARCH_BCM2708
+ ---help---
+ This driver provides the kernel-side support for the BCM2708 hardware.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bcm2708-rng.
+
+ If unsure, say N.
+
config HW_RANDOM_MSM
tristate "Qualcomm MSM Random Number Generator support"
depends on HW_RANDOM && ARCH_MSM
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index 3ae7755..a7bfb80 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -29,4 +29,5 @@ obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
+obj-$(CONFIG_HW_RANDOM_BCM2708) += bcm2708-rng.o
obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o
diff --git a/drivers/char/hw_random/bcm2708-rng.c b/drivers/char/hw_random/bcm2708-rng.c
new file mode 100755
index 0000000..1ffa7d7
--- /dev/null
+++ b/drivers/char/hw_random/bcm2708-rng.c
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2010-2012 Broadcom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/hw_random.h>
+#include <linux/printk.h>
+
+#include <asm/io.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#define RNG_CTRL (0x0)
+#define RNG_STATUS (0x4)
+#define RNG_DATA (0x8)
+#define RNG_FF_THRESHOLD (0xc)
+
+/* enable rng */
+#define RNG_RBGEN 0x1
+/* double speed, less random mode */
+#define RNG_RBG2X 0x2
+
+/* the initial numbers generated are "less random" so will be discarded */
+#define RNG_WARMUP_COUNT 0x40000
+
+static int bcm2708_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ void __iomem *rng_base = (void __iomem *)rng->priv;
+ unsigned words;
+ /* wait for a random number to be in fifo */
+ do {
+ words = __raw_readl(rng_base + RNG_STATUS)>>24;
+ }
+ while (words == 0);
+ /* read the random number */
+ *buffer = __raw_readl(rng_base + RNG_DATA);
+ return 4;
+}
+
+static struct hwrng bcm2708_rng_ops = {
+ .name = "bcm2708",
+ .data_read = bcm2708_rng_data_read,
+};
+
+static int __init bcm2708_rng_init(void)
+{
+ void __iomem *rng_base;
+ int err;
+
+ /* map peripheral */
+ rng_base = ioremap(RNG_BASE, 0x10);
+ pr_info("bcm2708_rng_init=%p\n", rng_base);
+ if (!rng_base) {
+ pr_err("bcm2708_rng_init failed to ioremap\n");
+ return -ENOMEM;
+ }
+ bcm2708_rng_ops.priv = (unsigned long)rng_base;
+ /* register driver */
+ err = hwrng_register(&bcm2708_rng_ops);
+ if (err) {
+ pr_err("bcm2708_rng_init hwrng_register()=%d\n", err);
+ iounmap(rng_base);
+ } else {
+ /* set warm-up count & enable */
+ __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS);
+ __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL);
+ }
+ return err;
+}
+
+static void __exit bcm2708_rng_exit(void)
+{
+ void __iomem *rng_base = (void __iomem *)bcm2708_rng_ops.priv;
+ pr_info("bcm2708_rng_exit\n");
+ /* disable rng hardware */
+ __raw_writel(0, rng_base + RNG_CTRL);
+ /* unregister driver */
+ hwrng_unregister(&bcm2708_rng_ops);
+ iounmap(rng_base);
+}
+
+module_init(bcm2708_rng_init);
+module_exit(bcm2708_rng_exit);
+
+MODULE_DESCRIPTION("BCM2708 H/W Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL and additional rights");
--
1.9.1

@ -0,0 +1,747 @@
From 04439327ad7c2afd72b6fe8c43c922b892dff7c3 Mon Sep 17 00:00:00 2001
From: Aron Szabo <aron@aron.ws>
Date: Sat, 16 Jun 2012 12:15:55 +0200
Subject: [PATCH 12/54] 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
---
drivers/staging/media/lirc/Kconfig | 6 +
drivers/staging/media/lirc/Makefile | 1 +
drivers/staging/media/lirc/lirc_rpi.c | 695 ++++++++++++++++++++++++++++++++++
3 files changed, 702 insertions(+)
create mode 100644 drivers/staging/media/lirc/lirc_rpi.c
diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
index e60a59f..6b7ff70 100644
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -38,6 +38,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
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
index b90fcab..2b227fd 100644
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.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
diff --git a/drivers/staging/media/lirc/lirc_rpi.c b/drivers/staging/media/lirc/lirc_rpi.c
new file mode 100644
index 0000000..57ffacf
--- /dev/null
+++ b/drivers/staging/media/lirc/lirc_rpi.c
@@ -0,0 +1,695 @@
+/*
+ * 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/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>
+
+#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 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;
+struct irq_chip *irqchip;
+struct irq_data *irqdata;
+
+/* forward declarations */
+static long send_pulse(unsigned long length);
+static void send_space(long length);
+static void lirc_rpi_exit(void);
+
+int valid_gpio_pins[] = { 0, 1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 17, 18, 21,
+ 22, 23, 24, 25 ,27, 28, 29, 30, 31 };
+
+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 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;
+ read_current_timer(&actual_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);
+ read_current_timer(&actual_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);
+
+ /* unmask the irq */
+ irqchip->irq_unmask(irqdata);
+
+ 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 int init_port(void)
+{
+ int i, nlow, nhigh, ret, irq;
+
+ gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
+
+ if (!gpiochip)
+ return -ENODEV;
+
+ if (gpio_request(gpio_out_pin, LIRC_DRIVER_NAME " ir/out")) {
+ printk(KERN_ALERT LIRC_DRIVER_NAME
+ ": cant claim gpio pin %d\n", gpio_out_pin);
+ ret = -ENODEV;
+ goto exit_init_port;
+ }
+
+ if (gpio_request(gpio_in_pin, LIRC_DRIVER_NAME " ir/in")) {
+ printk(KERN_ALERT LIRC_DRIVER_NAME
+ ": cant claim gpio pin %d\n", gpio_in_pin);
+ ret = -ENODEV;
+ goto exit_gpio_free_out_pin;
+ }
+
+ gpiochip->direction_input(gpiochip, gpio_in_pin);
+ gpiochip->direction_output(gpiochip, gpio_out_pin, 1);
+ gpiochip->set(gpiochip, gpio_out_pin, invert);
+
+ irq = gpiochip->to_irq(gpiochip, gpio_in_pin);
+ dprintk("to_irq %d\n", irq);
+ irqdata = irq_get_irq_data(irq);
+
+ if (irqdata && irqdata->chip) {
+ irqchip = irqdata->chip;
+ } else {
+ ret = -ENODEV;
+ goto exit_gpio_free_in_pin;
+ }
+
+ /* if pin is high, then this must be an active low receiver. */
+ if (sense == -1) {
+ /* wait 1/2 sec for the power supply */
+ msleep(500);
+
+ /*
+ * probe 9 times every 0.04s, collect "votes" for
+ * active high/low
+ */
+ nlow = 0;
+ nhigh = 0;
+ for (i = 0; i < 9; i++) {
+ if (gpiochip->get(gpiochip, gpio_in_pin))
+ nlow++;
+ else
+ nhigh++;
+ msleep(40);
+ }
+ sense = (nlow >= nhigh ? 1 : 0);
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": auto-detected active %s receiver on GPIO pin %d\n",
+ sense ? "low" : "high", gpio_in_pin);
+ } else {
+ printk(KERN_INFO LIRC_DRIVER_NAME
+ ": manually using active %s receiver on GPIO pin %d\n",
+ sense ? "low" : "high", gpio_in_pin);
+ }
+
+ return 0;
+
+ exit_gpio_free_in_pin:
+ gpio_free(gpio_in_pin);
+
+ exit_gpio_free_out_pin:
+ gpio_free(gpio_out_pin);
+
+ exit_init_port:
+ return ret;
+}
+
+// called when the character device is opened
+static int set_use_inc(void *data)
+{
+ int result;
+ unsigned long flags;
+
+ /* initialize timestamp */
+ do_gettimeofday(&lasttv);
+
+ result = request_irq(gpiochip->to_irq(gpiochip, gpio_in_pin),
+ (irq_handler_t) irq_handler, 0,
+ LIRC_DRIVER_NAME, (void*) 0);
+
+ switch (result) {
+ case -EBUSY:
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": IRQ %d is busy\n",
+ gpiochip->to_irq(gpiochip, gpio_in_pin));
+ return -EBUSY;
+ case -EINVAL:
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": Bad irq number or handler\n");
+ return -EINVAL;
+ default:
+ dprintk("Interrupt %d obtained\n",
+ gpiochip->to_irq(gpiochip, gpio_in_pin));
+ break;
+ };
+
+ /* initialize pulse/space widths */
+ init_timing_params(duty_cycle, freq);
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* GPIO Pin Falling/Rising Edge Detect Enable */
+ irqchip->irq_set_type(irqdata,
+ IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING);
+
+ /* unmask the irq */
+ irqchip->irq_unmask(irqdata);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ return 0;
+}
+
+static void set_use_dec(void *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&lock, flags);
+
+ /* GPIO Pin Falling/Rising Edge Detect Disable */
+ irqchip->irq_set_type(irqdata, 0);
+ irqchip->irq_mask(irqdata);
+
+ spin_unlock_irqrestore(&lock, flags);
+
+ free_irq(gpiochip->to_irq(gpiochip, gpio_in_pin), (void *) 0);
+
+ dprintk(KERN_INFO LIRC_DRIVER_NAME
+ ": freed IRQ %d\n", gpiochip->to_irq(gpiochip, gpio_in_pin));
+}
+
+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 struct platform_driver lirc_rpi_driver = {
+ .driver = {
+ .name = LIRC_DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init lirc_rpi_init(void)
+{
+ 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;
+ }
+
+ 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)
+{
+ 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, i;
+
+ result = lirc_rpi_init();
+ if (result)
+ return result;
+
+ /* check if the module received valid gpio pin numbers */
+ result = 0;
+ if (gpio_in_pin != gpio_out_pin) {
+ for(i = 0; (i < ARRAY_SIZE(valid_gpio_pins)) && (result != 2); i++) {
+ if (gpio_in_pin == valid_gpio_pins[i] ||
+ gpio_out_pin == valid_gpio_pins[i]) {
+ result++;
+ }
+ }
+ }
+
+ if (result != 2) {
+ result = -EINVAL;
+ printk(KERN_ERR LIRC_DRIVER_NAME
+ ": invalid GPIO pin(s) specified!\n");
+ goto exit_rpi;
+ }
+
+ 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)
+{
+ gpio_free(gpio_out_pin);
+ gpio_free(gpio_in_pin);
+
+ lirc_rpi_exit();
+
+ lirc_unregister_driver(driver.minor);
+ 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. Valid pin numbers are: 0, 1, 4, 8, 7, 9, 10, 11,"
+ " 14, 15, 17, 18, 21, 22, 23, 24, 25, default 17");
+
+module_param(gpio_in_pin, int, S_IRUGO);
+MODULE_PARM_DESC(gpio_in_pin, "GPIO input pin number of the BCM processor."
+ " Valid pin numbers are: 0, 1, 4, 8, 7, 9, 10, 11, 14, 15,"
+ " 17, 18, 21, 22, 23, 24, 25, default 18");
+
+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");
--
1.9.1

@ -0,0 +1,304 @@
From 4882beaf73302c162f08620d770f020211bf0acb Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 3 Jul 2013 00:49:20 +0100
Subject: [PATCH 14/54] Add cpufreq driver
---
arch/arm/Kconfig | 1 +
drivers/cpufreq/Kconfig.arm | 8 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/bcm2835-cpufreq.c | 239 ++++++++++++++++++++++++++++++++++++++
4 files changed, 249 insertions(+)
create mode 100755 drivers/cpufreq/bcm2835-cpufreq.c
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9e23417..be8a752 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -389,6 +389,7 @@ config ARCH_BCM2708
select NEED_MACH_GPIO_H
select NEED_MACH_MEMORY_H
select CLKDEV_LOOKUP
+ select ARCH_HAS_CPUFREQ
select GENERIC_CLOCKEVENTS
select ARM_ERRATA_411920
select MACH_BCM2708
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 3129749..d12c80d 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -235,6 +235,14 @@ config ARM_SPEAR_CPUFREQ
help
This adds the CPUFreq driver support for SPEAr SOCs.
+config ARM_BCM2835_CPUFREQ
+ bool "BCM2835 Driver"
+ default y
+ help
+ This adds the CPUFreq driver for BCM2835
+
+ If in doubt, say N.
+
config ARM_TEGRA_CPUFREQ
bool "TEGRA CPUFreq support"
depends on ARCH_TEGRA
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index dac58f6..d8ded24 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -73,6 +73,7 @@ obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
+obj-$(CONFIG_ARM_BCM2835_CPUFREQ) += bcm2835-cpufreq.o
obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o
obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o
diff --git a/drivers/cpufreq/bcm2835-cpufreq.c b/drivers/cpufreq/bcm2835-cpufreq.c
new file mode 100755
index 0000000..7bc55bd
--- /dev/null
+++ b/drivers/cpufreq/bcm2835-cpufreq.c
@@ -0,0 +1,239 @@
+/*****************************************************************************
+* 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 <mach/vcio.h>
+
+/* ---------- DEFINES ---------- */
+/*#define CPUFREQ_DEBUG_ENABLE*/ /* enable debugging */
+#define MODULE_NAME "bcm2835-cpufreq"
+
+#define VCMSG_ID_ARM_CLOCK 0x000000003 /* Clock/Voltage ID's */
+
+/* debug printk macros */
+#ifdef CPUFREQ_DEBUG_ENABLE
+#define print_debug(fmt,...) pr_debug("%s:%s:%d: "fmt, MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define print_debug(fmt,...)
+#endif
+#define print_err(fmt,...) pr_err("%s:%s:%d: "fmt, MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
+#define print_info(fmt,...) pr_info("%s: "fmt, MODULE_NAME, ##__VA_ARGS__)
+
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the message id */
+ uint32_t buffer_size; /* size of the buffer (which in this case is always 8 bytes) */
+ uint32_t data_size; /* amount of data being sent or received */
+ uint32_t dev_id; /* the ID of the clock/voltage to get or set */
+ uint32_t val; /* the value (e.g. rate (in Hz)) to set */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+/* ---------- GLOBALS ---------- */
+static struct cpufreq_driver bcm2835_cpufreq_driver; /* the cpufreq driver global */
+
+/*
+ ===============================================
+ clk_rate either gets or sets the clock rates.
+ ===============================================
+*/
+static uint32_t bcm2835_cpufreq_set_clock(int cur_rate, int arm_rate)
+{
+ int s, actual_rate=0;
+ struct vc_msg msg;
+
+ /* wipe all previous message data */
+ memset(&msg, 0, sizeof msg);
+
+ msg.msg_size = sizeof msg;
+
+ msg.tag.tag_id = VCMSG_SET_CLOCK_RATE;
+ msg.tag.buffer_size = 8;
+ msg.tag.data_size = 8; /* we're sending the clock ID and the new rates which is a total of 2 words */
+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
+ msg.tag.val = arm_rate * 1000;
+
+ /* send the message */
+ s = bcm_mailbox_property(&msg, sizeof msg);
+
+ /* check if it was all ok and return the rate in KHz */
+ if (s == 0 && (msg.request_code & 0x80000000))
+ actual_rate = msg.tag.val/1000;
+
+ print_debug("Setting new frequency = %d -> %d (actual %d)\n", cur_rate, arm_rate, actual_rate);
+ return actual_rate;
+}
+
+static uint32_t bcm2835_cpufreq_get_clock(int tag)
+{
+ int s;
+ int arm_rate = 0;
+ struct vc_msg msg;
+
+ /* wipe all previous message data */
+ memset(&msg, 0, sizeof msg);
+
+ msg.msg_size = sizeof msg;
+ msg.tag.tag_id = tag;
+ msg.tag.buffer_size = 8;
+ msg.tag.data_size = 4; /* we're just sending the clock ID which is one word long */
+ msg.tag.dev_id = VCMSG_ID_ARM_CLOCK;
+
+ /* send the message */
+ s = bcm_mailbox_property(&msg, sizeof msg);
+
+ /* check if it was all ok and return the rate in KHz */
+ if (s == 0 && (msg.request_code & 0x80000000))
+ arm_rate = msg.tag.val/1000;
+
+ print_debug("%s frequency = %d\n",
+ tag == VCMSG_GET_CLOCK_RATE ? "Current":
+ tag == VCMSG_GET_MIN_CLOCK ? "Min":
+ tag == VCMSG_GET_MAX_CLOCK ? "Max":
+ "Unexpected", arm_rate);
+
+ return arm_rate;
+}
+
+/*
+ ====================================================
+ Module Initialisation registers the cpufreq driver
+ ====================================================
+*/
+static int __init bcm2835_cpufreq_module_init(void)
+{
+ print_debug("IN\n");
+ return cpufreq_register_driver(&bcm2835_cpufreq_driver);
+}
+
+/*
+ =============
+ Module exit
+ =============
+*/
+static void __exit bcm2835_cpufreq_module_exit(void)
+{
+ print_debug("IN\n");
+ cpufreq_unregister_driver(&bcm2835_cpufreq_driver);
+ return;
+}
+
+/*
+ ==============================================================
+ Initialisation function sets up the CPU policy for first use
+ ==============================================================
+*/
+static int bcm2835_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+ /* measured value of how long it takes to change frequency */
+ policy->cpuinfo.transition_latency = 355000; /* ns */
+
+ /* now find out what the maximum and minimum frequencies are */
+ policy->min = policy->cpuinfo.min_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MIN_CLOCK);
+ policy->max = policy->cpuinfo.max_freq = bcm2835_cpufreq_get_clock(VCMSG_GET_MAX_CLOCK);
+ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
+
+ print_info("min=%d max=%d cur=%d\n", policy->min, policy->max, policy->cur);
+ return 0;
+}
+
+/*
+ =================================================================================
+ Target function chooses the most appropriate frequency from the table to enable
+ =================================================================================
+*/
+
+static int bcm2835_cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
+{
+ unsigned int target = target_freq;
+#ifdef CPUFREQ_DEBUG_ENABLE
+ unsigned int cur = policy->cur;
+#endif
+ print_debug("%s: min=%d max=%d cur=%d target=%d\n",policy->governor->name,policy->min,policy->max,policy->cur,target_freq);
+
+ /* if we are above min and using ondemand, then just use max */
+ if (strcmp("ondemand", policy->governor->name)==0 && target > policy->min)
+ target = policy->max;
+ /* if the frequency is the same, just quit */
+ if (target == policy->cur)
+ return 0;
+
+ /* otherwise were good to set the clock frequency */
+ policy->cur = bcm2835_cpufreq_set_clock(policy->cur, target);
+
+ if (!policy->cur)
+ {
+ print_err("Error occurred setting a new frequency (%d)!\n", target);
+ policy->cur = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
+ return -EINVAL;
+ }
+ print_debug("Freq %d->%d (min=%d max=%d target=%d request=%d)\n", cur, policy->cur, policy->min, policy->max, target_freq, target);
+ return 0;
+}
+
+static unsigned int bcm2835_cpufreq_driver_get(unsigned int cpu)
+{
+ unsigned int actual_rate = bcm2835_cpufreq_get_clock(VCMSG_GET_CLOCK_RATE);
+ print_debug("cpu=%d\n", actual_rate);
+ return actual_rate;
+}
+
+/*
+ =================================================================================
+ Verify ensures that when a policy is changed, it is suitable for the CPU to use
+ =================================================================================
+*/
+
+static int bcm2835_cpufreq_driver_verify(struct cpufreq_policy *policy)
+{
+ print_info("switching to governor %s\n", policy->governor->name);
+ return 0;
+}
+
+
+/* the CPUFreq driver */
+static struct cpufreq_driver bcm2835_cpufreq_driver = {
+ .name = "BCM2835 CPUFreq",
+ .init = bcm2835_cpufreq_driver_init,
+ .verify = bcm2835_cpufreq_driver_verify,
+ .target = bcm2835_cpufreq_driver_target,
+ .get = bcm2835_cpufreq_driver_get
+};
+
+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.9.1

@ -0,0 +1,510 @@
From 22964c3b89f28e0957965aee59e713670d3a7729 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 19:24:24 +0000
Subject: [PATCH 15/54] Added hwmon/thermal driver for reporting core
temperature. Thanks Dorian
---
arch/arm/mach-bcm2708/bcm2708.c | 11 ++
drivers/hwmon/Kconfig | 10 ++
drivers/hwmon/Makefile | 1 +
drivers/hwmon/bcm2835-hwmon.c | 219 ++++++++++++++++++++++++++++++++++++++
drivers/thermal/Kconfig | 6 ++
drivers/thermal/Makefile | 1 +
drivers/thermal/bcm2835-thermal.c | 184 ++++++++++++++++++++++++++++++++
7 files changed, 432 insertions(+)
create mode 100644 drivers/hwmon/bcm2835-hwmon.c
create mode 100644 drivers/thermal/bcm2835-thermal.c
Index: linux-3.14.18/arch/arm/mach-bcm2708/bcm2708.c
===================================================================
--- linux-3.14.18.orig/arch/arm/mach-bcm2708/bcm2708.c 2014-09-27 12:03:08.607411837 -0700
+++ linux-3.14.18/arch/arm/mach-bcm2708/bcm2708.c 2014-09-27 12:03:08.603411837 -0700
@@ -483,6 +483,14 @@
},
};
+static struct platform_device bcm2835_hwmon_device = {
+ .name = "bcm2835_hwmon",
+};
+
+static struct platform_device bcm2835_thermal_device = {
+ .name = "bcm2835_thermal",
+};
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -594,6 +602,9 @@
for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++)
bcm_register_device(&bcm2708_alsa_devices[i]);
+ bcm_register_device(&bcm2835_hwmon_device);
+ bcm_register_device(&bcm2835_thermal_device);
+
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
Index: linux-3.14.18/drivers/hwmon/Kconfig
===================================================================
--- linux-3.14.18.orig/drivers/hwmon/Kconfig 2014-09-27 12:03:08.607411837 -0700
+++ linux-3.14.18/drivers/hwmon/Kconfig 2014-09-27 12:03:08.603411837 -0700
@@ -1565,6 +1565,16 @@
help
Support for the A/D converter on MC13783 and MC13892 PMIC.
+config SENSORS_BCM2835
+ depends on THERMAL_BCM2835=n
+ tristate "Broadcom BCM2835 HWMON Driver"
+ help
+ If you say yes here you get support for the hardware
+ monitoring features of the BCM2835 Chip
+
+ This driver can also be built as a module. If so, the module
+ will be called bcm2835-hwmon.
+
if ACPI
comment "ACPI drivers"
Index: linux-3.14.18/drivers/hwmon/bcm2835-hwmon.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-3.14.18/drivers/hwmon/bcm2835-hwmon.c 2014-09-27 12:03:08.603411837 -0700
@@ -0,0 +1,219 @@
+/*****************************************************************************
+* Copyright 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <mach/vcio.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#define MODULE_NAME "bcm2835_hwmon"
+
+/*#define HWMON_DEBUG_ENABLE*/
+
+#ifdef HWMON_DEBUG_ENABLE
+#define print_debug(fmt,...) printk(KERN_INFO "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define print_debug(fmt,...)
+#endif
+#define print_err(fmt,...) printk(KERN_ERR "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
+#define print_info(fmt,...) printk(KERN_INFO "%s: "fmt"\n", MODULE_NAME, ##__VA_ARGS__)
+
+#define VC_TAG_GET_TEMP 0x00030006
+#define VC_TAG_GET_MAX_TEMP 0x0003000A
+
+/* --- STRUCTS --- */
+struct bcm2835_hwmon_data {
+ struct device *hwmon_dev;
+};
+
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the tag ID for the temperature */
+ uint32_t buffer_size; /* size of the buffer (should be 8) */
+ uint32_t request_code; /* identifies message as a request (should be 0) */
+ uint32_t id; /* extra ID field (should be 0) */
+ uint32_t val; /* returned value of the temperature */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+typedef enum {
+ TEMP,
+ MAX_TEMP,
+} temp_type;
+
+/* --- PROTOTYPES --- */
+static ssize_t bcm2835_get_temp(struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t bcm2835_get_name(struct device *dev, struct device_attribute *attr, char *buf);
+
+/* --- GLOBALS --- */
+
+static struct bcm2835_hwmon_data *bcm2835_data;
+static struct platform_driver bcm2835_hwmon_driver;
+
+static SENSOR_DEVICE_ATTR(name, S_IRUGO,bcm2835_get_name,NULL,0);
+static SENSOR_DEVICE_ATTR(temp1_input,S_IRUGO,bcm2835_get_temp,NULL,TEMP);
+static SENSOR_DEVICE_ATTR(temp1_max,S_IRUGO,bcm2835_get_temp,NULL,MAX_TEMP);
+
+static struct attribute* bcm2835_attributes[] = {
+ &sensor_dev_attr_name.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group bcm2835_attr_group = {
+ .attrs = bcm2835_attributes,
+};
+
+/* --- FUNCTIONS --- */
+
+static ssize_t bcm2835_get_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf,"bcm2835_hwmon\n");
+}
+
+static ssize_t bcm2835_get_temp(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct vc_msg msg;
+ int result;
+ uint temp = 0;
+ int index = ((struct sensor_device_attribute*)to_sensor_dev_attr(attr))->index;
+
+ print_debug("IN");
+
+ /* wipe all previous message data */
+ memset(&msg, 0, sizeof msg);
+
+ /* determine the message type */
+ if(index == TEMP)
+ msg.tag.tag_id = VC_TAG_GET_TEMP;
+ else if (index == MAX_TEMP)
+ msg.tag.tag_id = VC_TAG_GET_MAX_TEMP;
+ else
+ {
+ print_debug("Unknown temperature message!");
+ return -EINVAL;
+ }
+
+ msg.msg_size = sizeof msg;
+ msg.tag.buffer_size = 8;
+
+ /* send the message */
+ result = bcm_mailbox_property(&msg, sizeof msg);
+
+ /* check if it was all ok and return the rate in milli degrees C */
+ if (result == 0 && (msg.request_code & 0x80000000))
+ temp = (uint)msg.tag.val;
+ #ifdef HWMON_DEBUG_ENABLE
+ else
+ print_debug("Failed to get temperature!");
+ #endif
+ print_debug("Got temperature as %u",temp);
+ print_debug("OUT");
+ return sprintf(buf, "%u\n", temp);
+}
+
+
+static int bcm2835_hwmon_probe(struct platform_device *pdev)
+{
+ int err;
+
+ print_debug("IN");
+ print_debug("HWMON Driver has been probed!");
+
+ /* check that the device isn't null!*/
+ if(pdev == NULL)
+ {
+ print_debug("Platform device is empty!");
+ return -ENODEV;
+ }
+
+ /* allocate memory for neccessary data */
+ bcm2835_data = kzalloc(sizeof(struct bcm2835_hwmon_data),GFP_KERNEL);
+ if(!bcm2835_data)
+ {
+ print_debug("Unable to allocate memory for hwmon data!");
+ err = -ENOMEM;
+ goto kzalloc_error;
+ }
+
+ /* create the sysfs files */
+ if(sysfs_create_group(&pdev->dev.kobj, &bcm2835_attr_group))
+ {
+ print_debug("Unable to create sysfs files!");
+ err = -EFAULT;
+ goto sysfs_error;
+ }
+
+ /* register the hwmon device */
+ bcm2835_data->hwmon_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(bcm2835_data->hwmon_dev))
+ {
+ err = PTR_ERR(bcm2835_data->hwmon_dev);
+ goto hwmon_error;
+ }
+ print_debug("OUT");
+ return 0;
+
+ /* error goto's */
+ hwmon_error:
+ sysfs_remove_group(&pdev->dev.kobj, &bcm2835_attr_group);
+
+ sysfs_error:
+ kfree(bcm2835_data);
+
+ kzalloc_error:
+
+ return err;
+
+}
+
+static int bcm2835_hwmon_remove(struct platform_device *pdev)
+{
+ print_debug("IN");
+ hwmon_device_unregister(bcm2835_data->hwmon_dev);
+
+ sysfs_remove_group(&pdev->dev.kobj, &bcm2835_attr_group);
+ print_debug("OUT");
+ return 0;
+}
+
+/* Hwmon Driver */
+static struct platform_driver bcm2835_hwmon_driver = {
+ .probe = bcm2835_hwmon_probe,
+ .remove = bcm2835_hwmon_remove,
+ .driver = {
+ .name = "bcm2835_hwmon",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dorian Peake");
+MODULE_DESCRIPTION("HW Monitor driver for bcm2835 chip");
+
+module_platform_driver(bcm2835_hwmon_driver);
Index: linux-3.14.18/drivers/thermal/Kconfig
===================================================================
--- linux-3.14.18.orig/drivers/thermal/Kconfig 2014-09-27 12:03:08.607411837 -0700
+++ linux-3.14.18/drivers/thermal/Kconfig 2014-09-27 12:03:08.603411837 -0700
@@ -196,6 +196,12 @@
enforce idle time which results in more package C-state residency. The
user interface is exposed via generic thermal framework.
+config THERMAL_BCM2835
+ 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
Index: linux-3.14.18/drivers/thermal/Makefile
===================================================================
--- linux-3.14.18.orig/drivers/thermal/Makefile 2014-09-27 12:03:08.607411837 -0700
+++ linux-3.14.18/drivers/thermal/Makefile 2014-09-27 12:03:08.603411837 -0700
@@ -28,6 +28,7 @@
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_TI_SOC_THERMAL) += ti-soc-thermal/
obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o
Index: linux-3.14.18/drivers/thermal/bcm2835-thermal.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-3.14.18/drivers/thermal/bcm2835-thermal.c 2014-09-27 12:03:08.603411837 -0700
@@ -0,0 +1,184 @@
+/*****************************************************************************
+* Copyright 2011 Broadcom Corporation. All rights reserved.
+*
+* Unless you and Broadcom execute a separate written software license
+* agreement governing use of this software, this software is licensed to you
+* under the terms of the GNU General Public License version 2, available at
+* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+*
+* Notwithstanding the above, under no circumstances may you combine this
+* software in any way with any other Broadcom software provided under a
+* license other than the GPL, without Broadcom's express prior written
+* consent.
+*****************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <mach/vcio.h>
+#include <linux/thermal.h>
+
+
+/* --- DEFINITIONS --- */
+#define MODULE_NAME "bcm2835_thermal"
+
+/*#define THERMAL_DEBUG_ENABLE*/
+
+#ifdef THERMAL_DEBUG_ENABLE
+#define print_debug(fmt,...) printk(KERN_INFO "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define print_debug(fmt,...)
+#endif
+#define print_err(fmt,...) printk(KERN_ERR "%s:%s:%d: "fmt"\n", MODULE_NAME, __func__,__LINE__, ##__VA_ARGS__)
+
+#define VC_TAG_GET_TEMP 0x00030006
+#define VC_TAG_GET_MAX_TEMP 0x0003000A
+
+typedef enum {
+ TEMP,
+ MAX_TEMP,
+} temp_type;
+
+/* --- STRUCTS --- */
+/* tag part of the message */
+struct vc_msg_tag {
+ uint32_t tag_id; /* the tag ID for the temperature */
+ uint32_t buffer_size; /* size of the buffer (should be 8) */
+ uint32_t request_code; /* identifies message as a request (should be 0) */
+ uint32_t id; /* extra ID field (should be 0) */
+ uint32_t val; /* returned value of the temperature */
+};
+
+/* message structure to be sent to videocore */
+struct vc_msg {
+ uint32_t msg_size; /* simply, sizeof(struct vc_msg) */
+ uint32_t request_code; /* holds various information like the success and number of bytes returned (refer to mailboxes wiki) */
+ struct vc_msg_tag tag; /* the tag structure above to make */
+ uint32_t end_tag; /* an end identifier, should be set to NULL */
+};
+
+struct bcm2835_thermal_data {
+ struct thermal_zone_device *thermal_dev;
+ struct vc_msg msg;
+};
+
+/* --- GLOBALS --- */
+static struct bcm2835_thermal_data bcm2835_data;
+
+/* Thermal Device Operations */
+static struct thermal_zone_device_ops ops;
+
+/* --- FUNCTIONS --- */
+
+static int bcm2835_get_temp_or_max(struct thermal_zone_device *thermal_dev, unsigned long *temp, unsigned tag_id)
+{
+ int result = -1, retry = 3;
+ print_debug("IN");
+
+ *temp = 0;
+ while (result != 0 && retry-- > 0) {
+ /* wipe all previous message data */
+ memset(&bcm2835_data.msg, 0, sizeof bcm2835_data.msg);
+
+ /* prepare message */
+ bcm2835_data.msg.msg_size = sizeof bcm2835_data.msg;
+ bcm2835_data.msg.tag.buffer_size = 8;
+ bcm2835_data.msg.tag.tag_id = tag_id;
+
+ /* send the message */
+ result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg);
+ print_debug("Got %stemperature as %u (%d,%x)\n", tag_id==VC_TAG_GET_MAX_TEMP ? "max ":"", (uint)bcm2835_data.msg.tag.val, result, bcm2835_data.msg.request_code);
+ if (!(bcm2835_data.msg.request_code & 0x80000000))
+ result = -1;
+ }
+
+ /* check if it was all ok and return the rate in milli degrees C */
+ if (result == 0)
+ *temp = (uint)bcm2835_data.msg.tag.val;
+ else
+ print_err("Failed to get temperature! (%x:%d)\n", tag_id, result);
+ print_debug("OUT");
+ return result;
+}
+
+static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *temp)
+{
+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_TEMP);
+}
+
+static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int trip_num, unsigned long *temp)
+{
+ return bcm2835_get_temp_or_max(thermal_dev, temp, VC_TAG_GET_MAX_TEMP);
+}
+
+static int bcm2835_get_trip_type(struct thermal_zone_device * thermal_dev, int trip_num, enum thermal_trip_type *trip_type)
+{
+ *trip_type = THERMAL_TRIP_HOT;
+ return 0;
+}
+
+
+static int bcm2835_get_mode(struct thermal_zone_device *thermal_dev, enum thermal_device_mode *dev_mode)
+{
+ *dev_mode = THERMAL_DEVICE_ENABLED;
+ return 0;
+}
+
+
+static int bcm2835_thermal_probe(struct platform_device *pdev)
+{
+ print_debug("IN");
+ print_debug("THERMAL Driver has been probed!");
+
+ /* check that the device isn't null!*/
+ if(pdev == NULL)
+ {
+ print_debug("Platform device is empty!");
+ return -ENODEV;
+ }
+
+ if(!(bcm2835_data.thermal_dev = thermal_zone_device_register("bcm2835_thermal", 1, 0, NULL, &ops, NULL, 0, 0)))
+ {
+ print_debug("Unable to register the thermal device!");
+ return -EFAULT;
+ }
+ return 0;
+}
+
+
+static int bcm2835_thermal_remove(struct platform_device *pdev)
+{
+ print_debug("IN");
+
+ thermal_zone_device_unregister(bcm2835_data.thermal_dev);
+
+ print_debug("OUT");
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops ops = {
+ .get_temp = bcm2835_get_temp,
+ .get_trip_temp = bcm2835_get_max_temp,
+ .get_trip_type = bcm2835_get_trip_type,
+ .get_mode = bcm2835_get_mode,
+};
+
+/* Thermal Driver */
+static struct platform_driver bcm2835_thermal_driver = {
+ .probe = bcm2835_thermal_probe,
+ .remove = bcm2835_thermal_remove,
+ .driver = {
+ .name = "bcm2835_thermal",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Dorian Peake");
+MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
+
+module_platform_driver(bcm2835_thermal_driver);

@ -0,0 +1,96 @@
From c025fdfc5970f5d60a381bab953e60825de8500a Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Tue, 26 Mar 2013 17:26:38 +0000
Subject: [PATCH 16/54] 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(+)
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 424db65e..fc1ef4e 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -59,6 +59,7 @@
#define SUSPEND_SUSPEND3 (0x08)
#define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \
SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3)
+#define MAC_ADDR_LEN (6)
struct smsc95xx_priv {
u32 mac_cr;
@@ -74,6 +75,10 @@ static bool turbo_mode = true;
module_param(turbo_mode, bool, 0644);
MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction");
+static char *macaddr = ":";
+module_param(macaddr, charp, 0);
+MODULE_PARM_DESC(macaddr, "MAC address");
+
static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index,
u32 *data, int in_pm)
{
@@ -763,8 +768,59 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
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.9.1

@ -0,0 +1,77 @@
From d002a24f7ff4ca8b63d08e33fd2d88af84501267 Mon Sep 17 00:00:00 2001
From: cbeytas <cbeytas@shaw.ca>
Date: Mon, 24 Jun 2013 00:05:40 -0400
Subject: [PATCH 18/54] 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
---
drivers/i2c/busses/i2c-bcm2708.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/drivers/i2c/busses/i2c-bcm2708.c b/drivers/i2c/busses/i2c-bcm2708.c
index b3d96f0..05531db 100644
--- a/drivers/i2c/busses/i2c-bcm2708.c
+++ b/drivers/i2c/busses/i2c-bcm2708.c
@@ -74,6 +74,9 @@ 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;
@@ -150,7 +153,7 @@ static inline void bcm2708_bsc_fifo_fill(struct bcm2708_i2c *bi)
static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
{
unsigned long bus_hz;
- u32 cdiv;
+ u32 cdiv, s;
u32 c = BSC_C_I2CEN | BSC_C_INTD | BSC_C_ST | BSC_C_CLEAR_1;
bus_hz = clk_get_rate(bi->clk);
@@ -166,6 +169,32 @@ static inline void bcm2708_bsc_setup(struct bcm2708_i2c *bi)
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)));
+ /* 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);
}
--
1.9.1

@ -0,0 +1,279 @@
From 370acd9248703fb8531cd87982fb02dcce32a2b4 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 8 May 2013 11:46:50 +0100
Subject: [PATCH 19/54] 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>
---
arch/arm/mach-bcm2708/bcm2708.c | 29 +++++++++++++++++++++
drivers/w1/masters/w1-gpio.c | 57 ++++++++++++++++++++++++++++++++++++-----
drivers/w1/w1.h | 6 +++++
drivers/w1/w1_int.c | 14 ++++++++++
drivers/w1/w1_io.c | 18 ++++++++++---
5 files changed, 115 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index e892006..221d145 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
+#include <linux/w1-gpio.h>
#include <linux/version.h>
#include <linux/clkdev.h>
@@ -76,12 +77,19 @@
*/
#define DMA_MASK_BITS_COMMON 32
+// use GPIO 4 for the one-wire GPIO pin, if enabled
+#define W1_GPIO 4
+// ensure one-wire GPIO pullup is disabled by default
+#define W1_PULLUP -1
+
/* command line parameters */
static unsigned boardrev, serial;
static unsigned uart_clock;
static unsigned disk_led_gpio = 16;
static unsigned disk_led_active_low = 1;
static unsigned reboot_part = 0;
+static unsigned w1_gpio_pin = W1_GPIO;
+static unsigned w1_gpio_pullup = W1_PULLUP;
static void __init bcm2708_init_led(void);
@@ -258,6 +266,20 @@ static struct platform_device bcm2708_dmaman_device = {
.num_resources = ARRAY_SIZE(bcm2708_dmaman_resources),
};
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+static struct w1_gpio_platform_data w1_gpio_pdata = {
+ .pin = W1_GPIO,
+ .ext_pullup_enable_pin = W1_PULLUP,
+ .is_open_drain = 0,
+};
+
+static struct platform_device w1_device = {
+ .name = "w1-gpio",
+ .id = -1,
+ .dev.platform_data = &w1_gpio_pdata,
+};
+#endif
+
static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON);
static struct platform_device bcm2708_fb_device = {
@@ -680,6 +702,11 @@ void __init bcm2708_init(void)
#ifdef CONFIG_BCM2708_GPIO
bcm_register_device(&bcm2708_gpio_device);
#endif
+#if defined(CONFIG_W1_MASTER_GPIO) || defined(CONFIG_W1_MASTER_GPIO_MODULE)
+ w1_gpio_pdata.pin = w1_gpio_pin;
+ w1_gpio_pdata.ext_pullup_enable_pin = w1_gpio_pullup;
+ platform_device_register(&w1_device);
+#endif
bcm_register_device(&bcm2708_systemtimer_device);
bcm_register_device(&bcm2708_fb_device);
bcm_register_device(&bcm2708_usb_device);
@@ -883,3 +910,5 @@ module_param(uart_clock, uint, 0644);
module_param(disk_led_gpio, uint, 0644);
module_param(disk_led_active_low, uint, 0644);
module_param(reboot_part, uint, 0644);
+module_param(w1_gpio_pin, uint, 0644);
+module_param(w1_gpio_pullup, uint, 0644);
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 9709b8b..b10f9c9 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -23,6 +23,15 @@
#include "../w1.h"
#include "../w1_int.h"
+static int w1_gpio_pullup = -1;
+static int w1_gpio_pullup_orig = -1;
+module_param_named(pullup, w1_gpio_pullup, int, 0);
+MODULE_PARM_DESC(pullup, "GPIO pin pullup 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 +76,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 struct of_device_id w1_gpio_dt_ids[] = {
{ .compatible = "w1-gpio" },
@@ -102,14 +121,16 @@ static int w1_gpio_probe_dt(struct platform_device *pdev)
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) {
- dev_err(&pdev->dev, "Failed to parse DT\n");
- return err;
+ if(pdata == NULL) {
+ if (of_have_populated_dt()) {
+ err = w1_gpio_probe_dt(pdev);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Failed to parse DT\n");
+ return err;
+ }
}
}
@@ -127,6 +148,19 @@ static int w1_gpio_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ w1_gpio_pin_orig = pdata->pin;
+ w1_gpio_pullup_orig = pdata->ext_pullup_enable_pin;
+
+ if(gpio_is_valid(w1_gpio_pin)) {
+ pdata->pin = w1_gpio_pin;
+ pdata->ext_pullup_enable_pin = -1;
+ }
+ if(gpio_is_valid(w1_gpio_pullup)) {
+ pdata->ext_pullup_enable_pin = w1_gpio_pullup;
+ }
+
+ dev_info(&pdev->dev, "gpio pin %d, gpio pullup pin %d\n", pdata->pin, pdata->ext_pullup_enable_pin);
+
err = devm_gpio_request(&pdev->dev, pdata->pin, "w1");
if (err) {
dev_err(&pdev->dev, "gpio_request (pin) failed\n");
@@ -156,6 +190,14 @@ static int w1_gpio_probe(struct platform_device *pdev)
master->set_pullup = w1_gpio_set_pullup;
}
+ if (gpio_is_valid(w1_gpio_pullup)) {
+ if (pdata->is_open_drain)
+ printk(KERN_ERR "w1-gpio 'pullup' 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");
@@ -186,6 +228,9 @@ static int w1_gpio_remove(struct platform_device *pdev)
w1_remove_master_device(master);
+ pdata->pin = w1_gpio_pin_orig;
+ pdata->ext_pullup_enable_pin = w1_gpio_pullup_orig;
+
return 0;
}
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index ca8081a..3392959 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -148,6 +148,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);
+
/** Really nice hardware can handles the different types of ROM search
* w1_master* is passed to the slave found callback.
*/
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 590bd8a..a4d69b6 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -118,6 +118,20 @@ int w1_add_master_device(struct w1_bus_master *master)
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). */
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index e10acc2..667fdd5 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -127,10 +127,22 @@ static void w1_pre_write(struct w1_master *dev)
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;
}
}
--
1.9.1

@ -0,0 +1,112 @@
From eaaa194153e61ed6f9fec8dda18f3e462187d327 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Sat, 9 Nov 2013 13:32:03 +0000
Subject: [PATCH 21/54] wifi: add patches from 3.6.y tree to make rtl8192cu
work
wifi: add missing patch from 3.6.y tree to disable debug
---
drivers/net/wireless/rtl8192cu/Kconfig | 4 +++-
drivers/net/wireless/rtl8192cu/Makefile | 6 +++++-
drivers/net/wireless/rtl8192cu/include/autoconf.h | 2 +-
drivers/net/wireless/rtl8192cu/os_dep/linux/os_intfs.c | 13 +++++++++++++
drivers/net/wireless/rtl8192cu/os_dep/linux/usb_intf.c | 1 +
5 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/rtl8192cu/Kconfig b/drivers/net/wireless/rtl8192cu/Kconfig
index bee5ed6..ef46361 100644
--- a/drivers/net/wireless/rtl8192cu/Kconfig
+++ b/drivers/net/wireless/rtl8192cu/Kconfig
@@ -1,6 +1,8 @@
config RTL8192CU
tristate "Realtek 8192C USB WiFi"
depends on USB
+ select WIRELESS_EXT
+ select WEXT_PRIV
---help---
- Help message of RTL8192CU
+ Enable wireless network adapters based on Realtek RTL8192C chipset family, such as EDUP nano series
diff --git a/drivers/net/wireless/rtl8192cu/Makefile b/drivers/net/wireless/rtl8192cu/Makefile
index c399011..f85c59f 100644
--- a/drivers/net/wireless/rtl8192cu/Makefile
+++ b/drivers/net/wireless/rtl8192cu/Makefile
@@ -38,7 +38,7 @@ CONFIG_RTL8192CU_REDEFINE_1X1 = n
CONFIG_INTEL_WIDI = n
CONFIG_WAKE_ON_WLAN = n
-CONFIG_PLATFORM_I386_PC = y
+CONFIG_PLATFORM_I386_PC = n
CONFIG_PLATFORM_TI_AM3517 = n
CONFIG_PLATFORM_ANDROID_X86 = n
CONFIG_PLATFORM_JB_X86 = n
@@ -524,6 +524,10 @@ KVER := 3.3.0
#KSRC:= ../lichee/linux-3.3/
endif
+ifeq ($(CONFIG_ARCH_BCM2708), y)
+EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
+endif
+
ifneq ($(USER_MODULE_NAME),)
MODULE_NAME := $(USER_MODULE_NAME)
endif
diff --git a/drivers/net/wireless/rtl8192cu/include/autoconf.h b/drivers/net/wireless/rtl8192cu/include/autoconf.h
index 12294df..1341ff0 100644
--- a/drivers/net/wireless/rtl8192cu/include/autoconf.h
+++ b/drivers/net/wireless/rtl8192cu/include/autoconf.h
@@ -296,7 +296,7 @@
//#define CONFIG_DEBUG_RTL871X
#define DBG 0
-#define CONFIG_DEBUG_RTL819X
+//#define CONFIG_DEBUG_RTL819X
#define CONFIG_PROC_DEBUG 1
diff --git a/drivers/net/wireless/rtl8192cu/os_dep/linux/os_intfs.c b/drivers/net/wireless/rtl8192cu/os_dep/linux/os_intfs.c
index 82dee6d..b0bf0e9 100644
--- a/drivers/net/wireless/rtl8192cu/os_dep/linux/os_intfs.c
+++ b/drivers/net/wireless/rtl8192cu/os_dep/linux/os_intfs.c
@@ -277,6 +277,18 @@ static int rtw_proc_cnt = 0;
#define RTW_PROC_NAME DRV_NAME
+#ifndef create_proc_entry
+/* dummy routines */
+void rtw_proc_remove_one(struct net_device *dev)
+{
+}
+
+void rtw_proc_init_one(struct net_device *dev)
+{
+}
+
+#else /* create_proc_entry not defined */
+
void rtw_proc_init_one(struct net_device *dev)
{
struct proc_dir_entry *dir_dev = NULL;
@@ -751,6 +763,7 @@ void rtw_proc_remove_one(struct net_device *dev)
}
}
}
+#endif /* create_proc_entry not defined */
#endif
uint loadparam( _adapter *padapter, _nic_hdl pnetdev);
diff --git a/drivers/net/wireless/rtl8192cu/os_dep/linux/usb_intf.c b/drivers/net/wireless/rtl8192cu/os_dep/linux/usb_intf.c
index 4c1089a..baccb59 100644
--- a/drivers/net/wireless/rtl8192cu/os_dep/linux/usb_intf.c
+++ b/drivers/net/wireless/rtl8192cu/os_dep/linux/usb_intf.c
@@ -138,6 +138,7 @@ static void rtw_dev_remove(struct usb_interface *pusb_intf);
{USB_DEVICE(0x2001, 0x3307)},/* D-Link - Cameo */ \
{USB_DEVICE(0x2001, 0x330A)},/* D-Link - Alpha */ \
{USB_DEVICE(0x2001, 0x3309)},/* D-Link - Alpha */ \
+ {USB_DEVICE(0x2001, 0x330D)},/* D-Link - Alpha(?) */ \
{USB_DEVICE(0x0586, 0x341F)},/* Zyxel - Abocom */ \
{USB_DEVICE(0x7392, 0x7822)},/* Edimax - Edimax */ \
{USB_DEVICE(0x2019, 0xAB2B)},/* Planex - Abocom */ \
--
1.9.1

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

@ -0,0 +1,214 @@
From baadd46e587d311e40cfdcec7bdf691c8cce7fa9 Mon Sep 17 00:00:00 2001
From: Harm Hanemaaijer <fgenfb@yahoo.com>
Date: Thu, 20 Jun 2013 20:21:39 +0200
Subject: [PATCH 24/54] 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/cfbimgblt.c | 152 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 147 insertions(+), 5 deletions(-)
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index a2bb276..436494f 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/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 struct fb_image *image, struct fb_info *
}
}
+/*
+ * 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, const struct fb_image *image)
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.9.1

@ -0,0 +1,98 @@
From d0f5437f8fcabde286fcb89427ef79b93dc4c50d 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 25/54] 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/fbmem.c | 30 ++++++++++++++++++++++++++++++
include/uapi/linux/fb.h | 5 +++++
2 files changed, 35 insertions(+)
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 7309ac7..46984cc 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1083,6 +1083,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)
{
@@ -1093,6 +1112,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
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;
@@ -1210,6 +1230,15 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
unlock_fb_info(info);
console_unlock();
break;
+ case FBIOCOPYAREA:
+ if (info->flags & FBINFO_HWACCEL_COPYAREA) {
+ /* only provide this ioctl if it is accelerated */
+ if (copy_from_user(&copy, argp, sizeof(copy)))
+ return -EFAULT;
+ ret = fb_copyarea_user(info, &copy);
+ break;
+ }
+ /* fall through */
default:
if (!lock_fb_info(info))
return -ENODEV;
@@ -1364,6 +1393,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd,
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);
diff --git a/include/uapi/linux/fb.h b/include/uapi/linux/fb.h
index fb795c3..fa72af0 100644
--- 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.9.1

@ -0,0 +1,460 @@
From c2731f282848af32425043a2df88c1289538983e Mon Sep 17 00:00:00 2001
From: Siarhei Siamashka <siarhei.siamashka@gmail.com>
Date: Mon, 17 Jun 2013 16:00:25 +0300
Subject: [PATCH 26/54] bcm2708_fb: DMA acceleration for fb_copyarea
Based on http://www.raspberrypi.org/phpBB3/viewtopic.php?p=62425#p62425
Also used Simon's dmaer_master module as a reference for tweaking DMA
settings for better performance.
For now busylooping only. IRQ support might be added later.
With non-overclocked Raspberry Pi, the performance is ~360 MB/s
for simple copy or ~260 MB/s for two-pass copy (used when dragging
windows to the right).
In the case of using DMA channel 0, the performance improves
to ~440 MB/s.
For comparison, VFP optimized CPU copy can only do ~114 MB/s in
the same conditions (hindered by reading uncached source buffer).
Signed-off-by: Siarhei Siamashka <siarhei.siamashka@gmail.com>
bcm2708_fb: report number of dma copies
Add a counter (exported via debugfs) reporting the
number of dma copies that the framebuffer driver
has done, in order to help evaluate different
optimization strategies.
Signed-off-by: Luke Diamand <luked@broadcom.com>
bcm2708_fb: use IRQ for DMA copies
The copyarea ioctl() uses DMA to speed things along. This
was busy-waiting for completion. This change supports using
an interrupt instead for larger transfers. For small
transfers, busy-waiting is still likely to be faster.
Signed-off-by: Luke Diamand <luke@diamand.org>
---
arch/arm/mach-bcm2708/dma.c | 8 +
arch/arm/mach-bcm2708/include/mach/dma.h | 2 +
drivers/video/bcm2708_fb.c | 273 ++++++++++++++++++++++++++++++-
3 files changed, 278 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-bcm2708/dma.c b/arch/arm/mach-bcm2708/dma.c
index 51d147a..1da2413 100644
--- a/arch/arm/mach-bcm2708/dma.c
+++ b/arch/arm/mach-bcm2708/dma.c
@@ -83,6 +83,14 @@ extern void bcm_dma_wait_idle(void __iomem *dma_chan_base)
EXPORT_SYMBOL_GPL(bcm_dma_start);
+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
diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h
index ac7a4a0..6d2f9a0 100644
--- a/arch/arm/mach-bcm2708/include/mach/dma.h
+++ b/arch/arm/mach-bcm2708/include/mach/dma.h
@@ -62,11 +62,13 @@ struct bcm2708_dma_cb {
unsigned long next;
unsigned long pad[2];
};
+struct scatterlist;
extern int bcm_sg_suitable_for_dma(struct scatterlist *sg_ptr, int sg_len);
extern void bcm_dma_start(void __iomem *dma_chan_base,
dma_addr_t control_block);
extern void bcm_dma_wait_idle(void __iomem *dma_chan_base);
+extern bool bcm_dma_is_busy(void __iomem *dma_chan_base);
extern int /*rc*/ bcm_dma_abort(void __iomem *dma_chan_base);
/* When listing features we can ask for when allocating DMA channels give
diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c
index 54cd760..798eb52 100644
--- a/drivers/video/bcm2708_fb.c
+++ b/drivers/video/bcm2708_fb.c
@@ -21,13 +21,16 @@
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/printk.h>
#include <linux/console.h>
+#include <linux/debugfs.h>
+#include <mach/dma.h>
#include <mach/platform.h>
#include <mach/vcio.h>
@@ -51,6 +54,10 @@ static int fbheight = 480; /* module parameter */
static int fbdepth = 16; /* module parameter */
static int fbswap = 0; /* module parameter */
+static u32 dma_busy_wait_threshold = 1<<15;
+module_param(dma_busy_wait_threshold, int, 0644);
+MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area");
+
/* this data structure describes each frame buffer device we find */
struct fbinfo_s {
@@ -62,16 +69,73 @@ struct fbinfo_s {
u16 cmap[256];
};
+struct bcm2708_fb_stats {
+ struct debugfs_regset32 regset;
+ u32 dma_copies;
+ u32 dma_irqs;
+};
+
struct bcm2708_fb {
struct fb_info fb;
struct platform_device *dev;
struct fbinfo_s *info;
dma_addr_t dma;
u32 cmap[16];
+ int dma_chan;
+ int dma_irq;
+ void __iomem *dma_chan_base;
+ void *cb_base; /* DMA control blocks */
+ dma_addr_t cb_handle;
+ struct dentry *debugfs_dir;
+ wait_queue_head_t dma_waitq;
+ struct bcm2708_fb_stats stats;
};
#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
+static void bcm2708_fb_debugfs_deinit(struct bcm2708_fb *fb)
+{
+ debugfs_remove_recursive(fb->debugfs_dir);
+ fb->debugfs_dir = NULL;
+}
+
+static int bcm2708_fb_debugfs_init(struct bcm2708_fb *fb)
+{
+ static struct debugfs_reg32 stats_registers[] = {
+ {
+ "dma_copies",
+ offsetof(struct bcm2708_fb_stats, dma_copies)
+ },
+ {
+ "dma_irqs",
+ offsetof(struct bcm2708_fb_stats, dma_irqs)
+ },
+ };
+
+ fb->debugfs_dir = debugfs_create_dir(DRIVER_NAME, NULL);
+ if (!fb->debugfs_dir) {
+ pr_warn("%s: could not create debugfs entry\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ fb->stats.regset.regs = stats_registers;
+ fb->stats.regset.nregs = ARRAY_SIZE(stats_registers);
+ fb->stats.regset.base = &fb->stats;
+
+ if (!debugfs_create_regset32(
+ "stats", 0444, fb->debugfs_dir, &fb->stats.regset)) {
+ pr_warn("%s: could not create statistics registers\n",
+ __func__);
+ goto fail;
+ }
+ return 0;
+
+fail:
+ bcm2708_fb_debugfs_deinit(fb);
+ return -EFAULT;
+}
+
static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var)
{
int ret = 0;
@@ -322,11 +386,148 @@ static void bcm2708_fb_fillrect(struct fb_info *info,
cfb_fillrect(info, rect);
}
+/* A helper function for configuring dma control block */
+static void set_dma_cb(struct bcm2708_dma_cb *cb,
+ int burst_size,
+ dma_addr_t dst,
+ int dst_stride,
+ dma_addr_t src,
+ int src_stride,
+ int w,
+ int h)
+{
+ cb->info = BCM2708_DMA_BURST(burst_size) | BCM2708_DMA_S_WIDTH |
+ BCM2708_DMA_S_INC | BCM2708_DMA_D_WIDTH |
+ BCM2708_DMA_D_INC | BCM2708_DMA_TDMODE;
+ cb->dst = dst;
+ cb->src = src;
+ /*
+ * This is not really obvious from the DMA documentation,
+ * but the top 16 bits must be programmmed to "height -1"
+ * and not "height" in 2D mode.
+ */
+ cb->length = ((h - 1) << 16) | w;
+ cb->stride = ((dst_stride - w) << 16) | (u16)(src_stride - w);
+ cb->pad[0] = 0;
+ cb->pad[1] = 0;
+}
+
static void bcm2708_fb_copyarea(struct fb_info *info,
const struct fb_copyarea *region)
{
- /*print_debug("bcm2708_fb_copyarea\n"); */
- cfb_copyarea(info, region);
+ struct bcm2708_fb *fb = to_bcm2708(info);
+ struct bcm2708_dma_cb *cb = fb->cb_base;
+ int bytes_per_pixel = (info->var.bits_per_pixel + 7) >> 3;
+ /* Channel 0 supports larger bursts and is a bit faster */
+ int burst_size = (fb->dma_chan == 0) ? 8 : 2;
+ int pixels = region->width * region->height;
+
+ /* Fallback to cfb_copyarea() if we don't like something */
+ if (bytes_per_pixel > 4 ||
+ info->var.xres * info->var.yres > 1920 * 1200 ||
+ region->width <= 0 || region->width > info->var.xres ||
+ region->height <= 0 || region->height > info->var.yres ||
+ region->sx < 0 || region->sx >= info->var.xres ||
+ region->sy < 0 || region->sy >= info->var.yres ||
+ region->dx < 0 || region->dx >= info->var.xres ||
+ region->dy < 0 || region->dy >= info->var.yres ||
+ region->sx + region->width > info->var.xres ||
+ region->dx + region->width > info->var.xres ||
+ region->sy + region->height > info->var.yres ||
+ region->dy + region->height > info->var.yres) {
+ cfb_copyarea(info, region);
+ return;
+ }
+
+ if (region->dy == region->sy && region->dx > region->sx) {
+ /*
+ * A difficult case of overlapped copy. Because DMA can't
+ * copy individual scanlines in backwards direction, we need
+ * two-pass processing. We do it by programming a chain of dma
+ * control blocks in the first 16K part of the buffer and use
+ * the remaining 48K as the intermediate temporary scratch
+ * buffer. The buffer size is sufficient to handle up to
+ * 1920x1200 resolution at 32bpp pixel depth.
+ */
+ int y;
+ dma_addr_t control_block_pa = fb->cb_handle;
+ dma_addr_t scratchbuf = fb->cb_handle + 16 * 1024;
+ int scanline_size = bytes_per_pixel * region->width;
+ int scanlines_per_cb = (64 * 1024 - 16 * 1024) / scanline_size;
+
+ for (y = 0; y < region->height; y += scanlines_per_cb) {
+ dma_addr_t src =
+ fb->fb.fix.smem_start +
+ bytes_per_pixel * region->sx +
+ (region->sy + y) * fb->fb.fix.line_length;
+ dma_addr_t dst =
+ fb->fb.fix.smem_start +
+ bytes_per_pixel * region->dx +
+ (region->dy + y) * fb->fb.fix.line_length;
+
+ if (region->height - y < scanlines_per_cb)
+ scanlines_per_cb = region->height - y;
+
+ set_dma_cb(cb, burst_size, scratchbuf, scanline_size,
+ src, fb->fb.fix.line_length,
+ scanline_size, scanlines_per_cb);
+ control_block_pa += sizeof(struct bcm2708_dma_cb);
+ cb->next = control_block_pa;
+ cb++;
+
+ set_dma_cb(cb, burst_size, dst, fb->fb.fix.line_length,
+ scratchbuf, scanline_size,
+ scanline_size, scanlines_per_cb);
+ control_block_pa += sizeof(struct bcm2708_dma_cb);
+ cb->next = control_block_pa;
+ cb++;
+ }
+ /* move the pointer back to the last dma control block */
+ cb--;
+ } else {
+ /* A single dma control block is enough. */
+ int sy, dy, stride;
+ if (region->dy <= region->sy) {
+ /* processing from top to bottom */
+ dy = region->dy;
+ sy = region->sy;
+ stride = fb->fb.fix.line_length;
+ } else {
+ /* processing from bottom to top */
+ dy = region->dy + region->height - 1;
+ sy = region->sy + region->height - 1;
+ stride = -fb->fb.fix.line_length;
+ }
+ set_dma_cb(cb, burst_size,
+ fb->fb.fix.smem_start + dy * fb->fb.fix.line_length +
+ bytes_per_pixel * region->dx,
+ stride,
+ fb->fb.fix.smem_start + sy * fb->fb.fix.line_length +
+ bytes_per_pixel * region->sx,
+ stride,
+ region->width * bytes_per_pixel,
+ region->height);
+ }
+
+ /* end of dma control blocks chain */
+ cb->next = 0;
+
+
+ if (pixels < dma_busy_wait_threshold) {
+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+ bcm_dma_wait_idle(fb->dma_chan_base);
+ } else {
+ void __iomem *dma_chan = fb->dma_chan_base;
+ cb->info |= BCM2708_DMA_INT_EN;
+ bcm_dma_start(fb->dma_chan_base, fb->cb_handle);
+ while (bcm_dma_is_busy(dma_chan)) {
+ wait_event_interruptible(
+ fb->dma_waitq,
+ !bcm_dma_is_busy(dma_chan));
+ }
+ fb->stats.dma_irqs++;
+ }
+ fb->stats.dma_copies++;
}
static void bcm2708_fb_imageblit(struct fb_info *info,
@@ -336,6 +537,24 @@ static void bcm2708_fb_imageblit(struct fb_info *info,
cfb_imageblit(info, image);
}
+static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt)
+{
+ struct bcm2708_fb *fb = cxt;
+
+ /* FIXME: should read status register to check if this is
+ * actually interrupting us or not, in case this interrupt
+ * ever becomes shared amongst several DMA channels
+ *
+ * readl(dma_chan_base + BCM2708_DMA_CS) & BCM2708_DMA_IRQ;
+ */
+
+ /* acknowledge the interrupt */
+ writel(BCM2708_DMA_INT, fb->dma_chan_base + BCM2708_DMA_CS);
+
+ wake_up(&fb->dma_waitq);
+ return IRQ_HANDLED;
+}
+
static struct fb_ops bcm2708_fb_ops = {
.owner = THIS_MODULE,
.fb_check_var = bcm2708_fb_check_var,
@@ -365,7 +584,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb)
fb->dma = dma;
}
fb->fb.fbops = &bcm2708_fb_ops;
- fb->fb.flags = FBINFO_FLAG_DEFAULT;
+ fb->fb.flags = FBINFO_FLAG_DEFAULT | FBINFO_HWACCEL_COPYAREA;
fb->fb.pseudo_palette = fb->cmap;
strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id));
@@ -396,6 +615,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb)
fb->fb.monspecs.dclkmax = 100000000;
bcm2708_fb_set_bitfields(&fb->fb.var);
+ init_waitqueue_head(&fb->dma_waitq);
/*
* Allocate colourmap.
@@ -421,14 +641,45 @@ static int bcm2708_fb_probe(struct platform_device *dev)
struct bcm2708_fb *fb;
int ret;
- fb = kmalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
+ fb = kzalloc(sizeof(struct bcm2708_fb), GFP_KERNEL);
if (!fb) {
dev_err(&dev->dev,
"could not allocate new bcm2708_fb struct\n");
ret = -ENOMEM;
goto free_region;
}
- memset(fb, 0, sizeof(struct bcm2708_fb));
+
+ bcm2708_fb_debugfs_init(fb);
+
+ fb->cb_base = dma_alloc_writecombine(&dev->dev, SZ_64K,
+ &fb->cb_handle, GFP_KERNEL);
+ if (!fb->cb_base) {
+ dev_err(&dev->dev, "cannot allocate DMA CBs\n");
+ ret = -ENOMEM;
+ goto free_fb;
+ }
+
+ pr_info("BCM2708FB: allocated DMA memory %08x\n",
+ fb->cb_handle);
+
+ ret = bcm_dma_chan_alloc(BCM_DMA_FEATURE_BULK,
+ &fb->dma_chan_base, &fb->dma_irq);
+ if (ret < 0) {
+ dev_err(&dev->dev, "couldn't allocate a DMA channel\n");
+ goto free_cb;
+ }
+ fb->dma_chan = ret;
+
+ ret = request_irq(fb->dma_irq, bcm2708_fb_dma_irq,
+ 0, "bcm2708_fb dma", fb);
+ if (ret) {
+ pr_err("%s: failed to request DMA irq\n", __func__);
+ goto free_dma_chan;
+ }
+
+
+ pr_info("BCM2708FB: allocated DMA channel %d @ %p\n",
+ fb->dma_chan, fb->dma_chan_base);
fb->dev = dev;
@@ -438,6 +689,11 @@ static int bcm2708_fb_probe(struct platform_device *dev)
goto out;
}
+free_dma_chan:
+ bcm_dma_chan_free(fb->dma_chan);
+free_cb:
+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
+free_fb:
kfree(fb);
free_region:
dev_err(&dev->dev, "probe failed, err %d\n", ret);
@@ -455,8 +711,15 @@ static int bcm2708_fb_remove(struct platform_device *dev)
iounmap(fb->fb.screen_base);
unregister_framebuffer(&fb->fb);
+ dma_free_writecombine(&dev->dev, SZ_64K, fb->cb_base, fb->cb_handle);
+ bcm_dma_chan_free(fb->dma_chan);
+
dma_free_coherent(NULL, PAGE_ALIGN(sizeof(*fb->info)), (void *)fb->info,
fb->dma);
+ bcm2708_fb_debugfs_deinit(fb);
+
+ free_irq(fb->dma_irq, fb);
+
kfree(fb);
return 0;
--
1.9.1

@ -0,0 +1,77 @@
From 6f2dc468edc31cf2c9b2098566cbbcc1e59b5ad5 Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 18 Dec 2013 22:16:19 +0000
Subject: [PATCH 27/54] config: Enable CONFIG_MEMCG, but leave it disabled (due
to memory cost). Enable with cgroup_enable=memory.
---
arch/arm/configs/bcmrpi_defconfig | 1 +
kernel/cgroup.c | 27 +++++++++++++++++++++++++++
mm/memcontrol.c | 1 +
3 files changed, 29 insertions(+)
diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
index 78d789c..e89e430 100644
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -18,6 +18,7 @@ CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_RESOURCE_COUNTERS=y
+CONFIG_MEMCG=y
CONFIG_BLK_CGROUP=y
CONFIG_NAMESPACES=y
CONFIG_SCHED_AUTOGROUP=y
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 0c753dd..a18b46e 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -5252,6 +5252,33 @@ static int __init cgroup_disable(char *str)
}
__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;
+
+ /*
+ * cgroup_disable, being at boot time, can't know about
+ * module subsystems, so we don't worry about them.
+ */
+ for_each_builtin_subsys(ss, i) {
+ if (!strcmp(token, ss->name)) {
+ ss->disabled = 0;
+ printk(KERN_INFO "Disabling %s control group"
+ " subsystem\n", ss->name);
+ break;
+ }
+ }
+ }
+ return 1;
+}
+__setup("cgroup_enable=", cgroup_enable);
+
/**
* css_from_dir - get corresponding css from the dentry of a cgroup dir
* @dentry: directory dentry of interest
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 9b35da2..a9891cc 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -7289,6 +7289,7 @@ struct cgroup_subsys mem_cgroup_subsys = {
.bind = mem_cgroup_bind,
.base_cftypes = mem_cgroup_files,
.early_init = 0,
+ .disabled = 1,
};
#ifdef CONFIG_MEMCG_SWAP
--
1.9.1

@ -0,0 +1,473 @@
From 2172c6578ef13acb8fcf5cac643cb1ee8e824117 Mon Sep 17 00:00:00 2001
From: Julian Scheel <julian@jusst.de>
Date: Wed, 19 Feb 2014 16:06:59 +0100
Subject: [PATCH 32/54] snd-bcm2835: Add support for spdif/hdmi passthrough
This adds a dedicated subdevice which can be used for passthrough of non-audio
formats (ie encoded a52) through the hdmi audio link. In addition to this
driver extension an appropriate card config is required to make alsa-lib
support the AES parameters for this device.
---
sound/arm/bcm2835-ctl.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++
sound/arm/bcm2835-pcm.c | 128 +++++++++++++++++++++++++++++++++++++++++-------
sound/arm/bcm2835.c | 9 +++-
sound/arm/bcm2835.h | 9 ++++
4 files changed, 250 insertions(+), 19 deletions(-)
diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c
index 8c5334a..aad905f 100755
--- a/sound/arm/bcm2835-ctl.c
+++ b/sound/arm/bcm2835-ctl.c
@@ -30,6 +30,7 @@
#include <sound/rawmidi.h>
#include <sound/initval.h>
#include <sound/tlv.h>
+#include <sound/asoundef.h>
#include "bcm2835.h"
@@ -183,6 +184,122 @@ static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
},
};
+static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) && 0xff;
+
+ return 0;
+}
+
+static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int val = 0;
+ int i, change;
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
+ return change;
+}
+
+static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* bcm2835 supports only consumer mode and sets all other format flags
+ * automatically. So the only thing left is signalling non-audio
+ * content */
+ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) & 0xff;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int val = 0;
+ int i, change;
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int)ucontrol->value.iec958.status[i] << (i * 8);
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
+ return change;
+}
+
+static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = snd_bcm2835_spdif_default_info,
+ .get = snd_bcm2835_spdif_default_get,
+ .put = snd_bcm2835_spdif_default_put
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+ .info = snd_bcm2835_spdif_mask_info,
+ .get = snd_bcm2835_spdif_mask_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+ .info = snd_bcm2835_spdif_stream_info,
+ .get = snd_bcm2835_spdif_stream_get,
+ .put = snd_bcm2835_spdif_stream_put,
+ },
+};
+
int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
{
int err;
@@ -196,5 +313,11 @@ int snd_bcm2835_new_ctl(bcm2835_chip_t * chip)
if (err < 0)
return err;
}
+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
+ if (err < 0)
+ return err;
+ }
return 0;
}
diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c
index b4084bb..ebd3f62 100755
--- a/sound/arm/bcm2835-pcm.c
+++ b/sound/arm/bcm2835-pcm.c
@@ -15,6 +15,8 @@
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <sound/asoundef.h>
+
#include "bcm2835.h"
/* hardware definition */
@@ -34,6 +36,23 @@ static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
.periods_max = 128,
};
+static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 1,
+ .periods_max = 128,
+};
+
static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
{
audio_info("Freeing up alsa stream here ..\n");
@@ -89,7 +108,8 @@ static irqreturn_t bcm2835_playback_fifo_irq(int irq, void *dev_id)
}
/* open callback */
-static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
+static int snd_bcm2835_playback_open_generic(
+ struct snd_pcm_substream *substream, int spdif)
{
bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
@@ -102,6 +122,11 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
audio_info("Alsa open (%d)\n", substream->number);
idx = substream->number;
+ if (spdif && chip->opened != 0)
+ return -EBUSY;
+ else if (!spdif && (chip->opened & (1 << idx)))
+ return -EBUSY;
+
if (idx > MAX_SUBSTREAMS) {
audio_error
("substream(%d) device doesn't exist max(%d) substreams allowed\n",
@@ -143,13 +168,20 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
}
runtime->private_data = alsa_stream;
runtime->private_free = snd_bcm2835_playback_free;
- runtime->hw = snd_bcm2835_playback_hw;
+ if (spdif) {
+ runtime->hw = snd_bcm2835_playback_spdif_hw;
+ } else {
+ /* clear spdif status, as we are not in spdif mode */
+ chip->spdif_status = 0;
+ runtime->hw = snd_bcm2835_playback_hw;
+ }
/* minimum 16 bytes alignment (for vchiq bulk transfers) */
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
16);
chip->alsa_stream[idx] = alsa_stream;
+ chip->opened |= (1 << idx);
alsa_stream->open = 1;
alsa_stream->draining = 1;
@@ -159,6 +191,16 @@ out:
return err;
}
+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
+{
+ return snd_bcm2835_playback_open_generic(substream, 0);
+}
+
+static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
+{
+ return snd_bcm2835_playback_open_generic(substream, 1);
+}
+
/* close callback */
static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
{
@@ -166,6 +208,7 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
audio_info(" .. IN\n");
audio_info("Alsa close\n");
@@ -196,6 +239,8 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
* runtime->private_free callback we registered in *_open above
*/
+ chip->opened &= ~(1 << substream->number);
+
audio_info(" .. OUT\n");
return 0;
@@ -205,10 +250,9 @@ static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
- int err;
struct snd_pcm_runtime *runtime = substream->runtime;
- bcm2835_alsa_stream_t *alsa_stream =
- (bcm2835_alsa_stream_t *) runtime->private_data;
+ bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+ int err;
audio_info(" .. IN\n");
@@ -219,19 +263,9 @@ static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
return err;
}
- err = bcm2835_audio_set_params(alsa_stream, params_channels(params),
- params_rate(params),
- snd_pcm_format_width(params_format
- (params)));
- if (err < 0) {
- audio_error(" error setting hw params\n");
- }
-
- bcm2835_audio_setup(alsa_stream);
-
- /* in preparation of the stream, set the controls (volume level) of the stream */
- bcm2835_audio_set_ctls(alsa_stream->chip);
-
+ alsa_stream->channels = params_channels(params);
+ alsa_stream->params_rate = params_rate(params);
+ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format (params));
audio_info(" .. OUT\n");
return err;
@@ -247,11 +281,35 @@ static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
/* prepare callback */
static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
{
+ bcm2835_chip_t *chip = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
bcm2835_alsa_stream_t *alsa_stream = runtime->private_data;
+ int channels;
+ int err;
audio_info(" .. IN\n");
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+ * https://github.com/raspberrypi/linux/issues/528) */
+ if (chip->spdif_status & IEC958_AES0_NONAUDIO)
+ channels = 0;
+ else
+ channels = alsa_stream->channels;
+
+ err = bcm2835_audio_set_params(alsa_stream, channels,
+ alsa_stream->params_rate,
+ alsa_stream->pcm_format_width);
+ if (err < 0) {
+ audio_error(" error setting hw params\n");
+ }
+
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+ bcm2835_audio_set_ctls(alsa_stream->chip);
+
+
memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
alsa_stream->pcm_indirect.hw_buffer_size =
@@ -392,6 +450,18 @@ static struct snd_pcm_ops snd_bcm2835_playback_ops = {
.ack = snd_bcm2835_pcm_ack,
};
+static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
+ .open = snd_bcm2835_playback_spdif_open,
+ .close = snd_bcm2835_playback_close,
+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
+ .hw_params = snd_bcm2835_pcm_hw_params,
+ .hw_free = snd_bcm2835_pcm_hw_free,
+ .prepare = snd_bcm2835_pcm_prepare,
+ .trigger = snd_bcm2835_pcm_trigger,
+ .pointer = snd_bcm2835_pcm_pointer,
+ .ack = snd_bcm2835_pcm_ack,
+};
+
/* create a pcm device */
int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
{
@@ -424,3 +494,25 @@ int snd_bcm2835_new_pcm(bcm2835_chip_t * chip)
return 0;
}
+
+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
+ if (err < 0)
+ return err;
+
+ pcm->private_data = chip;
+ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
+ chip->pcm_spdif = pcm;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_bcm2835_playback_spdif_ops);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data (GFP_KERNEL),
+ 64 * 1024, 64 * 1024);
+
+ return 0;
+}
diff --git a/sound/arm/bcm2835.c b/sound/arm/bcm2835.c
index e2047a7..4136760 100755
--- a/sound/arm/bcm2835.c
+++ b/sound/arm/bcm2835.c
@@ -104,7 +104,7 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
goto out;
snd_card_set_dev(g_card, &pdev->dev);
- strcpy(g_card->driver, "BRCM bcm2835 ALSA Driver");
+ strcpy(g_card->driver, "bcm2835");
strcpy(g_card->shortname, "bcm2835 ALSA");
sprintf(g_card->longname, "%s", g_card->shortname);
@@ -121,6 +121,12 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev)
goto out_bcm2835_new_pcm;
}
+ err = snd_bcm2835_new_spdif_pcm(chip);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Failed to create new BCM2835 spdif pcm device\n");
+ goto out_bcm2835_new_spdif;
+ }
+
err = snd_bcm2835_new_ctl(chip);
if (err < 0) {
dev_err(&pdev->dev, "Failed to create new BCM2835 ctl\n");
@@ -156,6 +162,7 @@ add_register_map:
out_card_register:
out_bcm2835_new_ctl:
+out_bcm2835_new_spdif:
out_bcm2835_new_pcm:
out_bcm2835_create:
BUG_ON(!g_card);
diff --git a/sound/arm/bcm2835.h b/sound/arm/bcm2835.h
index 36afee3..8c2fe26 100755
--- a/sound/arm/bcm2835.h
+++ b/sound/arm/bcm2835.h
@@ -97,6 +97,7 @@ typedef enum {
typedef struct bcm2835_chip {
struct snd_card *card;
struct snd_pcm *pcm;
+ struct snd_pcm *pcm_spdif;
/* Bitmat for valid reg_base and irq numbers */
uint32_t avail_substreams;
struct platform_device *pdev[MAX_SUBSTREAMS];
@@ -106,6 +107,9 @@ typedef struct bcm2835_chip {
int old_volume; /* stores the volume value whist muted */
int dest;
int mute;
+
+ unsigned int opened;
+ unsigned int spdif_status;
} bcm2835_chip_t;
typedef struct bcm2835_alsa_stream {
@@ -123,6 +127,10 @@ typedef struct bcm2835_alsa_stream {
int running;
int draining;
+ int channels;
+ int params_rate;
+ int pcm_format_width;
+
unsigned int pos;
unsigned int buffer_size;
unsigned int period_size;
@@ -138,6 +146,7 @@ typedef struct bcm2835_alsa_stream {
int snd_bcm2835_new_ctl(bcm2835_chip_t * chip);
int snd_bcm2835_new_pcm(bcm2835_chip_t * chip);
+int snd_bcm2835_new_spdif_pcm(bcm2835_chip_t * chip);
int bcm2835_audio_open(bcm2835_alsa_stream_t * alsa_stream);
int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream);
--
1.9.1

@ -0,0 +1,642 @@
From 568b7292b8e7e1fe3d852db8b463d989d06b5adf 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 33/54] dmaengine: Add support for BCM2708
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>
---
drivers/dma/Kconfig | 6 +
drivers/dma/Makefile | 1 +
drivers/dma/bcm2708-dmaengine.c | 588 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 595 insertions(+)
create mode 100644 drivers/dma/bcm2708-dmaengine.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 605b016..edd5842 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -312,6 +312,12 @@ config DMA_BCM2835
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
+config DMA_BCM2708
+ tristate "BCM2708 DMA engine support"
+ depends on MACH_BCM2708
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+
config TI_CPPI41
tristate "AM33xx CPPI41 DMA support"
depends on ARCH_OMAP
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index a029d0f4..f4d9516 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
obj-$(CONFIG_DMA_OMAP) += omap-dma.o
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
+obj-$(CONFIG_DMA_BCM2708) += bcm2708-dmaengine.o
obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_TI_CPPI41) += cppi41.o
diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c
new file mode 100644
index 0000000..b244293
--- /dev/null
+++ b/drivers/dma/bcm2708-dmaengine.c
@@ -0,0 +1,588 @@
+/*
+ * BCM2708 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
+ *
+ * Based on
+ * OMAP DMAengine support by Russell King
+ *
+ * BCM2708 DMA Driver
+ * Copyright (C) 2010 Broadcom
+ *
+ * Raspberry Pi PCM I2S ALSA Driver
+ * Copyright (c) by Phil Poole 2013
+ *
+ * MARVELL MMP Peripheral DMA Driver
+ * Copyright 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+
+#include "virt-dma.h"
+
+#include <mach/dma.h>
+#include <mach/irqs.h>
+
+struct bcm2708_dmadev {
+ struct dma_device ddev;
+ spinlock_t lock;
+ void __iomem *base;
+ struct device_dma_parameters dma_parms;
+};
+
+struct bcm2708_chan {
+ struct virt_dma_chan vc;
+ struct list_head node;
+
+ struct dma_slave_config cfg;
+ bool cyclic;
+
+ int ch;
+ struct bcm2708_desc *desc;
+
+ void __iomem *chan_base;
+ int irq_number;
+};
+
+struct bcm2708_desc {
+ struct virt_dma_desc vd;
+ enum dma_transfer_direction dir;
+
+ unsigned int control_block_size;
+ struct bcm2708_dma_cb *control_block_base;
+ dma_addr_t control_block_base_phys;
+
+ unsigned frames;
+ size_t size;
+};
+
+#define BCM2708_DMA_DATA_TYPE_S8 1
+#define BCM2708_DMA_DATA_TYPE_S16 2
+#define BCM2708_DMA_DATA_TYPE_S32 4
+#define BCM2708_DMA_DATA_TYPE_S128 16
+
+static inline struct bcm2708_dmadev *to_bcm2708_dma_dev(struct dma_device *d)
+{
+ return container_of(d, struct bcm2708_dmadev, ddev);
+}
+
+static inline struct bcm2708_chan *to_bcm2708_dma_chan(struct dma_chan *c)
+{
+ return container_of(c, struct bcm2708_chan, vc.chan);
+}
+
+static inline struct bcm2708_desc *to_bcm2708_dma_desc(
+ struct dma_async_tx_descriptor *t)
+{
+ return container_of(t, struct bcm2708_desc, vd.tx);
+}
+
+static void bcm2708_dma_desc_free(struct virt_dma_desc *vd)
+{
+ struct bcm2708_desc *desc = container_of(vd, struct bcm2708_desc, vd);
+ dma_free_coherent(desc->vd.tx.chan->device->dev,
+ desc->control_block_size,
+ desc->control_block_base,
+ desc->control_block_base_phys);
+ kfree(desc);
+}
+
+static void bcm2708_dma_start_desc(struct bcm2708_chan *c)
+{
+ struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+ struct bcm2708_desc *d;
+
+ if (!vd) {
+ c->desc = NULL;
+ return;
+ }
+
+ list_del(&vd->node);
+
+ c->desc = d = to_bcm2708_dma_desc(&vd->tx);
+
+ bcm_dma_start(c->chan_base, d->control_block_base_phys);
+}
+
+static irqreturn_t bcm2708_dma_callback(int irq, void *data)
+{
+ struct bcm2708_chan *c = data;
+ struct bcm2708_desc *d;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ /* Acknowledge interrupt */
+ writel(BCM2708_DMA_INT, c->chan_base + BCM2708_DMA_CS);
+
+ d = c->desc;
+
+ if (d) {
+ /* TODO Only works for cyclic DMA */
+ vchan_cyclic_callback(&d->vd);
+ }
+
+ /* Keep the DMA engine running */
+ dsb(); /* ARM synchronization barrier */
+ writel(BCM2708_DMA_ACTIVE, c->chan_base + BCM2708_DMA_CS);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm2708_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct bcm2708_chan *c = to_bcm2708_dma_chan(chan);
+
+ return request_irq(c->irq_number,
+ bcm2708_dma_callback, 0, "DMA IRQ", c);
+}
+
+static void bcm2708_dma_free_chan_resources(struct dma_chan *chan)
+{
+ struct bcm2708_chan *c = to_bcm2708_dma_chan(chan);
+
+ vchan_free_chan_resources(&c->vc);
+ free_irq(c->irq_number, c);
+
+ dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->ch);
+}
+
+static size_t bcm2708_dma_desc_size(struct bcm2708_desc *d)
+{
+ return d->size;
+}
+
+static size_t bcm2708_dma_desc_size_pos(struct bcm2708_desc *d, dma_addr_t addr)
+{
+ unsigned i;
+ size_t size;
+
+ for (size = i = 0; i < d->frames; i++) {
+ struct bcm2708_dma_cb *control_block =
+ &d->control_block_base[i];
+ size_t this_size = control_block->length;
+ dma_addr_t dma;
+
+ if (d->dir == DMA_DEV_TO_MEM)
+ dma = control_block->dst;
+ else
+ dma = control_block->src;
+
+ if (size)
+ size += this_size;
+ else if (addr >= dma && addr < dma + this_size)
+ size += dma + this_size - addr;
+ }
+
+ return size;
+}
+
+static enum dma_status bcm2708_dma_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct bcm2708_chan *c = to_bcm2708_dma_chan(chan);
+ struct virt_dma_desc *vd;
+ enum dma_status ret;
+ unsigned long flags;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE || !txstate)
+ return ret;
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vd = vchan_find_desc(&c->vc, cookie);
+ if (vd) {
+ txstate->residue =
+ bcm2708_dma_desc_size(to_bcm2708_dma_desc(&vd->tx));
+ } else if (c->desc && c->desc->vd.tx.cookie == cookie) {
+ struct bcm2708_desc *d = c->desc;
+ dma_addr_t pos;
+
+ if (d->dir == DMA_MEM_TO_DEV)
+ pos = readl(c->chan_base + BCM2708_DMA_SOURCE_AD);
+ else if (d->dir == DMA_DEV_TO_MEM)
+ pos = readl(c->chan_base + BCM2708_DMA_DEST_AD);
+ else
+ pos = 0;
+
+ txstate->residue = bcm2708_dma_desc_size_pos(d, pos);
+ } else {
+ txstate->residue = 0;
+ }
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
+ return ret;
+}
+
+static void bcm2708_dma_issue_pending(struct dma_chan *chan)
+{
+ struct bcm2708_chan *c = to_bcm2708_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)
+ bcm2708_dma_start_desc(c);
+
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static struct dma_async_tx_descriptor *bcm2708_dma_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction direction,
+ unsigned long flags, void *context)
+{
+ struct bcm2708_chan *c = to_bcm2708_dma_chan(chan);
+ enum dma_slave_buswidth dev_width;
+ struct bcm2708_desc *d;
+ dma_addr_t dev_addr;
+ unsigned es, sync_type;
+ unsigned frame;
+
+ /* Grab configuration */
+ if (direction == DMA_DEV_TO_MEM) {
+ dev_addr = c->cfg.src_addr;
+ dev_width = c->cfg.src_addr_width;
+ sync_type = BCM2708_DMA_S_DREQ;
+ } else if (direction == DMA_MEM_TO_DEV) {
+ dev_addr = c->cfg.dst_addr;
+ dev_width = c->cfg.dst_addr_width;
+ sync_type = BCM2708_DMA_D_DREQ;
+ } else {
+ dev_err(chan->device->dev, "%s: bad direction?\n", __func__);
+ return NULL;
+ }
+
+ /* Bus width translates to the element size (ES) */
+ switch (dev_width) {
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ es = BCM2708_DMA_DATA_TYPE_S32;
+ break;
+ default:
+ return NULL;
+ }
+
+ /* Now allocate and setup the descriptor. */
+ d = kzalloc(sizeof(*d), GFP_NOWAIT);
+ if (!d)
+ return NULL;
+
+ d->dir = direction;
+ d->frames = buf_len / period_len;
+
+ /* Allocate memory for control blocks */
+ d->control_block_size = d->frames * sizeof(struct bcm2708_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 frames, create a control block
+ * for each frame and link them together.
+ */
+ for (frame = 0; frame < d->frames; frame++) {
+ struct bcm2708_dma_cb *control_block =
+ &d->control_block_base[frame];
+
+ /* Setup adresses */
+ if (d->dir == DMA_DEV_TO_MEM) {
+ control_block->info = BCM2708_DMA_D_INC;
+ control_block->src = dev_addr;
+ control_block->dst = buf_addr + frame * period_len;
+ } else {
+ control_block->info = BCM2708_DMA_S_INC;
+ control_block->src = buf_addr + frame * period_len;
+ control_block->dst = dev_addr;
+ }
+
+ /* Enable interrupt */
+ control_block->info |= BCM2708_DMA_INT_EN;
+
+ /* Setup synchronization */
+ if (sync_type != 0)
+ control_block->info |= sync_type;
+
+ /* Setup DREQ channel */
+ if (c->cfg.slave_id != 0)
+ control_block->info |=
+ BCM2708_DMA_PER_MAP(c->cfg.slave_id);
+
+ /* Length of a frame */
+ control_block->length = period_len;
+ d->size += control_block->length;
+
+ /*
+ * Next block is the next frame.
+ * This DMA engine driver currently only supports cyclic DMA.
+ * Therefore, wrap around at number of frames.
+ */
+ control_block->next = d->control_block_base_phys +
+ sizeof(struct bcm2708_dma_cb)
+ * ((frame + 1) % d->frames);
+ }
+
+ return vchan_tx_prep(&c->vc, &d->vd, flags);
+}
+
+static int bcm2708_dma_slave_config(struct bcm2708_chan *c,
+ struct dma_slave_config *cfg)
+{
+ if ((cfg->direction == DMA_DEV_TO_MEM &&
+ cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+ (cfg->direction == DMA_MEM_TO_DEV &&
+ cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+ !is_slave_direction(cfg->direction)) {
+ return -EINVAL;
+ }
+
+ c->cfg = *cfg;
+
+ return 0;
+}
+
+static int bcm2708_dma_terminate_all(struct bcm2708_chan *c)
+{
+ struct bcm2708_dmadev *d = to_bcm2708_dma_dev(c->vc.chan.device);
+ unsigned long flags;
+ int timeout = 10000;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&c->vc.lock, flags);
+
+ /* Prevent this channel being scheduled */
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
+
+ /*
+ * Stop DMA activity: we assume the callback will not be called
+ * after bcm_dma_abort() returns (even if it does, it will see
+ * c->desc is NULL and exit.)
+ */
+ if (c->desc) {
+ c->desc = NULL;
+ bcm_dma_abort(c->chan_base);
+
+ /* Wait for stopping */
+ while (timeout > 0) {
+ timeout--;
+ if (!(readl(c->chan_base + BCM2708_DMA_CS) &
+ BCM2708_DMA_ACTIVE))
+ break;
+
+ cpu_relax();
+ }
+
+ if (timeout <= 0)
+ dev_err(d->ddev.dev, "DMA transfer could not be terminated\n");
+ }
+
+ vchan_get_all_descriptors(&c->vc, &head);
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ vchan_dma_desc_free_list(&c->vc, &head);
+
+ return 0;
+}
+
+static int bcm2708_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+ unsigned long arg)
+{
+ struct bcm2708_chan *c = to_bcm2708_dma_chan(chan);
+
+ switch (cmd) {
+ case DMA_SLAVE_CONFIG:
+ return bcm2708_dma_slave_config(c,
+ (struct dma_slave_config *)arg);
+
+ case DMA_TERMINATE_ALL:
+ return bcm2708_dma_terminate_all(c);
+
+ default:
+ return -ENXIO;
+ }
+}
+
+static int bcm2708_dma_chan_init(struct bcm2708_dmadev *d, void __iomem* chan_base,
+ int chan_id, int irq)
+{
+ struct bcm2708_chan *c;
+
+ c = devm_kzalloc(d->ddev.dev, sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
+
+ c->vc.desc_free = bcm2708_dma_desc_free;
+ vchan_init(&c->vc, &d->ddev);
+ INIT_LIST_HEAD(&c->node);
+
+ d->ddev.chancnt++;
+
+ c->chan_base = chan_base;
+ c->ch = chan_id;
+ c->irq_number = irq;
+
+ return 0;
+}
+
+static void bcm2708_dma_free(struct bcm2708_dmadev *od)
+{
+ while (!list_empty(&od->ddev.channels)) {
+ struct bcm2708_chan *c = list_first_entry(&od->ddev.channels,
+ struct bcm2708_chan, vc.chan.device_node);
+
+ list_del(&c->vc.chan.device_node);
+ tasklet_kill(&c->vc.task);
+ }
+}
+
+static int bcm2708_dma_probe(struct platform_device *pdev)
+{
+ struct bcm2708_dmadev *od;
+ int rc, i;
+
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)
+ return rc;
+ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+
+ od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
+ if (!od)
+ return -ENOMEM;
+
+ pdev->dev.dma_parms = &od->dma_parms;
+ dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
+
+ dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
+ dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
+ od->ddev.device_alloc_chan_resources = bcm2708_dma_alloc_chan_resources;
+ od->ddev.device_free_chan_resources = bcm2708_dma_free_chan_resources;
+ od->ddev.device_tx_status = bcm2708_dma_tx_status;
+ od->ddev.device_issue_pending = bcm2708_dma_issue_pending;
+ od->ddev.device_prep_dma_cyclic = bcm2708_dma_prep_dma_cyclic;
+ od->ddev.device_control = bcm2708_dma_control;
+ od->ddev.dev = &pdev->dev;
+ INIT_LIST_HEAD(&od->ddev.channels);
+ spin_lock_init(&od->lock);
+
+ platform_set_drvdata(pdev, od);
+
+ for (i = 0; i < 16; i++) {
+ void __iomem* chan_base;
+ int chan_id, irq;
+
+ chan_id = bcm_dma_chan_alloc(BCM_DMA_FEATURE_FAST,
+ &chan_base,
+ &irq);
+
+ if (chan_id < 0)
+ break;
+
+ rc = bcm2708_dma_chan_init(od, chan_base, chan_id, irq);
+ if (rc) {
+ bcm2708_dma_free(od);
+ return rc;
+ }
+ }
+
+ rc = dma_async_device_register(&od->ddev);
+ if (rc) {
+ dev_err(&pdev->dev,
+ "Failed to register slave DMA engine device: %d\n", rc);
+ bcm2708_dma_free(od);
+ return rc;
+ }
+
+ dev_dbg(&pdev->dev, "Load BCM2708 DMA engine driver\n");
+
+ return rc;
+}
+
+static int bcm2708_dma_remove(struct platform_device *pdev)
+{
+ struct bcm2708_dmadev *od = platform_get_drvdata(pdev);
+
+ dma_async_device_unregister(&od->ddev);
+ bcm2708_dma_free(od);
+
+ return 0;
+}
+
+static struct platform_driver bcm2708_dma_driver = {
+ .probe = bcm2708_dma_probe,
+ .remove = bcm2708_dma_remove,
+ .driver = {
+ .name = "bcm2708-dmaengine",
+ .owner = THIS_MODULE,
+ },
+};
+
+static struct platform_device *pdev;
+
+static const struct platform_device_info bcm2708_dma_dev_info = {
+ .name = "bcm2708-dmaengine",
+ .id = -1,
+};
+
+static int bcm2708_dma_init(void)
+{
+ int rc = platform_driver_register(&bcm2708_dma_driver);
+
+ if (rc == 0) {
+ pdev = platform_device_register_full(&bcm2708_dma_dev_info);
+ if (IS_ERR(pdev)) {
+ platform_driver_unregister(&bcm2708_dma_driver);
+ rc = PTR_ERR(pdev);
+ }
+ }
+
+ return rc;
+}
+subsys_initcall(bcm2708_dma_init);
+
+static void __exit bcm2708_dma_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&bcm2708_dma_driver);
+}
+module_exit(bcm2708_dma_exit);
+
+MODULE_ALIAS("platform:bcm2708-dma");
+MODULE_DESCRIPTION("BCM2708 DMA engine driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
--
1.9.1

@ -0,0 +1,47 @@
From 824d59b5066dff20761ecedebd4fbce27f301c70 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 14:37:51 +0100
Subject: [PATCH 35/54] BCM2708: Extend mach header
Extend the headers of the mach-bcm2708
in order to support I2S and DMA engine.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/mach-bcm2708/include/mach/dma.h | 2 ++
arch/arm/mach-bcm2708/include/mach/platform.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h
index 6d2f9a0..a4aac4c 100644
--- a/arch/arm/mach-bcm2708/include/mach/dma.h
+++ b/arch/arm/mach-bcm2708/include/mach/dma.h
@@ -45,6 +45,8 @@
#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
diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h
index 992a630..2e7e1bb 100644
--- a/arch/arm/mach-bcm2708/include/mach/platform.h
+++ b/arch/arm/mach-bcm2708/include/mach/platform.h
@@ -62,10 +62,12 @@
#define DMA_BASE (BCM2708_PERI_BASE + 0x7000) /* DMA controller */
#define ARM_BASE (BCM2708_PERI_BASE + 0xB000) /* BCM2708 ARM control block */
#define PM_BASE (BCM2708_PERI_BASE + 0x100000) /* Power Management, Reset controller and Watchdog registers */
+#define PCM_CLOCK_BASE (BCM2708_PERI_BASE + 0x101098) /* PCM Clock */
#define RNG_BASE (BCM2708_PERI_BASE + 0x104000) /* Hardware RNG */
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO */
#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
#define MMCI0_BASE (BCM2708_PERI_BASE + 0x202000) /* MMC interface */
+#define I2S_BASE (BCM2708_PERI_BASE + 0x203000) /* I2S */
#define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 */
#define BSC0_BASE (BCM2708_PERI_BASE + 0x205000) /* BSC0 I2C/TWI */
#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
--
1.9.1

@ -0,0 +1,130 @@
From c2155e69578ea9f02c915960599bb5216ce860c1 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 36/54] ASoC: Add support for PCM5102A codec
Some definitions to support the PCM5102A codec
by Texas Instruments.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
sound/soc/codecs/Kconfig | 4 +++
sound/soc/codecs/Makefile | 2 ++
sound/soc/codecs/pcm5102a.c | 63 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 69 insertions(+)
create mode 100644 sound/soc/codecs/pcm5102a.c
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 983d087a..f0d76ec 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM3008
+ select SND_SOC_PCM5102A
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
select SND_SOC_SGTL5000 if I2C
@@ -313,6 +314,9 @@ config SND_SOC_PCM1792A
config SND_SOC_PCM3008
tristate
+config SND_SOC_PCM5102A
+ tristate
+
config SND_SOC_RT5631
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index bc12676..612f414 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -46,6 +46,7 @@ snd-soc-hdmi-codec-objs := hdmi.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm1792a-codec-objs := pcm1792a.o
snd-soc-pcm3008-objs := pcm3008.o
+snd-soc-pcm5102a-objs := pcm5102a.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-rt5640-objs := rt5640.o
snd-soc-sgtl5000-objs := sgtl5000.o
@@ -179,6 +180,7 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.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_SGTL5000) += snd-soc-sgtl5000.o
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
new file mode 100644
index 0000000..126f1e9
--- /dev/null
+++ b/sound/soc/codecs/pcm5102a.c
@@ -0,0 +1,63 @@
+/*
+ * Driver for the PCM5102A codec
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver pcm5102a_dai = {
+ .name = "pcm5102a-hifi",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm5102a;
+
+static int pcm5102a_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm5102a,
+ &pcm5102a_dai, 1);
+}
+
+static int pcm5102a_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pcm5102a_codec_driver = {
+ .probe = pcm5102a_probe,
+ .remove = pcm5102a_remove,
+ .driver = {
+ .name = "pcm5102a-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pcm5102a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM5102A codec driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
--
1.9.1

@ -0,0 +1,60 @@
From 575806f9f3c40e16ac377c9d7d076fb87773968a Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 22 Nov 2013 19:04:54 +0100
Subject: [PATCH 37/54] BCM2708: Add I2S support to board file
Adds the required initializations for I2S
to the board file of mach-bcm2708.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/mach-bcm2708/bcm2708.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 89d0824..07da1fd 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -615,6 +615,28 @@ static struct platform_device bcm2835_thermal_device = {
.name = "bcm2835_thermal",
};
+#ifdef CONFIG_SND_BCM2708_SOC_I2S_MODULE
+static struct resource bcm2708_i2s_resources[] = {
+ {
+ .start = I2S_BASE,
+ .end = I2S_BASE + 0x20,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = PCM_CLOCK_BASE,
+ .end = PCM_CLOCK_BASE + 0x02,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device bcm2708_i2s_device = {
+ .name = "bcm2708-i2s",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bcm2708_i2s_resources),
+ .resource = bcm2708_i2s_resources,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -738,6 +760,10 @@ void __init bcm2708_init(void)
bcm_register_device(&bcm2835_hwmon_device);
bcm_register_device(&bcm2835_thermal_device);
+#ifdef CONFIG_SND_BCM2708_SOC_I2S_MODULE
+ bcm_register_device(&bcm2708_i2s_device);
+#endif
+
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
--
1.9.1

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

@ -0,0 +1,53 @@
From c5749de8927e1b64eaf5e6c7401a24d1ee0fdc68 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 39/54] BCM2708: Add HifiBerry DAC to board file
This adds the initalization of the HifiBerry DAC
to the mach-bcm2708 board file.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/mach-bcm2708/bcm2708.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 07da1fd..82b09a5 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -637,6 +637,20 @@ static struct platform_device bcm2708_i2s_device = {
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+static struct platform_device snd_hifiberry_dac_device = {
+ .name = "snd-hifiberry-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm5102a_codec_device = {
+ .name = "pcm5102a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -764,6 +778,11 @@ void __init bcm2708_init(void)
bcm_register_device(&bcm2708_i2s_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) || defined(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC_MODULE)
+ bcm_register_device(&snd_hifiberry_dac_device);
+ bcm_register_device(&snd_pcm5102a_codec_device);
+#endif
+
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
--
1.9.1

@ -0,0 +1,77 @@
From 5b06b2affe65b243dd828aeac9f48854902b1823 Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 6 Dec 2013 18:55:53 +0100
Subject: [PATCH 40/54] 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>
---
sound/soc/bcm/bcm2708-i2s.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c
index ebaf3d6..a179216 100644
--- a/sound/soc/bcm/bcm2708-i2s.c
+++ b/sound/soc/bcm/bcm2708-i2s.c
@@ -346,6 +346,10 @@ static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream,
data_length = 16;
bclk_ratio = 40;
break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ data_length = 24;
+ bclk_ratio = 40;
+ break;
case SNDRV_PCM_FORMAT_S32_LE:
data_length = 32;
bclk_ratio = 80;
@@ -424,7 +428,7 @@ static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream,
/* Setup the frame format */
format = BCM2708_I2S_CHEN;
- if (data_length > 24)
+ if (data_length >= 24)
format |= BCM2708_I2S_CHWEX;
format |= BCM2708_I2S_CHWID((data_length-8)&0xf);
@@ -714,6 +718,7 @@ static struct snd_soc_dai_driver bcm2708_i2s_dai = {
.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 = {
@@ -721,6 +726,7 @@ static struct snd_soc_dai_driver bcm2708_i2s_dai = {
.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 = &bcm2708_i2s_dai_ops,
@@ -810,11 +816,10 @@ static void bcm2708_i2s_setup_gpio(void)
}
static const struct snd_pcm_hardware bcm2708_pcm_hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_INTERLEAVED |
+ .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,
--
1.9.1

@ -0,0 +1,45 @@
From 8dd97bbaf4bd92b07bc942e4012b68f64b8a5ebc Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Mon, 2 Dec 2013 20:28:22 +0100
Subject: [PATCH 41/54] BCM2708: Add I2S and DMA support to default config
This commit adds several modules that are needed for
I2S support for the Raspberry Pi to the defconfig.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/configs/bcmrpi_defconfig | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
index d70da44..36e7473 100644
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -739,6 +739,13 @@ CONFIG_SND_USB_UA101=m
CONFIG_SND_USB_CAIAQ=m
CONFIG_SND_USB_CAIAQ_INPUT=y
CONFIG_SND_USB_6FIRE=m
+CONFIG_SND_SOC=m
+CONFIG_SND_SOC_DMAENGINE_PCM=y
+CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+CONFIG_SND_BCM2708_SOC_I2S=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_SOC_I2C_AND_SPI=m
+CONFIG_SND_SOC_PCM5102A=m
CONFIG_SOUND_PRIME=m
CONFIG_HIDRAW=y
CONFIG_HID_A4TECH=m
@@ -929,6 +936,10 @@ CONFIG_RTC_DRV_RS5C348=m
CONFIG_RTC_DRV_DS3234=m
CONFIG_RTC_DRV_PCF2123=m
CONFIG_RTC_DRV_RX4581=m
+CONFIG_DMADEVICES=y
+CONFIG_DMA_BCM2708=m
+CONFIG_DMA_ENGINE=y
+CONFIG_DMA_VIRTUAL_CHANNELS=m
CONFIG_UIO=m
CONFIG_UIO_PDRV_GENIRQ=m
CONFIG_STAGING=y
--
1.9.1

@ -0,0 +1,316 @@
From ab038bbb25bcd86ef59a5f5651ce00d30190d4ad Mon Sep 17 00:00:00 2001
From: Florian Meier <florian.meier@koalo.de>
Date: Fri, 6 Dec 2013 20:50:28 +0100
Subject: [PATCH 42/54] ASoC: BCM2708: Add support for RPi-DAC
This adds a machine driver for the RPi-DAC.
Signed-off-by: Florian Meier <florian.meier@koalo.de>
---
arch/arm/configs/bcmrpi_defconfig | 2 +
arch/arm/mach-bcm2708/bcm2708.c | 19 ++++++++
sound/soc/bcm/Kconfig | 7 +++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/rpi-dac.c | 97 +++++++++++++++++++++++++++++++++++++++
sound/soc/codecs/Kconfig | 4 ++
sound/soc/codecs/Makefile | 2 +
sound/soc/codecs/pcm1794a.c | 62 +++++++++++++++++++++++++
8 files changed, 195 insertions(+)
create mode 100644 sound/soc/bcm/rpi-dac.c
create mode 100644 sound/soc/codecs/pcm1794a.c
diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
index 36e7473..f877ab2 100644
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -744,8 +744,10 @@ CONFIG_SND_SOC_DMAENGINE_PCM=y
CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
CONFIG_SND_BCM2708_SOC_I2S=m
CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_RPI_DAC=m
CONFIG_SND_SOC_I2C_AND_SPI=m
CONFIG_SND_SOC_PCM5102A=m
+CONFIG_SND_SOC_PCM1794A=m
CONFIG_SOUND_PRIME=m
CONFIG_HIDRAW=y
CONFIG_HID_A4TECH=m
diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c
index 82b09a5..cf10f74 100644
--- a/arch/arm/mach-bcm2708/bcm2708.c
+++ b/arch/arm/mach-bcm2708/bcm2708.c
@@ -651,6 +651,20 @@ static struct platform_device snd_pcm5102a_codec_device = {
};
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+static struct platform_device snd_rpi_dac_device = {
+ .name = "snd-rpi-dac",
+ .id = 0,
+ .num_resources = 0,
+};
+
+static struct platform_device snd_pcm1794a_codec_device = {
+ .name = "pcm1794a-codec",
+ .id = -1,
+ .num_resources = 0,
+};
+#endif
+
int __init bcm_register_device(struct platform_device *pdev)
{
int ret;
@@ -783,6 +797,11 @@ void __init bcm2708_init(void)
bcm_register_device(&snd_pcm5102a_codec_device);
#endif
+#if defined(CONFIG_SND_BCM2708_SOC_RPI_DAC) || defined(CONFIG_SND_BCM2708_SOC_RPI_DAC_MODULE)
+ bcm_register_device(&snd_rpi_dac_device);
+ bcm_register_device(&snd_pcm1794a_codec_device);
+#endif
+
for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
struct amba_device *d = amba_devs[i];
amba_device_register(d, &iomem_resource);
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
index b36a62f..714841d 100644
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -25,3 +25,10 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
select SND_SOC_PCM5102A
help
Say Y or M if you want to add support for HifiBerry DAC.
+
+config SND_BCM2708_SOC_RPI_DAC
+ tristate "Support for RPi-DAC"
+ depends on SND_BCM2708_SOC_I2S
+ select SND_SOC_PCM1794A
+ help
+ Say Y or M if you want to add support for RPi-DAC.
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
index be90a49cb..ccc9809 100644
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -10,5 +10,7 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o
# 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
diff --git a/sound/soc/bcm/rpi-dac.c b/sound/soc/bcm/rpi-dac.c
new file mode 100644
index 0000000..ef3cd93
--- /dev/null
+++ b/sound/soc/bcm/rpi-dac.c
@@ -0,0 +1,97 @@
+/*
+ * ASoC Driver for RPi-DAC.
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+static int snd_rpi_rpi_dac_init(struct snd_soc_pcm_runtime *rtd)
+{
+ return 0;
+}
+
+static int snd_rpi_rpi_dac_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+ return snd_soc_dai_set_bclk_ratio(cpu_dai, 32*2);
+}
+
+/* machine stream operations */
+static struct snd_soc_ops snd_rpi_rpi_dac_ops = {
+ .hw_params = snd_rpi_rpi_dac_hw_params,
+};
+
+static struct snd_soc_dai_link snd_rpi_rpi_dac_dai[] = {
+{
+ .name = "HifiBerry Mini",
+ .stream_name = "HifiBerry Mini HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "pcm1794a-hifi",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "pcm1794a-codec",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &snd_rpi_rpi_dac_ops,
+ .init = snd_rpi_rpi_dac_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_rpi_dac = {
+ .name = "snd_rpi_rpi_dac",
+ .dai_link = snd_rpi_rpi_dac_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_rpi_dac_dai),
+};
+
+static int snd_rpi_rpi_dac_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_rpi_dac.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_rpi_dac);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_rpi_dac_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_rpi_dac);
+}
+
+static struct platform_driver snd_rpi_rpi_dac_driver = {
+ .driver = {
+ .name = "snd-rpi-dac",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_rpi_dac_probe,
+ .remove = snd_rpi_rpi_dac_remove,
+};
+
+module_platform_driver(snd_rpi_rpi_dac_driver);
+
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_DESCRIPTION("ASoC Driver for RPi-DAC");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index f0d76ec..4d2569e 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -59,6 +59,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM1681 if I2C
select SND_SOC_PCM1792A if SPI_MASTER
select SND_SOC_PCM3008
+ select SND_SOC_PCM1794A
select SND_SOC_PCM5102A
select SND_SOC_RT5631 if I2C
select SND_SOC_RT5640 if I2C
@@ -314,6 +315,9 @@ config SND_SOC_PCM1792A
config SND_SOC_PCM3008
tristate
+config SND_SOC_PCM1794A
+ tristate
+
config SND_SOC_PCM5102A
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 612f414..9b806a2 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -46,6 +46,7 @@ snd-soc-hdmi-codec-objs := hdmi.o
snd-soc-pcm1681-objs := pcm1681.o
snd-soc-pcm1792a-codec-objs := pcm1792a.o
snd-soc-pcm3008-objs := pcm3008.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
@@ -180,6 +181,7 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o
obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o
obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.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
diff --git a/sound/soc/codecs/pcm1794a.c b/sound/soc/codecs/pcm1794a.c
new file mode 100644
index 0000000..b4eaa44
--- /dev/null
+++ b/sound/soc/codecs/pcm1794a.c
@@ -0,0 +1,62 @@
+/*
+ * Driver for the PCM1794A codec
+ *
+ * Author: Florian Meier <florian.meier@koalo.de>
+ * Copyright 2013
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+
+static struct snd_soc_dai_driver pcm1794a_dai = {
+ .name = "pcm1794a-hifi",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE
+ },
+};
+
+static struct snd_soc_codec_driver soc_codec_dev_pcm1794a;
+
+static int pcm1794a_probe(struct platform_device *pdev)
+{
+ return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pcm1794a,
+ &pcm1794a_dai, 1);
+}
+
+static int pcm1794a_remove(struct platform_device *pdev)
+{
+ snd_soc_unregister_codec(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver pcm1794a_codec_driver = {
+ .probe = pcm1794a_probe,
+ .remove = pcm1794a_remove,
+ .driver = {
+ .name = "pcm1794a-codec",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(pcm1794a_codec_driver);
+
+MODULE_DESCRIPTION("ASoC PCM1794A codec driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
--
1.9.1

@ -0,0 +1,119 @@
From 0b1d46fef20d096cc3991df89ec793a10df0eaf2 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 43/54] 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 | 19 +++++++++++++++----
sound/soc/codecs/wm8804.h | 4 ++++
2 files changed, 19 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 9bc8206..c35b4f3 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -63,6 +63,7 @@ struct wm8804_priv {
struct regmap *regmap;
struct regulator_bulk_data supplies[WM8804_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8804_NUM_SUPPLIES];
+ int mclk_div;
};
static int txsrc_get(struct snd_kcontrol *kcontrol,
@@ -277,6 +278,7 @@ static int wm8804_hw_params(struct snd_pcm_substream *substream,
blen = 0x1;
break;
case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S32_LE:
blen = 0x2;
break;
default:
@@ -318,7 +320,7 @@ static struct {
#define FIXED_PLL_SIZE ((1ULL << 22) * 10)
static int pll_factors(struct pll_div *pll_div, unsigned int target,
- unsigned int source)
+ unsigned int source, unsigned int mclk_div)
{
u64 Kpart;
unsigned long int K, Ndiv, Nmod, tmp;
@@ -330,7 +332,8 @@ static int pll_factors(struct pll_div *pll_div, unsigned int target,
*/
for (i = 0; i < ARRAY_SIZE(post_table); i++) {
tmp = target * post_table[i].div;
- if (tmp >= 90000000 && tmp <= 100000000) {
+ if ((tmp >= 90000000 && tmp <= 100000000) &&
+ (mclk_div == post_table[i].mclkdiv)) {
pll_div->freqmode = post_table[i].freqmode;
pll_div->mclkdiv = post_table[i].mclkdiv;
target *= post_table[i].div;
@@ -387,8 +390,11 @@ static int wm8804_set_pll(struct snd_soc_dai *dai, int pll_id,
} else {
int ret;
struct pll_div pll_div;
+ struct wm8804_priv *wm8804;
- ret = pll_factors(&pll_div, freq_out, freq_in);
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+
+ ret = pll_factors(&pll_div, freq_out, freq_in, wm8804->mclk_div);
if (ret)
return ret;
@@ -452,6 +458,7 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
int div_id, int div)
{
struct snd_soc_codec *codec;
+ struct wm8804_priv *wm8804;
codec = dai->codec;
switch (div_id) {
@@ -459,6 +466,10 @@ static int wm8804_set_clkdiv(struct snd_soc_dai *dai,
snd_soc_update_bits(codec, WM8804_PLL5, 0x30,
(div & 0x3) << 4);
break;
+ case WM8804_MCLK_DIV:
+ wm8804 = snd_soc_codec_get_drvdata(codec);
+ wm8804->mclk_div = div;
+ break;
default:
dev_err(dai->dev, "Unknown clock divider: %d\n", div_id);
return -EINVAL;
@@ -641,7 +652,7 @@ static const struct snd_soc_dai_ops wm8804_dai_ops = {
};
#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 | \
diff --git a/sound/soc/codecs/wm8804.h b/sound/soc/codecs/wm8804.h
index 8ec14f5..e72d4f4 100644
--- a/sound/soc/codecs/wm8804.h
+++ b/sound/soc/codecs/wm8804.h
@@ -57,5 +57,9 @@
#define WM8804_CLKOUT_SRC_OSCCLK 4
#define WM8804_CLKOUT_DIV 1
+#define WM8804_MCLK_DIV 2
+
+#define WM8804_MCLKDIV_256FS 0
+#define WM8804_MCLKDIV_128FS 1
#endif /* _WM8804_H */
--
1.9.1

@ -0,0 +1,208 @@
From dad63ece33a339a45c992915eae9d7d8885e98c7 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 44/54] ASoC: BCM:Add support for HiFiBerry Digi. Driver is
based on the patched WM8804 driver.
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
---
sound/soc/bcm/Kconfig | 7 ++
sound/soc/bcm/Makefile | 2 +
sound/soc/bcm/hifiberry_digi.c | 153 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 162 insertions(+)
create mode 100644 sound/soc/bcm/hifiberry_digi.c
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig
index 714841d..e563dbc 100644
--- a/sound/soc/bcm/Kconfig
+++ b/sound/soc/bcm/Kconfig
@@ -26,6 +26,13 @@ config SND_BCM2708_SOC_HIFIBERRY_DAC
help
Say Y or M if you want to add support for HifiBerry DAC.
+config SND_BCM2708_SOC_HIFIBERRY_DIGI
+ tristate "Support for HifiBerry Digi"
+ depends on SND_BCM2708_SOC_I2S
+ 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
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile
index ccc9809..826df7d 100644
--- a/sound/soc/bcm/Makefile
+++ b/sound/soc/bcm/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o
# 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
diff --git a/sound/soc/bcm/hifiberry_digi.c b/sound/soc/bcm/hifiberry_digi.c
new file mode 100644
index 0000000..e4f769d
--- /dev/null
+++ b/sound/soc/bcm/hifiberry_digi.c
@@ -0,0 +1,153 @@
+/*
+ * 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 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_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 ret;
+
+ samplerate = params_rate(params);
+
+ switch (samplerate) {
+ case 44100:
+ case 48000:
+ case 88200:
+ case 96000:
+ mclk_freq=samplerate*256;
+ mclk_div=WM8804_MCLKDIV_256FS;
+ break;
+ case 176400:
+ case 192000:
+ mclk_freq=samplerate*128;
+ mclk_div=WM8804_MCLKDIV_128FS;
+ break;
+ default:
+ dev_err(substream->pcm->dev,
+ "Failed to set WM8804 SYSCLK, unsupported samplerate\n");
+ }
+
+ 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(substream->pcm->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);
+
+ 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,
+};
+
+static struct snd_soc_dai_link snd_rpi_hifiberry_digi_dai[] = {
+{
+ .name = "HifiBerry Digi",
+ .stream_name = "HifiBerry Digi HiFi",
+ .cpu_dai_name = "bcm2708-i2s.0",
+ .codec_dai_name = "wm8804-spdif",
+ .platform_name = "bcm2708-i2s.0",
+ .codec_name = "wm8804.1-003b",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM,
+ .ops = &snd_rpi_hifiberry_digi_ops,
+ .init = snd_rpi_hifiberry_digi_init,
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card snd_rpi_hifiberry_digi = {
+ .name = "snd_rpi_hifiberry_digi",
+ .dai_link = snd_rpi_hifiberry_digi_dai,
+ .num_links = ARRAY_SIZE(snd_rpi_hifiberry_digi_dai),
+};
+
+static int snd_rpi_hifiberry_digi_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ snd_rpi_hifiberry_digi.dev = &pdev->dev;
+ ret = snd_soc_register_card(&snd_rpi_hifiberry_digi);
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+ return ret;
+}
+
+static int snd_rpi_hifiberry_digi_remove(struct platform_device *pdev)
+{
+ return snd_soc_unregister_card(&snd_rpi_hifiberry_digi);
+}
+
+static struct platform_driver snd_rpi_hifiberry_digi_driver = {
+ .driver = {
+ .name = "snd-hifiberry-digi",
+ .owner = THIS_MODULE,
+ },
+ .probe = snd_rpi_hifiberry_digi_probe,
+ .remove = snd_rpi_hifiberry_digi_remove,
+};
+
+module_platform_driver(snd_rpi_hifiberry_digi_driver);
+
+MODULE_AUTHOR("Daniel Matuschek <info@crazy-audio.com>");
+MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi");
+MODULE_LICENSE("GPL v2");
--
1.9.1

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

@ -0,0 +1,30 @@
From f70ff551596e371431a05ab5678fb12f2dfc282a Mon Sep 17 00:00:00 2001
From: Daniel Matuschek <info@crazy-audio.com>
Date: Thu, 16 Jan 2014 07:27:28 +0100
Subject: [PATCH 46/54] BCM2708: Added HiFiBerry Digi configuration option It
will be compiled as a module by default. This also includes the WM8804
driver.
Signed-off-by: Daniel Matuschek <daniel@matuschek.net>
---
arch/arm/configs/bcmrpi_defconfig | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig
index f877ab2..3d3c8ab 100644
--- a/arch/arm/configs/bcmrpi_defconfig
+++ b/arch/arm/configs/bcmrpi_defconfig
@@ -742,8 +742,10 @@ CONFIG_SND_USB_6FIRE=m
CONFIG_SND_SOC=m
CONFIG_SND_SOC_DMAENGINE_PCM=y
CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM=y
+CONFIG_SND_SOC_WM8804=m
CONFIG_SND_BCM2708_SOC_I2S=m
CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC=m
+CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI=m
CONFIG_SND_BCM2708_SOC_RPI_DAC=m
CONFIG_SND_SOC_I2C_AND_SPI=m
CONFIG_SND_SOC_PCM5102A=m
--
1.9.1

@ -0,0 +1,27 @@
From d3dd70a52c9da2cec7b1b9247834357e5e5166eb 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 47/54] 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(-)
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index c35b4f3..8915d08 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -685,7 +685,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8804 = {
.suspend = wm8804_suspend,
.resume = wm8804_resume,
.set_bias_level = wm8804_set_bias_level,
- .idle_bias_off = true,
+ .idle_bias_off = false,
.controls = wm8804_snd_controls,
.num_controls = ARRAY_SIZE(wm8804_snd_controls),
--
1.9.1

@ -0,0 +1,40 @@
From ea4cb320f037ddad635159ad0d34a4e7993a252b Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Wed, 12 Mar 2014 11:46:34 +0000
Subject: [PATCH 48/54] ASoc: Don't report S24_LE support, it produces white
noise with xbmc
---
sound/soc/bcm/bcm2708-i2s.c | 2 +-
sound/soc/codecs/pcm5102a.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c
index a179216..b25e158 100644
--- a/sound/soc/bcm/bcm2708-i2s.c
+++ b/sound/soc/bcm/bcm2708-i2s.c
@@ -718,7 +718,7 @@ static struct snd_soc_dai_driver bcm2708_i2s_dai = {
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE
- | SNDRV_PCM_FMTBIT_S24_LE
+ // | SNDRV_PCM_FMTBIT_S24_LE : disable for now, it causes white noise with xbmc
| SNDRV_PCM_FMTBIT_S32_LE
},
.capture = {
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c
index 126f1e9..7812d34 100644
--- a/sound/soc/codecs/pcm5102a.c
+++ b/sound/soc/codecs/pcm5102a.c
@@ -28,7 +28,7 @@ static struct snd_soc_dai_driver pcm5102a_dai = {
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
- SNDRV_PCM_FMTBIT_S24_LE |
+ // SNDRV_PCM_FMTBIT_S24_LE | : disable for now, it causes white noise with xbmc
SNDRV_PCM_FMTBIT_S32_LE
},
};
--
1.9.1

@ -0,0 +1,78 @@
From a46efd685fc6c9676b68f02e8ef12c5821809364 Mon Sep 17 00:00:00 2001
From: Howard Mitchell <hm@hmbedded.co.uk>
Date: Fri, 28 Mar 2014 16:27:57 +0000
Subject: [PATCH 50/54] Fix volsw_range functions so SOC_DOUBLE_R_RANGE_TLV
works.
This is so that the correct rabge of values as specified
with the SOC_DOUBLE_R_RANGE_TLV macro are sent to the
hardware for both the normal and invert cases.
---
sound/soc/soc-core.c | 22 ++++++++++------------
1 file changed, 10 insertions(+), 12 deletions(-)
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index fe1df50..c3f41e7 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3038,8 +3038,8 @@ int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - min;
+ uinfo->value.integer.min = min;
+ uinfo->value.integer.max = platform_max;
return 0;
}
@@ -3070,9 +3070,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
unsigned int val, val_mask;
int ret;
- val = ((ucontrol->value.integer.value[0] + min) & mask);
if (invert)
- val = max - val;
+ val = ((max - ucontrol->value.integer.value[0] + min) & mask);
+ else
+ val = (ucontrol->value.integer.value[0] & mask);
val_mask = mask << shift;
val = val << shift;
@@ -3081,9 +3082,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
return ret;
if (snd_soc_volsw_is_stereo(mc)) {
- val = ((ucontrol->value.integer.value[1] + min) & mask);
if (invert)
- val = max - val;
+ val = ((max - ucontrol->value.integer.value[1] + min) & mask);
+ else
+ val = (ucontrol->value.integer.value[1] & mask);
val_mask = mask << shift;
val = val << shift;
@@ -3121,18 +3123,14 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
(snd_soc_read(codec, reg) >> shift) & mask;
if (invert)
ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
- ucontrol->value.integer.value[0] =
- ucontrol->value.integer.value[0] - min;
+ max - ucontrol->value.integer.value[0] + min;
if (snd_soc_volsw_is_stereo(mc)) {
ucontrol->value.integer.value[1] =
(snd_soc_read(codec, rreg) >> shift) & mask;
if (invert)
ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- ucontrol->value.integer.value[1] =
- ucontrol->value.integer.value[1] - min;
+ max - ucontrol->value.integer.value[1] + min;
}
return 0;
--
1.9.1

@ -0,0 +1,29 @@
From 53f059eb1ce439b171516c0e6673ab88ca25e166 Mon Sep 17 00:00:00 2001
From: Howard Mitchell <hm@hmbedded.co.uk>
Date: Fri, 28 Mar 2014 16:40:31 +0000
Subject: [PATCH 51/54] Use a range macro for Playback Volume.
This allows limiting the output gain to avoid clipping in the
DAC ouput stages.
---
sound/soc/codecs/pcm512x.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 55b6200..2653311 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -240,8 +240,8 @@ static const struct soc_enum pcm512x_veds =
pcm512x_ramp_step_text);
static const struct snd_kcontrol_new pcm512x_controls[] = {
-SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
- PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv),
+SOC_DOUBLE_R_RANGE_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
+ PCM512x_DIGITAL_VOLUME_3, 0, 48, 255, 1, digital_tlv),
SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
--
1.9.1

@ -0,0 +1,56 @@
From 7d86ec6d4ad388d8287a68d31ff3e3028477fd86 Mon Sep 17 00:00:00 2001
From: Gordon Garrity <gordon@iqaudio.com>
Date: Sun, 30 Mar 2014 13:52:33 +0100
Subject: [PATCH 52/54] fix soc-core's inverse range and let IQaudIO DAC use
this fixed SOC_DOUBLE_R_RANGE_TLV support
---
sound/soc/codecs/pcm512x.c | 3 ++-
sound/soc/soc-core.c | 8 ++++----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c
index 2653311..b669e15 100644
--- a/sound/soc/codecs/pcm512x.c
+++ b/sound/soc/codecs/pcm512x.c
@@ -239,9 +239,10 @@ static const struct soc_enum pcm512x_veds =
SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4,
pcm512x_ramp_step_text);
+/* Don't let the DAC go into clipping by limiting the alsa volume control range */
static const struct snd_kcontrol_new pcm512x_controls[] = {
SOC_DOUBLE_R_RANGE_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2,
- PCM512x_DIGITAL_VOLUME_3, 0, 48, 255, 1, digital_tlv),
+ PCM512x_DIGITAL_VOLUME_3, 0, 40, 255, 1, digital_tlv),
SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT,
PCM512x_RQMR_SHIFT, 1, 1),
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index c3f41e7..a8a753f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3072,8 +3072,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
if (invert)
val = ((max - ucontrol->value.integer.value[0] + min) & mask);
- else
- val = (ucontrol->value.integer.value[0] & mask);
+ else
+ val = (ucontrol->value.integer.value[0] & mask);
val_mask = mask << shift;
val = val << shift;
@@ -3084,8 +3084,8 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
if (snd_soc_volsw_is_stereo(mc)) {
if (invert)
val = ((max - ucontrol->value.integer.value[1] + min) & mask);
- else
- val = (ucontrol->value.integer.value[1] & mask);
+ else
+ val = (ucontrol->value.integer.value[1] & mask);
val_mask = mask << shift;
val = val << shift;
--
1.9.1

@ -0,0 +1,101 @@
From 3eae00b73609f4e5a19260bfa4ca9021f295c0af Mon Sep 17 00:00:00 2001
From: Gordon Hollingworth <gordon@holliweb.co.uk>
Date: Fri, 2 May 2014 16:13:59 +0100
Subject: [PATCH 53/54] Move GPIO setup to hw_params.
This is used to stop the I2S driver from breaking
the GPIO setup for other uses of the PCM interface
---
sound/soc/bcm/bcm2708-i2s.c | 55 +++++++++++++++++++++++----------------------
1 file changed, 28 insertions(+), 27 deletions(-)
diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c
index b25e158..9976571 100644
--- a/sound/soc/bcm/bcm2708-i2s.c
+++ b/sound/soc/bcm/bcm2708-i2s.c
@@ -305,6 +305,31 @@ static int bcm2708_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai,
return 0;
}
+
+static void bcm2708_i2s_setup_gpio(void)
+{
+ /*
+ * This is the common way to handle the GPIO pins for
+ * the Raspberry Pi.
+ * TODO Better way would be to handle
+ * this in the device tree!
+ */
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+ unsigned int *gpio;
+ int pin;
+ gpio = ioremap(GPIO_BASE, SZ_16K);
+
+ /* SPI is on GPIO 7..11 */
+ for (pin = 28; pin <= 31; pin++) {
+ INP_GPIO(pin); /* set mode to GPIO input first */
+ SET_GPIO_ALT(pin, 2); /* set mode to ALT 0 */
+ }
+#undef INP_GPIO
+#undef SET_GPIO_ALT
+}
+
static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -334,6 +359,9 @@ static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream,
if (csreg & (BCM2708_I2S_TXON | BCM2708_I2S_RXON))
return 0;
+
+ bcm2708_i2s_setup_gpio();
+
/*
* Adjust the data length according to the format.
* We prefill the half frame length with an integer
@@ -790,31 +818,6 @@ static const struct snd_soc_component_driver bcm2708_i2s_component = {
.name = "bcm2708-i2s-comp",
};
-
-static void bcm2708_i2s_setup_gpio(void)
-{
- /*
- * This is the common way to handle the GPIO pins for
- * the Raspberry Pi.
- * TODO Better way would be to handle
- * this in the device tree!
- */
-#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
-#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
-
- unsigned int *gpio;
- int pin;
- gpio = ioremap(GPIO_BASE, SZ_16K);
-
- /* SPI is on GPIO 7..11 */
- for (pin = 28; pin <= 31; pin++) {
- INP_GPIO(pin); /* set mode to GPIO input first */
- SET_GPIO_ALT(pin, 2); /* set mode to ALT 0 */
- }
-#undef INP_GPIO
-#undef SET_GPIO_ALT
-}
-
static const struct snd_pcm_hardware bcm2708_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_JOINT_DUPLEX,
@@ -865,8 +868,6 @@ static int bcm2708_i2s_probe(struct platform_device *pdev)
if (IS_ERR(dev))
return PTR_ERR(dev);
- bcm2708_i2s_setup_gpio();
-
dev->i2s_regmap = regmap[0];
dev->clk_regmap = regmap[1];
--
1.9.1

@ -0,0 +1,77 @@
From 2bdcc63f2648ad4dfa88aaf035e025b2b193a1cc Mon Sep 17 00:00:00 2001
From: popcornmix <popcornmix@gmail.com>
Date: Fri, 9 May 2014 15:45:13 +0100
Subject: [PATCH 54/54] fb: distinguish physical and bus addresses
---
drivers/video/bcm2708_fb.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c
index 798eb52..b3b1e04 100644
--- a/drivers/video/bcm2708_fb.c
+++ b/drivers/video/bcm2708_fb.c
@@ -89,6 +89,7 @@ struct bcm2708_fb {
struct dentry *debugfs_dir;
wait_queue_head_t dma_waitq;
struct bcm2708_fb_stats stats;
+ unsigned long fb_bus_address;
};
#define to_bcm2708(info) container_of(info, struct bcm2708_fb, fb)
@@ -314,13 +315,15 @@ static int bcm2708_fb_set_par(struct fb_info *info)
else
fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ fb->fb_bus_address = fbinfo->base;
+ fbinfo->base &= ~0xc0000000;
fb->fb.fix.smem_start = fbinfo->base;
fb->fb.fix.smem_len = fbinfo->pitch * fbinfo->yres_virtual;
fb->fb.screen_size = fbinfo->screen_size;
if (fb->fb.screen_base)
iounmap(fb->fb.screen_base);
fb->fb.screen_base =
- (void *)ioremap_wc(fb->fb.fix.smem_start, fb->fb.screen_size);
+ (void *)ioremap_wc(fbinfo->base, fb->fb.screen_size);
if (!fb->fb.screen_base) {
/* the console may currently be locked */
console_trylock();
@@ -331,7 +334,7 @@ static int bcm2708_fb_set_par(struct fb_info *info)
}
print_debug
("BCM2708FB: start = %p,%p width=%d, height=%d, bpp=%d, pitch=%d size=%d success=%d\n",
- (void *)fb->fb.screen_base, (void *)fb->fb.fix.smem_start,
+ (void *)fb->fb.screen_base, (void *)fb->fb_bus_address,
fbinfo->xres, fbinfo->yres, fbinfo->bpp,
fbinfo->pitch, (int)fb->fb.screen_size, val);
@@ -457,11 +460,11 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
for (y = 0; y < region->height; y += scanlines_per_cb) {
dma_addr_t src =
- fb->fb.fix.smem_start +
+ fb->fb_bus_address +
bytes_per_pixel * region->sx +
(region->sy + y) * fb->fb.fix.line_length;
dma_addr_t dst =
- fb->fb.fix.smem_start +
+ fb->fb_bus_address +
bytes_per_pixel * region->dx +
(region->dy + y) * fb->fb.fix.line_length;
@@ -499,10 +502,10 @@ static void bcm2708_fb_copyarea(struct fb_info *info,
stride = -fb->fb.fix.line_length;
}
set_dma_cb(cb, burst_size,
- fb->fb.fix.smem_start + dy * fb->fb.fix.line_length +
+ fb->fb_bus_address + dy * fb->fb.fix.line_length +
bytes_per_pixel * region->dx,
stride,
- fb->fb.fix.smem_start + sy * fb->fb.fix.line_length +
+ fb->fb_bus_address + sy * fb->fb.fix.line_length +
bytes_per_pixel * region->sx,
stride,
region->width * bytes_per_pixel,
--
1.9.1
Loading…
Cancel
Save