From 1b251bddc18737136dfa6d7346426f154d769da9 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Tue, 1 Apr 2014 00:35:52 +0200 Subject: [PATCH] projects/RPi/patches: update RPi kernel patch for kernel 3.14, switch to kernel 3.14 Signed-off-by: Stephan Raue --- projects/RPi/linux/linux.arm.conf | 80 +- projects/RPi/options | 2 +- ...tch => linux-01-RPi_support-dbddcf7.patch} | 15636 ++++++++-------- 3 files changed, 7530 insertions(+), 8188 deletions(-) rename projects/RPi/patches/linux/{linux-01-RPi_support-2514e94.patch => linux-01-RPi_support-dbddcf7.patch} (97%) diff --git a/projects/RPi/linux/linux.arm.conf b/projects/RPi/linux/linux.arm.conf index d47e5877c9..05ff3e29c9 100644 --- a/projects/RPi/linux/linux.arm.conf +++ b/projects/RPi/linux/linux.arm.conf @@ -1,6 +1,6 @@ # # Automatically generated file; DO NOT EDIT. -# Linux/arm 3.13.5 Kernel Configuration +# Linux/arm 3.14.0 Kernel Configuration # CONFIG_ARM=y CONFIG_SYS_SUPPORTS_APM_EMULATION=y @@ -115,7 +115,6 @@ CONFIG_CGROUPS=y # CONFIG_BLK_CGROUP is not set # CONFIG_CHECKPOINT_RESTORE is not set # CONFIG_NAMESPACES is not set -# CONFIG_UIDGID_STRICT_TYPE_CHECKS is not set # CONFIG_SCHED_AUTOGROUP is not set # CONFIG_SYSFS_DEPRECATED is not set # CONFIG_RELAY is not set @@ -169,6 +168,8 @@ CONFIG_HAVE_OPROFILE=y # CONFIG_KPROBES is not set CONFIG_JUMP_LABEL=y # CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set +CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y +CONFIG_ARCH_USE_BUILTIN_BSWAP=y CONFIG_HAVE_KPROBES=y CONFIG_HAVE_KRETPROBES=y CONFIG_HAVE_ARCH_TRACEHOOK=y @@ -184,6 +185,11 @@ CONFIG_HAVE_PERF_USER_STACK_DUMP=y CONFIG_HAVE_ARCH_JUMP_LABEL=y CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y +CONFIG_HAVE_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR is not set +CONFIG_CC_STACKPROTECTOR_NONE=y +# CONFIG_CC_STACKPROTECTOR_REGULAR is not set +# CONFIG_CC_STACKPROTECTOR_STRONG is not set CONFIG_HAVE_CONTEXT_TRACKING=y CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y @@ -282,8 +288,8 @@ CONFIG_ARCH_BCM2708=y # CONFIG_ARCH_W90X900 is not set # CONFIG_ARCH_LPC32XX is not set # CONFIG_ARCH_PXA is not set -# CONFIG_ARCH_MSM is not set -# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_MSM_NODT is not set +# CONFIG_ARCH_SHMOBILE_LEGACY is not set # CONFIG_ARCH_RPC is not set # CONFIG_ARCH_SA1100 is not set # CONFIG_ARCH_S3C24XX is not set @@ -377,6 +383,7 @@ CONFIG_ARCH_WANT_GENERAL_HUGETLB=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_HAVE_MEMBLOCK=y +CONFIG_NO_BOOTMEM=y # CONFIG_HAVE_BOOTMEM_INFO_NODE is not set CONFIG_PAGEFLAGS_EXTENDED=y CONFIG_SPLIT_PTLOCK_CPUS=4 @@ -393,11 +400,11 @@ CONFIG_FRONTSWAP=y # CONFIG_CMA is not set # CONFIG_ZBUD is not set # CONFIG_ZSWAP is not set +# CONFIG_ZSMALLOC is not set CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_ALIGNMENT_TRAP=y # CONFIG_UACCESS_WITH_MEMCPY is not set # CONFIG_SECCOMP is not set -# CONFIG_CC_STACKPROTECTOR is not set CONFIG_SWIOTLB=y CONFIG_IOMMU_HELPER=y @@ -646,6 +653,7 @@ CONFIG_LLC=m # CONFIG_LAPB is not set # CONFIG_PHONET is not set # CONFIG_IEEE802154 is not set +CONFIG_6LOWPAN_IPHC=m # CONFIG_NET_SCHED is not set # CONFIG_DCB is not set CONFIG_DNS_RESOLVER=y @@ -656,7 +664,8 @@ CONFIG_DNS_RESOLVER=y # CONFIG_NETLINK_DIAG is not set # CONFIG_NET_MPLS_GSO is not set # CONFIG_HSR is not set -# CONFIG_NETPRIO_CGROUP is not set +# CONFIG_CGROUP_NET_PRIO is not set +# CONFIG_CGROUP_NET_CLASSID is not set CONFIG_NET_RX_BUSY_POLL=y CONFIG_BQL=y # CONFIG_BPF_JIT is not set @@ -962,6 +971,7 @@ CONFIG_USB_NET_CDCETHER=m # CONFIG_USB_NET_CDC_MBIM is not set CONFIG_USB_NET_DM9601=m # CONFIG_USB_NET_SR9700 is not set +# CONFIG_USB_NET_SR9800 is not set CONFIG_USB_NET_SMSC75XX=m CONFIG_USB_NET_SMSC95XX=y # CONFIG_USB_NET_GL620A is not set @@ -1021,6 +1031,7 @@ CONFIG_B43_HWRNG=y # CONFIG_B43_DEBUG is not set # CONFIG_B43LEGACY is not set CONFIG_BRCMUTIL=m +# CONFIG_BRCMSMAC is not set CONFIG_BRCMFMAC=m # CONFIG_BRCMFMAC_SDIO is not set CONFIG_BRCMFMAC_USB=y @@ -1198,7 +1209,14 @@ CONFIG_I2C=y CONFIG_I2C_BOARDINFO=y # CONFIG_I2C_COMPAT is not set CONFIG_I2C_CHARDEV=y -# CONFIG_I2C_MUX is not set +CONFIG_I2C_MUX=m + +# +# Multiplexer I2C Chip support +# +# CONFIG_I2C_MUX_GPIO is not set +# CONFIG_I2C_MUX_PCA9541 is not set +# CONFIG_I2C_MUX_PCA954x is not set CONFIG_I2C_HELPER_AUTO=y CONFIG_I2C_ALGOBIT=y @@ -1218,16 +1236,15 @@ CONFIG_I2C_GPIO=y # CONFIG_I2C_OCORES is not set # CONFIG_I2C_PCA_PLATFORM is not set # CONFIG_I2C_PXA_PCI is not set -# CONFIG_I2C_SH_MOBILE is not set # CONFIG_I2C_SIMTEC is not set # CONFIG_I2C_XILINX is not set -# CONFIG_I2C_RCAR is not set # # External I2C/SMBus adapter drivers # # CONFIG_I2C_DIOLAN_U2C is not set # CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_ROBOTFUZZ_OSIF is not set # CONFIG_I2C_TAOS_EVM is not set # CONFIG_I2C_TINY_USB is not set @@ -1294,6 +1311,7 @@ CONFIG_GPIO_SYSFS=y # CONFIG_GPIO_GENERIC_PLATFORM is not set # CONFIG_GPIO_PL061 is not set # CONFIG_GPIO_RCAR is not set +# CONFIG_GPIO_SCH311X is not set # CONFIG_GPIO_TS5500 is not set # @@ -1313,9 +1331,7 @@ CONFIG_GPIO_SYSFS=y # SPI GPIO expanders: # # CONFIG_GPIO_MAX7301 is not set -# CONFIG_GPIO_MCP23S08 is not set # CONFIG_GPIO_MC33880 is not set -# CONFIG_GPIO_74X164 is not set # # AC97 GPIO expanders: @@ -1469,7 +1485,6 @@ CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y # CONFIG_THERMAL_GOV_FAIR_SHARE is not set CONFIG_THERMAL_GOV_STEP_WISE=y # CONFIG_THERMAL_GOV_USER_SPACE is not set -# CONFIG_CPU_THERMAL is not set # CONFIG_THERMAL_EMULATION is not set CONFIG_THERMAL_BCM2835=y @@ -1519,6 +1534,7 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_MFD_88PM800 is not set # CONFIG_MFD_88PM805 is not set # CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_MAX14577 is not set # CONFIG_MFD_MAX77686 is not set # CONFIG_MFD_MAX77693 is not set # CONFIG_MFD_MAX8907 is not set @@ -1538,6 +1554,7 @@ CONFIG_BCMA_POSSIBLE=y # CONFIG_MFD_STMPE is not set # CONFIG_MFD_SYSCON is not set # CONFIG_MFD_TI_AM335X_TSCADC is not set +# CONFIG_MFD_LP3943 is not set # CONFIG_MFD_LP8788 is not set # CONFIG_MFD_PALMAS is not set # CONFIG_TPS6105X is not set @@ -1590,7 +1607,6 @@ CONFIG_VIDEOBUF_DVB=m CONFIG_VIDEOBUF2_CORE=m CONFIG_VIDEOBUF2_MEMOPS=m CONFIG_VIDEOBUF2_VMALLOC=m -# CONFIG_VIDEO_V4L2_INT_DEVICE is not set CONFIG_DVB_CORE=m CONFIG_DVB_NET=y CONFIG_TTPCI_EEPROM=m @@ -1702,6 +1718,7 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m # Webcam, TV (analog/digital) USB devices # CONFIG_VIDEO_EM28XX=m +# CONFIG_VIDEO_EM28XX_V4L2 is not set # CONFIG_VIDEO_EM28XX_ALSA is not set CONFIG_VIDEO_EM28XX_DVB=m CONFIG_VIDEO_EM28XX_RC=m @@ -1745,7 +1762,6 @@ CONFIG_VIDEO_WM8775=m # Video decoders # CONFIG_VIDEO_SAA711X=m -CONFIG_VIDEO_TVP5150=m # # Video and audio decoders @@ -1759,7 +1775,6 @@ CONFIG_VIDEO_CX25840=m # # Camera sensor devices # -CONFIG_VIDEO_MT9V011=m # # Flash devices @@ -1769,6 +1784,10 @@ CONFIG_VIDEO_MT9V011=m # Video improvement chips # +# +# Audio/Video compression chips +# + # # Miscellaneous helper chips # @@ -1803,6 +1822,7 @@ CONFIG_MEDIA_TUNER_FC0013=m CONFIG_MEDIA_TUNER_TDA18212=m CONFIG_MEDIA_TUNER_E4000=m CONFIG_MEDIA_TUNER_FC2580=m +CONFIG_MEDIA_TUNER_M88TS2022=m CONFIG_MEDIA_TUNER_TUA9001=m CONFIG_MEDIA_TUNER_IT913X=m CONFIG_MEDIA_TUNER_R820T=m @@ -1815,6 +1835,7 @@ CONFIG_DVB_STB0899=m CONFIG_DVB_STB6100=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m +CONFIG_DVB_M88DS3103=m # # Multistandard (cable + terrestrial) frontends @@ -1839,7 +1860,7 @@ CONFIG_DVB_TUNER_ITD1000=m CONFIG_DVB_TUNER_CX24113=m CONFIG_DVB_TDA826X=m CONFIG_DVB_CX24116=m -CONFIG_DVB_M88DS3103=m +CONFIG_DVB_DVBSKY_M88DS3103=m CONFIG_DVB_SI21XX=m CONFIG_DVB_TS2020=m CONFIG_DVB_DS3000=m @@ -1946,6 +1967,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y # CONFIG_FB_BCM2708=y # CONFIG_FB_ARMCLCD is not set +# CONFIG_FB_OPENCORES is not set # CONFIG_FB_S1D13XXX is not set # CONFIG_FB_SMSCUFX is not set # CONFIG_FB_UDL is not set @@ -2011,18 +2033,12 @@ 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_BCM2708_SOC_HIFIBERRY_MINI=m -CONFIG_SND_BCM2708_SOC_RPI_CODEC_MBED=m -CONFIG_SND_BCM2708_SOC_RPI_CODEC_TDA1541A=m -CONFIG_SND_BCM2708_SOC_RPI_CODEC_PROTO=m -CONFIG_SND_BCM2708_SOC_RPI_CODEC_ESS9018=m -CONFIG_SND_BCM2708_SOC_RPI_CODEC_PCM5102A=m +CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m # CONFIG_SND_DESIGNWARE_I2S is not set CONFIG_SND_SOC_I2C_AND_SPI=m CONFIG_SND_SOC_PCM1794A=m CONFIG_SND_SOC_PCM5102A=m -CONFIG_SND_SOC_TLV320AIC3X=m -CONFIG_SND_SOC_WM8731=m +CONFIG_SND_SOC_PCM512x=m CONFIG_SND_SOC_WM8804=m # CONFIG_SND_SIMPLE_CARD is not set # CONFIG_SOUND_PRIME is not set @@ -2188,7 +2204,9 @@ CONFIG_USB_STORAGE=y # # CONFIG_USB_MDC800 is not set # CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MUSB_HDRC is not set # CONFIG_USB_DWC3 is not set +# CONFIG_USB_DWC2 is not set # # USB port drivers @@ -2223,6 +2241,7 @@ CONFIG_USB_SERIAL_IUU=m # CONFIG_USB_SERIAL_METRO is not set # CONFIG_USB_SERIAL_MOS7720 is not set # CONFIG_USB_SERIAL_MOS7840 is not set +# CONFIG_USB_SERIAL_MXUPORT is not set # CONFIG_USB_SERIAL_NAVMAN is not set CONFIG_USB_SERIAL_PL2303=m # CONFIG_USB_SERIAL_OTI6858 is not set @@ -2275,6 +2294,7 @@ CONFIG_USB_SERIAL_PL2303=m # USB Physical Layer drivers # # CONFIG_USB_PHY is not set +# CONFIG_USB_OTG_FSM is not set # CONFIG_NOP_USB_XCEIV is not set # CONFIG_AM335X_PHY_USB is not set # CONFIG_SAMSUNG_USB2PHY is not set @@ -2386,6 +2406,7 @@ CONFIG_RTC_DRV_DS1307=m # CONFIG_RTC_DRV_RS5C372 is not set # CONFIG_RTC_DRV_ISL1208 is not set # CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_ISL12057 is not set # CONFIG_RTC_DRV_X1205 is not set # CONFIG_RTC_DRV_PCF2127 is not set # CONFIG_RTC_DRV_PCF8523 is not set @@ -2454,6 +2475,7 @@ CONFIG_DMADEVICES=y # CONFIG_DW_DMAC is not set # CONFIG_TIMB_DMA is not set # CONFIG_PL330_DMA is not set +CONFIG_DMA_BCM2835=m CONFIG_DMA_BCM2708=m CONFIG_DMA_ENGINE=y CONFIG_DMA_VIRTUAL_CHANNELS=m @@ -2490,7 +2512,6 @@ CONFIG_RTS5139=m # CONFIG_LINE6_USB is not set # CONFIG_USB_SERIAL_QUATECH2 is not set CONFIG_VT6656=m -# CONFIG_ZSMALLOC is not set # CONFIG_USB_ENESTORAGE is not set # CONFIG_BCM_WIMAX is not set # CONFIG_FT1000 is not set @@ -2505,6 +2526,7 @@ CONFIG_STAGING_MEDIA=y CONFIG_DVB_AS102=m # CONFIG_VIDEO_GO7007 is not set CONFIG_USB_MSI3101=m +# CONFIG_USB_SN9C102 is not set CONFIG_LIRC_STAGING=y CONFIG_LIRC_IGORPLUGUSB=m # CONFIG_LIRC_IMON is not set @@ -2524,9 +2546,7 @@ CONFIG_LIRC_XBOX=m # CONFIG_LTE_GDM724X is not set # CONFIG_CED1401 is not set # CONFIG_DGRP is not set -# CONFIG_USB_DWC2 is not set # CONFIG_LUSTRE_FS is not set -CONFIG_USB_BTMTK=m # CONFIG_DGAP is not set CONFIG_CLKDEV_LOOKUP=y @@ -2609,7 +2629,6 @@ CONFIG_FANOTIFY=y CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=m # CONFIG_CUSE is not set -CONFIG_GENERIC_ACL=y # # Caches @@ -2829,6 +2848,7 @@ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0 # CONFIG_DETECT_HUNG_TASK is not set # CONFIG_PANIC_ON_OOPS is not set CONFIG_PANIC_ON_OOPS_VALUE=0 +CONFIG_PANIC_TIMEOUT=0 # CONFIG_SCHED_DEBUG is not set # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set @@ -2891,9 +2911,12 @@ CONFIG_TRACING_SUPPORT=y # CONFIG_TEST_STRING_HELPERS is not set # CONFIG_TEST_KSTRTOX is not set # CONFIG_DMA_API_DEBUG is not set +# CONFIG_TEST_MODULE is not set +# CONFIG_TEST_USER_COPY is not set # CONFIG_SAMPLES is not set CONFIG_HAVE_ARCH_KGDB=y # CONFIG_KGDB is not set +# CONFIG_ARM_PTDUMP is not set # CONFIG_STRICT_DEVMEM is not set # CONFIG_ARM_UNWIND is not set # CONFIG_DEBUG_USER is not set @@ -2904,6 +2927,7 @@ CONFIG_DEBUG_LL_INCLUDE="mach/debug-macro.S" CONFIG_UNCOMPRESS_INCLUDE="mach/uncompress.h" # CONFIG_OC_ETM is not set # CONFIG_PID_IN_CONTEXTIDR is not set +# CONFIG_DEBUG_SET_MODULE_RONX is not set # # Security options diff --git a/projects/RPi/options b/projects/RPi/options index 83031438d6..1a3e6f35cd 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -106,7 +106,7 @@ # Kernel to use. values can be: # default: default mainline kernel - LINUX="3.13" + LINUX="default" # use linux-next (latest rc) instead latest released version LINUX_NEXT="no" diff --git a/projects/RPi/patches/linux/linux-01-RPi_support-2514e94.patch b/projects/RPi/patches/linux/linux-01-RPi_support-dbddcf7.patch similarity index 97% rename from projects/RPi/patches/linux/linux-01-RPi_support-2514e94.patch rename to projects/RPi/patches/linux/linux-01-RPi_support-dbddcf7.patch index f858829d34..e49ddf2a65 100644 --- a/projects/RPi/patches/linux/linux-01-RPi_support-2514e94.patch +++ b/projects/RPi/patches/linux/linux-01-RPi_support-dbddcf7.patch @@ -1,7 +1,7 @@ -From 1f02e316c486f346622a9d667f1546e8d7a63e66 Mon Sep 17 00:00:00 2001 +From eed8f04670917df6c455a4c1d2927acba4289f0d Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 001/118] Main bcm2708 linux port +Subject: [PATCH 01/99] Main bcm2708 linux port Signed-off-by: popcornmix --- @@ -17,9 +17,9 @@ Signed-off-by: popcornmix arch/arm/mach-bcm2708/Makefile.boot | 3 + arch/arm/mach-bcm2708/armctrl.c | 208 ++++ arch/arm/mach-bcm2708/armctrl.h | 27 + - arch/arm/mach-bcm2708/bcm2708.c | 711 +++++++++++ + arch/arm/mach-bcm2708/bcm2708.c | 717 +++++++++++ arch/arm/mach-bcm2708/bcm2708.h | 49 + - arch/arm/mach-bcm2708/bcm2708_gpio.c | 339 +++++ + arch/arm/mach-bcm2708/bcm2708_gpio.c | 361 ++++++ arch/arm/mach-bcm2708/clock.c | 61 + arch/arm/mach-bcm2708/clock.h | 24 + arch/arm/mach-bcm2708/dma.c | 399 ++++++ @@ -56,7 +56,7 @@ Signed-off-by: popcornmix drivers/mmc/host/sdhci.h | 37 + drivers/tty/serial/amba-pl011.c | 2 +- include/linux/mmc/sdhci.h | 2 + - 51 files changed, 7763 insertions(+), 72 deletions(-) + 51 files changed, 7791 insertions(+), 72 deletions(-) create mode 100644 arch/arm/configs/bcmrpi_cutdown_defconfig create mode 100644 arch/arm/configs/bcmrpi_defconfig create mode 100644 arch/arm/configs/bcmrpi_emergency_defconfig @@ -97,10 +97,10 @@ Signed-off-by: popcornmix create mode 100644 drivers/mmc/host/sdhci-bcm2708.c diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 47085a0..99605f2 100644 +index 1594945..14252d3 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -373,6 +373,22 @@ config ARCH_AT91 +@@ -379,6 +379,22 @@ config ARCH_AT91 This enables support for systems based on Atmel AT91RM9200 and AT91SAM9* processors. @@ -123,7 +123,7 @@ index 47085a0..99605f2 100644 config ARCH_CLPS711X bool "Cirrus Logic CLPS711x/EP721x/EP731x-based" select ARCH_REQUIRE_GPIOLIB -@@ -1020,6 +1036,7 @@ source "arch/arm/mach-virt/Kconfig" +@@ -1053,6 +1069,7 @@ source "arch/arm/mach-virt/Kconfig" source "arch/arm/mach-vt8500/Kconfig" source "arch/arm/mach-w90x900/Kconfig" @@ -132,10 +132,10 @@ index 47085a0..99605f2 100644 source "arch/arm/mach-zynq/Kconfig" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug -index 5765abf..313f96d 100644 +index 0531da8..117fb79 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug -@@ -882,6 +882,14 @@ choice +@@ -920,6 +920,14 @@ choice options; the platform specific options are deprecated and will be soon removed. @@ -151,17 +151,17 @@ index 5765abf..313f96d 100644 config DEBUG_EXYNOS_UART diff --git a/arch/arm/Makefile b/arch/arm/Makefile -index c99b108..14e15c1 100644 +index 08a9ef5..755e9c2 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile -@@ -147,6 +147,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 +@@ -143,6 +143,7 @@ textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000 # by CONFIG_* macro name. machine-$(CONFIG_ARCH_AT91) += at91 machine-$(CONFIG_ARCH_BCM) += bcm +machine-$(CONFIG_ARCH_BCM2708) += bcm2708 machine-$(CONFIG_ARCH_BCM2835) += bcm2835 + machine-$(CONFIG_ARCH_BERLIN) += berlin machine-$(CONFIG_ARCH_CLPS711X) += clps711x - machine-$(CONFIG_ARCH_CNS3XXX) += cns3xxx diff --git a/arch/arm/configs/bcmrpi_cutdown_defconfig b/arch/arm/configs/bcmrpi_cutdown_defconfig new file mode 100644 index 0000000..74f2dc9 @@ -2028,10 +2028,10 @@ index 0000000..0aa916e +#endif diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c new file mode 100644 -index 0000000..2d4b548 +index 0000000..2aa15f6 --- /dev/null +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -0,0 +1,711 @@ +@@ -0,0 +1,717 @@ +/* + * linux/arch/arm/mach-bcm2708/bcm2708.c + * @@ -2112,6 +2112,8 @@ index 0000000..2d4b548 +/* 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 void __init bcm2708_init_led(void); @@ -2703,7 +2705,9 @@ index 0000000..2d4b548 + +static void __init bcm2708_init_led(void) +{ -+ platform_device_register(&bcm2708_led_device); ++ bcm2708_leds[0].gpio = disk_led_gpio; ++ bcm2708_leds[0].active_low = disk_led_active_low; ++ platform_device_register(&bcm2708_led_device); +} +#else +static inline void bcm2708_init_led(void) @@ -2742,6 +2746,8 @@ index 0000000..2d4b548 +module_param(boardrev, uint, 0644); +module_param(serial, uint, 0644); +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); diff --git a/arch/arm/mach-bcm2708/bcm2708.h b/arch/arm/mach-bcm2708/bcm2708.h new file mode 100644 @@ -2800,10 +2806,10 @@ index 0000000..e339a93 +#endif diff --git a/arch/arm/mach-bcm2708/bcm2708_gpio.c b/arch/arm/mach-bcm2708/bcm2708_gpio.c new file mode 100644 -index 0000000..d0339eb +index 0000000..bab8a49 --- /dev/null +++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c -@@ -0,0 +1,339 @@ +@@ -0,0 +1,361 @@ +/* + * linux/arch/arm/mach-bcm2708/bcm2708_gpio.c + * @@ -2864,6 +2870,8 @@ index 0000000..d0339eb + struct gpio_chip gc; + unsigned long rising; + unsigned long falling; ++ unsigned long high; ++ unsigned long low; +}; + +static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset, @@ -2951,20 +2959,22 @@ index 0000000..d0339eb + unsigned irq = d->irq; + struct bcm2708_gpio *gpio = irq_get_chip_data(irq); + -+ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) ++ gpio->rising &= ~(1 << irq_to_gpio(irq)); ++ gpio->falling &= ~(1 << irq_to_gpio(irq)); ++ gpio->high &= ~(1 << irq_to_gpio(irq)); ++ gpio->low &= ~(1 << irq_to_gpio(irq)); ++ ++ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) + return -EINVAL; + -+ if (type & IRQ_TYPE_EDGE_RISING) { ++ if (type & IRQ_TYPE_EDGE_RISING) + gpio->rising |= (1 << irq_to_gpio(irq)); -+ } else { -+ gpio->rising &= ~(1 << irq_to_gpio(irq)); -+ } -+ -+ if (type & IRQ_TYPE_EDGE_FALLING) { ++ if (type & IRQ_TYPE_EDGE_FALLING) + gpio->falling |= (1 << irq_to_gpio(irq)); -+ } else { -+ gpio->falling &= ~(1 << irq_to_gpio(irq)); -+ } ++ if (type & IRQ_TYPE_LEVEL_HIGH) ++ gpio->high |= (1 << irq_to_gpio(irq)); ++ if (type & IRQ_TYPE_LEVEL_LOW) ++ gpio->low |= (1 << irq_to_gpio(irq)); + return 0; +} + @@ -2974,13 +2984,17 @@ index 0000000..d0339eb + struct bcm2708_gpio *gpio = irq_get_chip_data(irq); + unsigned gn = irq_to_gpio(irq); + unsigned gb = gn / 32; -+ unsigned long rising = readl(gpio->base + GPIOREN(gb)); ++ unsigned long rising = readl(gpio->base + GPIOREN(gb)); + unsigned long falling = readl(gpio->base + GPIOFEN(gb)); ++ unsigned long high = readl(gpio->base + GPIOHEN(gb)); ++ unsigned long low = readl(gpio->base + GPIOLEN(gb)); + + gn = gn % 32; + -+ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); ++ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); + writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); ++ writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); ++ writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); +} + +static void bcm2708_gpio_irq_unmask(struct irq_data *d) @@ -2989,24 +3003,38 @@ index 0000000..d0339eb + struct bcm2708_gpio *gpio = irq_get_chip_data(irq); + unsigned gn = irq_to_gpio(irq); + unsigned gb = gn / 32; -+ unsigned long rising = readl(gpio->base + GPIOREN(gb)); ++ unsigned long rising = readl(gpio->base + GPIOREN(gb)); + unsigned long falling = readl(gpio->base + GPIOFEN(gb)); ++ unsigned long high = readl(gpio->base + GPIOHEN(gb)); ++ unsigned long low = readl(gpio->base + GPIOLEN(gb)); + + gn = gn % 32; + + writel(1 << gn, gpio->base + GPIOEDS(gb)); + + if (gpio->rising & (1 << gn)) { -+ writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); ++ writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); + } else { + writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); + } + + if (gpio->falling & (1 << gn)) { -+ writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); ++ writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); + } else { + writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); + } ++ ++ if (gpio->high & (1 << gn)) { ++ writel(high | (1 << gn), gpio->base + GPIOHEN(gb)); ++ } else { ++ writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); ++ } ++ ++ if (gpio->low & (1 << gn)) { ++ writel(low | (1 << gn), gpio->base + GPIOLEN(gb)); ++ } else { ++ writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); ++ } +} + +static struct irq_chip bcm2708_irqchip = { @@ -4151,7 +4179,7 @@ index 0000000..04b37a8 +#endif diff --git a/arch/arm/mach-bcm2708/include/mach/debug-macro.S b/arch/arm/mach-bcm2708/include/mach/debug-macro.S new file mode 100644 -index 0000000..2d0dc1c +index 0000000..b24304a --- /dev/null +++ b/arch/arm/mach-bcm2708/include/mach/debug-macro.S @@ -0,0 +1,22 @@ @@ -4176,7 +4204,7 @@ index 0000000..2d0dc1c + ldr \rv, =IO_ADDRESS(UART0_BASE) + .endm + -+#include ++#include diff --git a/arch/arm/mach-bcm2708/include/mach/dma.h b/arch/arm/mach-bcm2708/include/mach/dma.h new file mode 100644 index 0000000..ac7a4a0 @@ -6549,10 +6577,10 @@ index a10297d..c9ddd87 100644 ics_if_voip MACH_ICS_IF_VOIP ICS_IF_VOIP 3206 wlf_cragg_6410 MACH_WLF_CRAGG_6410 WLF_CRAGG_6410 3207 diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig -index 7fc5099..97cb760 100644 +index 1384f67..bad4c9b 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig -@@ -260,6 +260,27 @@ config MMC_SDHCI_BCM_KONA +@@ -272,6 +272,27 @@ config MMC_SDHCI_BCM_KONA If you have a controller with this interface, say Y or M here. @@ -6581,10 +6609,10 @@ index 7fc5099..97cb760 100644 tristate "SDHCI platform support for the BCM2835 SD/MMC Controller" depends on ARCH_BCM2835 diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile -index c41d0c3..656dfa1 100644 +index 3483b6b..11460d7 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile -@@ -15,6 +15,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o +@@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o @@ -8023,7 +8051,7 @@ index 0000000..d8ef77c +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 3c71920..3cd62f2 100644 +index 9ddef47..b78afa2 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -28,6 +28,7 @@ @@ -8194,7 +8222,7 @@ index 3c71920..3cd62f2 100644 sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); } -@@ -920,7 +918,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, +@@ -925,7 +923,8 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, if (data->flags & MMC_DATA_READ) mode |= SDHCI_TRNS_READ; @@ -8204,7 +8232,7 @@ index 3c71920..3cd62f2 100644 mode |= SDHCI_TRNS_DMA; sdhci_writew(host, mode, SDHCI_TRANSFER_MODE); -@@ -936,13 +935,16 @@ static void sdhci_finish_data(struct sdhci_host *host) +@@ -941,13 +940,16 @@ static void sdhci_finish_data(struct sdhci_host *host) host->data = NULL; if (host->flags & SDHCI_REQ_USE_DMA) { @@ -8225,7 +8253,7 @@ index 3c71920..3cd62f2 100644 } /* -@@ -995,6 +997,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +@@ -1000,6 +1002,12 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY)) mask |= SDHCI_DATA_INHIBIT; @@ -8238,14 +8266,17 @@ index 3c71920..3cd62f2 100644 /* We shouldn't wait for data inihibit for stop commands, even though they might use busy signaling */ if (host->mrq->data && (cmd == host->mrq->data->stop)) -@@ -1012,10 +1020,16 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +@@ -1017,6 +1025,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) timeout--; mdelay(1); } + DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask, + sdhci_readl(host, SDHCI_INT_STATUS)); - mod_timer(&host->timer, jiffies + 10 * HZ); + timeout = jiffies; + if (!cmd->data && cmd->cmd_timeout_ms > 9000) +@@ -1026,6 +1036,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) + mod_timer(&host->timer, timeout); host->cmd = cmd; + if (host->last_cmdop == MMC_APP_CMD) @@ -8255,7 +8286,7 @@ index 3c71920..3cd62f2 100644 sdhci_prepare_data(host, cmd); -@@ -1488,7 +1502,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +@@ -1505,7 +1519,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) else ctrl &= ~SDHCI_CTRL_HISPD; @@ -8264,7 +8295,7 @@ index 3c71920..3cd62f2 100644 u16 clk, ctrl_2; /* In case of UHS-I modes, set High Speed Enable */ -@@ -2187,7 +2201,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2204,7 +2218,7 @@ static void sdhci_timeout_timer(unsigned long data) if (host->mrq) { pr_err("%s: Timeout waiting for hardware " @@ -8273,7 +8304,7 @@ index 3c71920..3cd62f2 100644 sdhci_dumpregs(host); if (host->data) { -@@ -2232,10 +2246,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) +@@ -2249,10 +2263,13 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { @@ -8287,7 +8318,7 @@ index 3c71920..3cd62f2 100644 return; } -@@ -2305,6 +2322,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) +@@ -2322,6 +2339,19 @@ static void sdhci_show_adma_error(struct sdhci_host *host) static void sdhci_show_adma_error(struct sdhci_host *host) { } #endif @@ -8307,7 +8338,7 @@ index 3c71920..3cd62f2 100644 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) { u32 command; -@@ -2334,23 +2364,39 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2351,23 +2381,39 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) } } @@ -8351,7 +8382,7 @@ index 3c71920..3cd62f2 100644 pr_err("%s: ADMA error\n", mmc_hostname(host->mmc)); sdhci_show_adma_error(host); host->data->error = -EIO; -@@ -2358,11 +2404,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2375,11 +2421,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->ops->adma_workaround(host, intmask); } @@ -8374,7 +8405,7 @@ index 3c71920..3cd62f2 100644 /* * We currently don't do anything fancy with DMA -@@ -2391,18 +2444,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) +@@ -2408,18 +2461,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) sdhci_writel(host, dmanow, SDHCI_DMA_ADDRESS); } @@ -8395,7 +8426,7 @@ index 3c71920..3cd62f2 100644 } } -@@ -2458,6 +2501,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2475,6 +2518,22 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) tasklet_schedule(&host->card_tasklet); } @@ -8418,7 +8449,7 @@ index 3c71920..3cd62f2 100644 if (intmask & SDHCI_INT_CMD_MASK) { sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK, SDHCI_INT_STATUS); -@@ -2472,7 +2531,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2489,7 +2548,13 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK); @@ -8433,7 +8464,7 @@ index 3c71920..3cd62f2 100644 if (intmask & SDHCI_INT_BUS_POWER) { pr_err("%s: Card is consuming too much power!\n", -@@ -2585,7 +2650,8 @@ int sdhci_resume_host(struct sdhci_host *host) +@@ -2602,7 +2667,8 @@ int sdhci_resume_host(struct sdhci_host *host) { int ret = 0; @@ -8443,7 +8474,7 @@ index 3c71920..3cd62f2 100644 if (host->ops->enable_dma) host->ops->enable_dma(host); } -@@ -2816,14 +2882,16 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -2833,14 +2899,16 @@ int sdhci_add_host(struct sdhci_host *host) host->flags &= ~SDHCI_USE_ADMA; } @@ -8462,7 +8493,7 @@ index 3c71920..3cd62f2 100644 } } } -@@ -3249,6 +3317,7 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -3266,6 +3334,7 @@ int sdhci_add_host(struct sdhci_host *host) pr_info("%s: SDHCI controller on %s [%s] using %s\n", mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), @@ -8526,7 +8557,7 @@ index 0a3ed01..6857875 100644 extern int sdhci_runtime_suspend_host(struct sdhci_host *host); extern int sdhci_runtime_resume_host(struct sdhci_host *host); diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index a0dfb86..b93df06 100644 +index d58783d..4f7dbb2 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -84,7 +84,7 @@ struct vendor_data { @@ -8562,10 +8593,10 @@ index 362927c4..e23fffb 100644 1.8.5.5 -From 7a13d7edb47f433fb1733853bb43e0f3386e61c5 Mon Sep 17 00:00:00 2001 +From 7efa2f27f5f930c10bed164474c672c05b6bf04c Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 7 May 2013 22:20:24 +0100 -Subject: [PATCH 002/118] Add quick config. +Subject: [PATCH 02/99] Add quick config. This is designed for quick compiling when developing. No modules are needed and it includes all Pi specific drivers @@ -8781,10 +8812,10 @@ index 0000000..e5efe75 1.8.5.5 -From 0cba8b7abbde7612778e91df5f45d4b3f2a983ce Mon Sep 17 00:00:00 2001 +From a6b43555e61c258257494af635a054d96190ba24 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 003/118] Add dwc_otg driver +Subject: [PATCH 03/99] Add dwc_otg driver Signed-off-by: popcornmix --- @@ -8913,10 +8944,10 @@ Signed-off-by: popcornmix create mode 100644 drivers/usb/host/dwc_otg/test/test_sysfs.pl diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 70d7c5b..df8834b 100644 +index 1ae2bf3..c4a45aa 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile -@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/ +@@ -24,6 +24,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/ obj-$(CONFIG_USB_ISP1760_HCD) += host/ @@ -8937,10 +8968,10 @@ index acbfeb0..7d675c8 100644 return i; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index bb31597..5449ad7 100644 +index f829a1a..4a44ae7 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c -@@ -1889,6 +1889,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) +@@ -1888,6 +1888,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) if (cp->string == NULL && !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); @@ -12947,10 +12978,10 @@ index a9707da..e252b95 100644 tristate "i.MX21 HCD support" depends on ARM && ARCH_MXC diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 01e879e..71d40d3 100644 +index 7530468..876f024 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile -@@ -65,6 +65,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o +@@ -63,6 +63,8 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o @@ -12961,7 +12992,7 @@ index 01e879e..71d40d3 100644 obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile new file mode 100644 -index 0000000..b2136bc0 +index 0000000..f10d466 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/Makefile @@ -0,0 +1,58 @@ @@ -12971,16 +13002,16 @@ index 0000000..b2136bc0 + +ifneq ($(KERNELRELEASE),) + -+EXTRA_CFLAGS += -DDWC_LINUX -+#EXTRA_CFLAGS += -DDEBUG -+#EXTRA_CFLAGS += -DDWC_DEBUG_REGS -+#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY ++ccflags-y += -DDWC_LINUX ++#ccflags-y += -DDEBUG ++#ccflags-y += -DDWC_DEBUG_REGS ++#ccflags-y += -DDWC_DEBUG_MEMORY + -+EXTRA_CFLAGS += -DDWC_LIBMODULE -+EXTRA_CFLAGS += -DDWC_CCLIB -+#EXTRA_CFLAGS += -DDWC_CRYPTOLIB -+EXTRA_CFLAGS += -DDWC_NOTIFYLIB -+EXTRA_CFLAGS += -DDWC_UTFLIB ++ccflags-y += -DDWC_LIBMODULE ++ccflags-y += -DDWC_CCLIB ++#ccflags-y += -DDWC_CRYPTOLIB ++ccflags-y += -DDWC_NOTIFYLIB ++ccflags-y += -DDWC_UTFLIB + +obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ @@ -12991,8 +13022,8 @@ index 0000000..b2136bc0 +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) + +ifneq ($(kernrel3),2.6.20) -+# grayg - I only know that we use EXTRA_CFLAGS in 2.6.31 actually -+EXTRA_CFLAGS += $(CPPFLAGS) ++# grayg - I only know that we use ccflags-y in 2.6.31 actually ++ccflags-y += $(CPPFLAGS) +endif + +else @@ -13048,7 +13079,7 @@ index 0000000..45db991 +.include diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux new file mode 100644 -index 0000000..961df3f +index 0000000..0cef7b4 --- /dev/null +++ b/drivers/usb/host/dwc_common_port/Makefile.linux @@ -0,0 +1,49 @@ @@ -13057,16 +13088,16 @@ index 0000000..961df3f +# +ifneq ($(KERNELRELEASE),) + -+EXTRA_CFLAGS += -DDWC_LINUX -+#EXTRA_CFLAGS += -DDEBUG -+#EXTRA_CFLAGS += -DDWC_DEBUG_REGS -+#EXTRA_CFLAGS += -DDWC_DEBUG_MEMORY ++ccflags-y += -DDWC_LINUX ++#ccflags-y += -DDEBUG ++#ccflags-y += -DDWC_DEBUG_REGS ++#ccflags-y += -DDWC_DEBUG_MEMORY + -+EXTRA_CFLAGS += -DDWC_LIBMODULE -+EXTRA_CFLAGS += -DDWC_CCLIB -+EXTRA_CFLAGS += -DDWC_CRYPTOLIB -+EXTRA_CFLAGS += -DDWC_NOTIFYLIB -+EXTRA_CFLAGS += -DDWC_UTFLIB ++ccflags-y += -DDWC_LIBMODULE ++ccflags-y += -DDWC_CCLIB ++ccflags-y += -DDWC_CRYPTOLIB ++ccflags-y += -DDWC_NOTIFYLIB ++ccflags-y += -DDWC_UTFLIB + +obj-m := dwc_common_port_lib.o +dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ @@ -23393,7 +23424,7 @@ index 0000000..27bda82 +#endif /* _USB_H_ */ diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile new file mode 100644 -index 0000000..5748f7d +index 0000000..236c47c --- /dev/null +++ b/drivers/usb/host/dwc_otg/Makefile @@ -0,0 +1,80 @@ @@ -23411,22 +23442,22 @@ index 0000000..5748f7d + BUS_INTERFACE = -DPLATFORM_INTERFACE +endif + -+#EXTRA_CFLAGS += -DDEBUG -+#EXTRA_CFLAGS += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs ++#ccflags-y += -DDEBUG ++#ccflags-y += -DDWC_OTG_DEBUGLEV=1 # reduce common debug msgs + +# Use one of the following flags to compile the software in host-only or +# device-only mode. -+#EXTRA_CFLAGS += -DDWC_HOST_ONLY -+#EXTRA_CFLAGS += -DDWC_DEVICE_ONLY ++#ccflags-y += -DDWC_HOST_ONLY ++#ccflags-y += -DDWC_DEVICE_ONLY + -+EXTRA_CFLAGS += -Dlinux -DDWC_HS_ELECT_TST -+#EXTRA_CFLAGS += -DDWC_EN_ISOC -+EXTRA_CFLAGS += -I$(obj)/../dwc_common_port -+#EXTRA_CFLAGS += -I$(PORTLIB) -+EXTRA_CFLAGS += -DDWC_LINUX -+EXTRA_CFLAGS += $(CFI) -+EXTRA_CFLAGS += $(BUS_INTERFACE) -+#EXTRA_CFLAGS += -DDWC_DEV_SRPCAP ++ccflags-y += -Dlinux -DDWC_HS_ELECT_TST ++#ccflags-y += -DDWC_EN_ISOC ++ccflags-y += -I$(obj)/../dwc_common_port ++#ccflags-y += -I$(PORTLIB) ++ccflags-y += -DDWC_LINUX ++ccflags-y += $(CFI) ++ccflags-y += $(BUS_INTERFACE) ++#ccflags-y += -DDWC_DEV_SRPCAP + +obj-$(CONFIG_USB_DWCOTG) += dwc_otg.o + @@ -23443,7 +23474,7 @@ index 0000000..5748f7d +kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) + +ifneq ($(kernrel3),2.6.20) -+EXTRA_CFLAGS += $(CPPFLAGS) ++ccflags-y += $(CPPFLAGS) +endif + +else @@ -40932,7 +40963,7 @@ index 0000000..8900318 +#endif diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c new file mode 100644 -index 0000000..dcfbd66 +index 0000000..ac2c846 --- /dev/null +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c @@ -0,0 +1,1700 @@ @@ -41164,7 +41195,7 @@ index 0000000..dcfbd66 + .rx_thr_length = -1, + .pti_enable = -1, + .mpi_enable = -1, -+ .lpm_enable = -1, ++ .lpm_enable = 0, + .ic_usb_cap = -1, + .ahb_thr_ratio = -1, + .power_down = -1, @@ -65856,10 +65887,10 @@ index 0000000..cdc9963 1.8.5.5 -From 8086eaa83b8775d04fabf882b8f1545337262c2c Mon Sep 17 00:00:00 2001 +From 3046bec13238fe2eed0de383199b8be25f2b71a6 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:54:32 +0100 -Subject: [PATCH 004/118] bcm2708 watchdog driver +Subject: [PATCH 04/99] bcm2708 watchdog driver Signed-off-by: popcornmix --- @@ -65870,10 +65901,10 @@ Signed-off-by: popcornmix create mode 100644 drivers/watchdog/bcm2708_wdog.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig -index 5be6e91..dd7fe73 100644 +index 79d2589..3641dbd 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig -@@ -392,6 +392,12 @@ config RETU_WATCHDOG +@@ -402,6 +402,12 @@ config RETU_WATCHDOG To compile this driver as a module, choose M here: the module will be called retu_wdt. @@ -65887,7 +65918,7 @@ index 5be6e91..dd7fe73 100644 tristate "MOXART watchdog" depends on ARCH_MOXART diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile -index 91bd95a..c22a199 100644 +index 985a66c..f68e32c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o @@ -66292,22 +66323,22 @@ index 0000000..2f19203 1.8.5.5 -From 18c3c0ec43007d771d2959c8b5305735b2fef695 Mon Sep 17 00:00:00 2001 +From 38b9e8eb11a75a3953e6e1b6003258d439cd8d6b Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 1 May 2013 19:55:09 +0100 -Subject: [PATCH 005/118] bcm2708 framebuffer driver +Subject: [PATCH 05/99] bcm2708 framebuffer driver Signed-off-by: popcornmix --- drivers/video/Kconfig | 14 + drivers/video/Makefile | 1 + - drivers/video/bcm2708_fb.c | 491 ++++++ + drivers/video/bcm2708_fb.c | 499 ++++++ drivers/video/logo/logo_linux_clut224.ppm | 2483 ++++++++++------------------- - 4 files changed, 1387 insertions(+), 1602 deletions(-) + 4 files changed, 1395 insertions(+), 1602 deletions(-) create mode 100644 drivers/video/bcm2708_fb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig -index 4f2e1b3..b41c7b8 100644 +index dade5b7..4afc29b 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -310,6 +310,20 @@ config FB_PM2_FIFO_DISCONNECT @@ -66330,9 +66361,9 @@ index 4f2e1b3..b41c7b8 100644 + config FB_ARMCLCD tristate "ARM PrimeCell PL110 support" - depends on FB && ARM && ARM_AMBA + depends on ARM || ARM64 || COMPILE_TEST diff --git a/drivers/video/Makefile b/drivers/video/Makefile -index e8bae8d..032f386 100644 +index ae17ddf..35654ba 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_FB_PVR2) += pvr2fb.o @@ -66345,10 +66376,10 @@ index e8bae8d..032f386 100644 obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c new file mode 100644 -index 0000000..08d9238 +index 0000000..54cd760 --- /dev/null +++ b/drivers/video/bcm2708_fb.c -@@ -0,0 +1,491 @@ +@@ -0,0 +1,499 @@ +/* + * linux/drivers/video/bcm2708_fb.c + * @@ -66397,6 +66428,11 @@ index 0000000..08d9238 + +#define DRIVER_NAME "bcm2708_fb" + ++static int fbwidth = 800; /* module parameter */ ++static int fbheight = 480; /* module parameter */ ++static int fbdepth = 16; /* module parameter */ ++static int fbswap = 0; /* module parameter */ ++ +/* this data structure describes each frame buffer device we find */ + +struct fbinfo_s { @@ -66471,7 +66507,12 @@ index 0000000..08d9238 + * encoded in the pixel data. Calculate their position from + * the bitfield length defined above. + */ -+ if (ret == 0 && var->bits_per_pixel >= 24) { ++ if (ret == 0 && var->bits_per_pixel >= 24 && fbswap) { ++ var->blue.offset = 0; ++ var->green.offset = var->blue.offset + var->blue.length; ++ var->red.offset = var->green.offset + var->green.length; ++ var->transp.offset = var->red.offset + var->red.length; ++ } else if (ret == 0 && var->bits_per_pixel >= 24) { + var->red.offset = 0; + var->green.offset = var->red.offset + var->red.length; + var->blue.offset = var->green.offset + var->green.length; @@ -66541,8 +66582,8 @@ index 0000000..08d9238 + else if (var->vmode & FB_VMODE_INTERLACED) + yres = (yres + 1) / 2; + -+ if (yres > 1200) { -+ pr_err("bcm2708_fb_check_var: ERROR: VerticalTotal >= 1200; " ++ if (var->xres * yres > 1920 * 1200) { ++ pr_err("bcm2708_fb_check_var: ERROR: Pixel size >= 1920x1200; " + "special treatment required! (TODO)\n"); + return -EINVAL; + } @@ -66688,10 +66729,6 @@ index 0000000..08d9238 + .fb_imageblit = bcm2708_fb_imageblit, +}; + -+static int fbwidth = 800; /* module parameter */ -+static int fbheight = 480; /* module parameter */ -+static int fbdepth = 16; /* module parameter */ -+ +static int bcm2708_fb_register(struct bcm2708_fb *fb) +{ + int ret; @@ -66748,8 +66785,8 @@ index 0000000..08d9238 + + fb_set_var(&fb->fb, &fb->fb.var); + -+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d)\n", fbwidth, -+ fbheight, fbdepth); ++ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth ++ fbheight, fbdepth, fbswap); + + ret = register_framebuffer(&fb->fb); + print_debug("BCM2708FB: register framebuffer (%d)\n", ret); @@ -66833,6 +66870,7 @@ index 0000000..08d9238 +module_param(fbwidth, int, 0644); +module_param(fbheight, int, 0644); +module_param(fbdepth, int, 0644); ++module_param(fbswap, int, 0644); + +MODULE_DESCRIPTION("BCM2708 framebuffer driver"); +MODULE_LICENSE("GPL"); @@ -66840,6 +66878,7 @@ index 0000000..08d9238 +MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer"); +MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer"); +MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer"); ++MODULE_PARM_DESC(fbswap, "Swap order of red and blue in 24 and 32 bit modes"); diff --git a/drivers/video/logo/logo_linux_clut224.ppm b/drivers/video/logo/logo_linux_clut224.ppm index 3c14e43..7626beb 100644 --- a/drivers/video/logo/logo_linux_clut224.ppm @@ -69334,12 +69373,24 @@ index 3c14e43..7626beb 100644 1.8.5.5 -From ea589c3d2b47930a2e9de46114746e75a6bf294b Mon Sep 17 00:00:00 2001 +From 361c55ff6ff6accb1c7d5bb1c75f2ddd54ff4d54 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 2 Jul 2013 23:42:01 +0100 -Subject: [PATCH 006/118] bcm2708 vchiq driver +Subject: [PATCH 06/99] bcm2708 vchiq driver Signed-off-by: popcornmix + +vchiq: create_pagelist copes with vmalloc memory + +Signed-off-by: Daniel Stone + +vchiq: fix the shim message release + +Signed-off-by: Daniel Stone + +vchiq: export additional symbols + +Signed-off-by: Daniel Stone --- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + @@ -69354,7 +69405,7 @@ Signed-off-by: popcornmix .../misc/vc04_services/interface/vchi/vchi_mh.h | 42 + .../misc/vc04_services/interface/vchiq_arm/vchiq.h | 40 + .../vc04_services/interface/vchiq_arm/vchiq_2835.h | 42 + - .../interface/vchiq_arm/vchiq_2835_arm.c | 538 +++ + .../interface/vchiq_arm/vchiq_2835_arm.c | 561 +++ .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 2813 ++++++++++++++ .../vc04_services/interface/vchiq_arm/vchiq_arm.h | 212 ++ .../interface/vchiq_arm/vchiq_build_info.h | 37 + @@ -69370,11 +69421,11 @@ Signed-off-by: popcornmix .../interface/vchiq_arm/vchiq_memdrv.h | 71 + .../interface/vchiq_arm/vchiq_pagelist.h | 58 + .../vc04_services/interface/vchiq_arm/vchiq_proc.c | 253 ++ - .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 815 +++++ + .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 828 +++++ .../vc04_services/interface/vchiq_arm/vchiq_util.c | 151 + .../vc04_services/interface/vchiq_arm/vchiq_util.h | 81 + .../interface/vchiq_arm/vchiq_version.c | 59 + - 33 files changed, 12222 insertions(+) + 33 files changed, 12258 insertions(+) create mode 100644 drivers/misc/vc04_services/Kconfig create mode 100644 drivers/misc/vc04_services/Makefile create mode 100644 drivers/misc/vc04_services/interface/vchi/connections/connection.h @@ -69408,26 +69459,28 @@ Signed-off-by: popcornmix create mode 100644 drivers/misc/vc04_services/interface/vchiq_arm/vchiq_version.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig -index a3e291d..f6745bb 100644 +index 6cb388e..56867fa 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig -@@ -524,5 +524,6 @@ source "drivers/misc/carma/Kconfig" +@@ -524,6 +524,7 @@ source "drivers/misc/carma/Kconfig" source "drivers/misc/altera-stapl/Kconfig" source "drivers/misc/mei/Kconfig" source "drivers/misc/vmw_vmci/Kconfig" +source "drivers/misc/vc04_services/Kconfig" source "drivers/misc/mic/Kconfig" + source "drivers/misc/genwqe/Kconfig" endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index f45473e..a81bc2e 100644 +index 99b9424..ad85616 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -52,4 +52,5 @@ obj-$(CONFIG_INTEL_MEI) += mei/ +@@ -52,5 +52,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o +obj-y += vc04_services/ obj-y += mic/ + obj-$(CONFIG_GENWQE) += genwqe/ diff --git a/drivers/misc/vc04_services/Kconfig b/drivers/misc/vc04_services/Kconfig new file mode 100644 index 0000000..2663933 @@ -69445,7 +69498,7 @@ index 0000000..2663933 + are included in the build, N otherwise. diff --git a/drivers/misc/vc04_services/Makefile b/drivers/misc/vc04_services/Makefile new file mode 100644 -index 0000000..eed2a9c +index 0000000..4224f58 --- /dev/null +++ b/drivers/misc/vc04_services/Makefile @@ -0,0 +1,17 @@ @@ -69463,7 +69516,7 @@ index 0000000..eed2a9c + interface/vchiq_arm/vchiq_util.o \ + interface/vchiq_arm/vchiq_connected.o \ + -+EXTRA_CFLAGS += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 ++ccflags-y += -DVCOS_VERIFY_BKPTS=1 -Idrivers/misc/vc04_services -DUSE_VCHIQ_ARM -D__VCCOREVER__=0x04000000 + +endif diff --git a/drivers/misc/vc04_services/interface/vchi/connections/connection.h b/drivers/misc/vc04_services/interface/vchi/connections/connection.h @@ -71009,10 +71062,10 @@ index 0000000..7ea5c64 +#endif /* VCHIQ_2835_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 new file mode 100644 -index 0000000..2b5fa56 +index 0000000..b3bdaa2 --- /dev/null +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c -@@ -0,0 +1,538 @@ +@@ -0,0 +1,561 @@ +/** + * Copyright (c) 2010-2012 Broadcom. All rights reserved. + * @@ -71389,6 +71442,7 @@ index 0000000..2b5fa56 + unsigned int num_pages, offset, i; + char *addr, *base_addr, *next_addr; + int run, addridx, actual_pages; ++ unsigned long *need_release; + + offset = (unsigned int)buf & (PAGE_SIZE - 1); + num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE; @@ -71399,9 +71453,10 @@ index 0000000..2b5fa56 + ** list + */ + pagelist = kmalloc(sizeof(PAGELIST_T) + -+ (num_pages * sizeof(unsigned long)) + -+ (num_pages * sizeof(pages[0])), -+ GFP_KERNEL); ++ (num_pages * sizeof(unsigned long)) + ++ sizeof(unsigned long) + ++ (num_pages * sizeof(pages[0])), ++ GFP_KERNEL); + + vchiq_log_trace(vchiq_arm_log_level, + "create_pagelist - %x", (unsigned int)pagelist); @@ -71409,28 +71464,44 @@ index 0000000..2b5fa56 + return -ENOMEM; + + addrs = pagelist->addrs; -+ pages = (struct page **)(addrs + num_pages); ++ need_release = (unsigned long *)(addrs + num_pages); ++ pages = (struct page **)(addrs + num_pages + 1); + -+ down_read(&task->mm->mmap_sem); -+ actual_pages = get_user_pages(task, task->mm, -+ (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages, -+ (type == PAGELIST_READ) /*Write */ , 0 /*Force */ , -+ pages, NULL /*vmas */); -+ up_read(&task->mm->mmap_sem); ++ if (is_vmalloc_addr(buf)) { ++ for (actual_pages = 0; actual_pages < num_pages; actual_pages++) { ++ pages[actual_pages] = vmalloc_to_page(buf + (actual_pages * PAGE_SIZE)); ++ } ++ *need_release = 0; /* do not try and release vmalloc pages */ ++ } else { ++ down_read(&task->mm->mmap_sem); ++ actual_pages = get_user_pages(task, task->mm, ++ (unsigned long)buf & ~(PAGE_SIZE - 1), ++ num_pages, ++ (type == PAGELIST_READ) /*Write */ , ++ 0 /*Force */ , ++ pages, ++ NULL /*vmas */); ++ up_read(&task->mm->mmap_sem); + -+ if (actual_pages != num_pages) -+ { -+ /* This is probably due to the process being killed */ -+ while (actual_pages > 0) -+ { -+ actual_pages--; -+ page_cache_release(pages[actual_pages]); -+ } -+ kfree(pagelist); -+ if (actual_pages == 0) -+ actual_pages = -ENOMEM; -+ return actual_pages; -+ } ++ if (actual_pages != num_pages) { ++ vchiq_log_info(vchiq_arm_log_level, ++ "create_pagelist - only %d/%d pages locked", ++ actual_pages, ++ num_pages); ++ ++ /* This is probably due to the process being killed */ ++ while (actual_pages > 0) ++ { ++ actual_pages--; ++ page_cache_release(pages[actual_pages]); ++ } ++ kfree(pagelist); ++ if (actual_pages == 0) ++ actual_pages = -ENOMEM; ++ return actual_pages; ++ } ++ *need_release = 1; /* release user pages */ ++ } + + pagelist->length = count; + pagelist->type = type; @@ -71497,6 +71568,7 @@ index 0000000..2b5fa56 +static void +free_pagelist(PAGELIST_T *pagelist, int actual) +{ ++ unsigned long *need_release; + struct page **pages; + unsigned int num_pages, i; + @@ -71507,7 +71579,8 @@ index 0000000..2b5fa56 + (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / + PAGE_SIZE; + -+ pages = (struct page **)(pagelist->addrs + num_pages); ++ need_release = (unsigned long *)(pagelist->addrs + num_pages); ++ pages = (struct page **)(pagelist->addrs + num_pages + 1); + + /* Deal with any partial cache lines (fragments) */ + if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) { @@ -71543,11 +71616,14 @@ index 0000000..2b5fa56 + up(&g_free_fragments_sema); + } + -+ for (i = 0; i < num_pages; i++) { -+ if (pagelist->type != PAGELIST_WRITE) -+ set_page_dirty(pages[i]); -+ page_cache_release(pages[i]); -+ } ++ if (*need_release) { ++ for (i = 0; i < num_pages; i++) { ++ if (pagelist->type != PAGELIST_WRITE) ++ set_page_dirty(pages[i]); ++ ++ page_cache_release(pages[i]); ++ } ++ } + + kfree(pagelist); +} @@ -80706,10 +80782,10 @@ index 0000000..8e59676 +#endif diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c new file mode 100644 -index 0000000..f752f8d +index 0000000..a0b069d --- /dev/null +++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -@@ -0,0 +1,815 @@ +@@ -0,0 +1,828 @@ +/** + * Copyright (c) 2010-2012 Broadcom. All rights reserved. + * @@ -81117,6 +81193,7 @@ index 0000000..f752f8d + + return 0; +} ++EXPORT_SYMBOL(vchi_held_msg_release); + +/*********************************************************** + * Name: vchi_msg_hold @@ -81162,6 +81239,7 @@ index 0000000..f752f8d + + return 0; +} ++EXPORT_SYMBOL(vchi_msg_hold); + +/*********************************************************** + * Name: vchi_initialise @@ -81257,47 +81335,58 @@ index 0000000..f752f8d + SHIM_SERVICE_T *service = + (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); + ++ if (!service->callback) ++ goto release; ++ + switch (reason) { + case VCHIQ_MESSAGE_AVAILABLE: + vchiu_queue_push(&service->queue, header); + -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_MSG_AVAILABLE, NULL); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_MSG_AVAILABLE, NULL); ++ ++ goto done; + break; ++ + case VCHIQ_BULK_TRANSMIT_DONE: -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_SENT, bulk_user); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_BULK_SENT, bulk_user); + break; ++ + case VCHIQ_BULK_RECEIVE_DONE: -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_RECEIVED, bulk_user); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_BULK_RECEIVED, bulk_user); + break; ++ + case VCHIQ_SERVICE_CLOSED: -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_SERVICE_CLOSED, NULL); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_SERVICE_CLOSED, NULL); + break; ++ + case VCHIQ_SERVICE_OPENED: + /* No equivalent VCHI reason */ + break; ++ + case VCHIQ_BULK_TRANSMIT_ABORTED: -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, ++ bulk_user); + break; ++ + case VCHIQ_BULK_RECEIVE_ABORTED: -+ if (service->callback) -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user); ++ service->callback(service->callback_param, ++ VCHI_CALLBACK_BULK_RECEIVE_ABORTED, ++ bulk_user); + break; ++ + default: + WARN(1, "not supported\n"); + break; + } + ++release: ++ vchiq_release_message(service->handle, header); ++done: + return VCHIQ_SUCCESS; +} + @@ -81838,10 +81927,10 @@ index 0000000..b6bfa21 1.8.5.5 -From 0a06a49fa0fca87e169ed3d0e4defe63bad620a5 Mon Sep 17 00:00:00 2001 +From 1e512eca45e669d13cf2ef06607701ab587a4966 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:31:47 +0100 -Subject: [PATCH 007/118] cma: Add vc_cma driver to enable use of CMA +Subject: [PATCH 07/99] cma: Add vc_cma driver to enable use of CMA Signed-off-by: popcornmix --- @@ -81861,10 +81950,10 @@ Signed-off-by: popcornmix create mode 100644 include/linux/broadcom/vc_cma.h diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig -index fa3243d..bb602b8 100644 +index 1386749..fcf51a3 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig -@@ -580,6 +580,8 @@ config DEVPORT +@@ -581,6 +581,8 @@ config DEVPORT source "drivers/s390/char/Kconfig" @@ -81874,10 +81963,10 @@ index fa3243d..bb602b8 100644 bool "Enable device interface for some SMD packet ports" default n diff --git a/drivers/char/Makefile b/drivers/char/Makefile -index 7ff1d0d..fc85f0c 100644 +index a324f93..aef3ed0 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile -@@ -62,3 +62,5 @@ obj-$(CONFIG_JS_RTC) += js-rtc.o +@@ -61,3 +61,5 @@ obj-$(CONFIG_JS_RTC) += js-rtc.o js-rtc-y = rtc.o obj-$(CONFIG_TILE_SROM) += tile-srom.o @@ -81914,20 +82003,20 @@ index 0000000..13c5bca +obj-$(CONFIG_BCM_VC_CMA) += vc_cma/ diff --git a/drivers/char/broadcom/vc_cma/Makefile b/drivers/char/broadcom/vc_cma/Makefile new file mode 100644 -index 0000000..c6fcc37 +index 0000000..6a94de4 --- /dev/null +++ b/drivers/char/broadcom/vc_cma/Makefile @@ -0,0 +1,14 @@ -+EXTRA_CFLAGS += -Wall -Wstrict-prototypes -Wno-trigraphs -+EXTRA_CFLAGS += -Werror -+EXTRA_CFLAGS += -I"include/linux/broadcom" -+EXTRA_CFLAGS += -I"drivers/misc/vc04_services" -+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchi" -+EXTRA_CFLAGS += -I"drivers/misc/vc04_services/interface/vchiq_arm" ++ccflags-y += -Wall -Wstrict-prototypes -Wno-trigraphs ++ccflags-y += -Werror ++ccflags-y += -Iinclude/linux/broadcom ++ccflags-y += -Idrivers/misc/vc04_services ++ccflags-y += -Idrivers/misc/vc04_services/interface/vchi ++ccflags-y += -Idrivers/misc/vc04_services/interface/vchiq_arm + -+EXTRA_CFLAGS += -D__KERNEL__ -+EXTRA_CFLAGS += -D__linux__ -+EXTRA_CFLAGS += -Werror ++ccflags-y += -D__KERNEL__ ++ccflags-y += -D__linux__ ++ccflags-y += -Werror + +obj-$(CONFIG_BCM_VC_CMA) += vc-cma.o + @@ -83082,16 +83171,17 @@ index 0000000..a635f9f +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile -index a81bc2e..40e5af1 100644 +index ad85616..8418ba7 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile -@@ -52,5 +52,5 @@ obj-$(CONFIG_INTEL_MEI) += mei/ +@@ -52,6 +52,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o obj-$(CONFIG_SRAM) += sram.o -obj-y += vc04_services/ +obj-$(CONFIG_BCM2708_VCHIQ) += vc04_services/ obj-y += mic/ + obj-$(CONFIG_GENWQE) += genwqe/ diff --git a/include/linux/broadcom/vc_cma.h b/include/linux/broadcom/vc_cma.h new file mode 100644 index 0000000..5325832 @@ -83131,16 +83221,16 @@ index 0000000..5325832 1.8.5.5 -From acdc48586e5a7650b2ce59e4d24e67c9e4309c1e Mon Sep 17 00:00:00 2001 +From 4a65459237ba2b8ce27f88619f4c8aef0e7b8346 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 26 Mar 2012 22:15:50 +0100 -Subject: [PATCH 008/118] bcm2708: alsa sound driver +Subject: [PATCH 08/99] bcm2708: alsa sound driver Signed-off-by: popcornmix --- arch/arm/configs/bcmrpi_cutdown_defconfig | 20 + arch/arm/configs/bcmrpi_defconfig | 20 + - arch/arm/mach-bcm2708/bcm2708.c | 12 + + arch/arm/mach-bcm2708/bcm2708.c | 54 ++ sound/arm/Kconfig | 7 + sound/arm/Makefile | 5 + sound/arm/bcm2835-ctl.c | 200 +++++++ @@ -83149,7 +83239,7 @@ Subject: [PATCH 008/118] bcm2708: alsa sound driver sound/arm/bcm2835.c | 413 +++++++++++++++ sound/arm/bcm2835.h | 155 ++++++ sound/arm/vc_vchi_audioserv_defs.h | 116 ++++ - 11 files changed, 2201 insertions(+) + 11 files changed, 2243 insertions(+) create mode 100755 sound/arm/bcm2835-ctl.c create mode 100755 sound/arm/bcm2835-pcm.c create mode 100755 sound/arm/bcm2835-vchiq.c @@ -83220,27 +83310,69 @@ index 339aabf..df947e5 100644 CONFIG_USB_HIDDEV=y CONFIG_HID_A4TECH=m diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 2d4b548..db1b7b5 100644 +index 2aa15f6..ac4c11d6 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -429,6 +429,16 @@ struct platform_device bcm2708_powerman_device = { +@@ -431,6 +431,58 @@ struct platform_device bcm2708_powerman_device = { .coherent_dma_mask = 0xffffffffUL}, }; + +static struct platform_device bcm2708_alsa_devices[] = { -+ [0] = { -+ .name = "bcm2835_AUD0", -+ .id = 0, /* first audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, ++ [0] = { ++ .name = "bcm2835_AUD0", ++ .id = 0, /* first audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [1] = { ++ .name = "bcm2835_AUD1", ++ .id = 1, /* second audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [2] = { ++ .name = "bcm2835_AUD2", ++ .id = 2, /* third audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [3] = { ++ .name = "bcm2835_AUD3", ++ .id = 3, /* forth audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [4] = { ++ .name = "bcm2835_AUD4", ++ .id = 4, /* fifth audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [5] = { ++ .name = "bcm2835_AUD5", ++ .id = 5, /* sixth audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [6] = { ++ .name = "bcm2835_AUD6", ++ .id = 6, /* seventh audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, ++ [7] = { ++ .name = "bcm2835_AUD7", ++ .id = 7, /* eighth audio device */ ++ .resource = 0, ++ .num_resources = 0, ++ }, +}; + int __init bcm_register_device(struct platform_device *pdev) { int ret; -@@ -537,6 +547,8 @@ void __init bcm2708_init(void) +@@ -539,6 +591,8 @@ void __init bcm2708_init(void) bcm_register_device(&bcm2708_emmc_device); #endif bcm2708_init_led(); @@ -83267,7 +83399,7 @@ index 885683a..f7ceafd 100644 endif # SND_ARM diff --git a/sound/arm/Makefile b/sound/arm/Makefile -index 8c0c851..1f5ce26 100644 +index 8c0c851..6796d7f 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -14,3 +14,8 @@ snd-pxa2xx-lib-$(CONFIG_SND_PXA2XX_LIB_AC97) += pxa2xx-ac97-lib.o @@ -83278,7 +83410,7 @@ index 8c0c851..1f5ce26 100644 +obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o +snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o + -+EXTRA_CFLAGS += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000 ++ccflags-y += -Idrivers/misc/vc04_services -Idrivers/misc/vc04_services/interface/vcos/linuxkernel -D__VCCOREVER__=0x04000000 diff --git a/sound/arm/bcm2835-ctl.c b/sound/arm/bcm2835-ctl.c new file mode 100755 index 0000000..8c5334a @@ -83487,7 +83619,7 @@ index 0000000..8c5334a +} diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c new file mode 100755 -index 0000000..ef775a4 +index 0000000..b5435fb --- /dev/null +++ b/sound/arm/bcm2835-pcm.c @@ -0,0 +1,409 @@ @@ -83619,7 +83751,6 @@ index 0000000..ef775a4 + alsa_stream->chip = chip; + alsa_stream->substream = substream; + alsa_stream->idx = idx; -+ chip->alsa_stream[idx] = alsa_stream; + + sema_init(&alsa_stream->buffers_update_sem, 0); + sema_init(&alsa_stream->control_sem, 0); @@ -83641,6 +83772,7 @@ index 0000000..ef775a4 + kfree(alsa_stream); + return err; + } ++ chip->alsa_stream[idx] = alsa_stream; + + alsa_stream->open = 1; + alsa_stream->draining = 1; @@ -83902,7 +84034,7 @@ index 0000000..ef775a4 +} diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c new file mode 100755 -index 0000000..9801410 +index 0000000..b9b4fe8 --- /dev/null +++ b/sound/arm/bcm2835-vchiq.c @@ -0,0 +1,844 @@ @@ -84049,7 +84181,7 @@ index 0000000..9801410 + +void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream) +{ -+ alsa_stream->my_wq = create_workqueue("my_queue"); ++ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1); + return; +} + @@ -85456,107 +85588,1422 @@ index 0000000..af3e6eb 1.8.5.5 -From 57834ddba388a4fd93a172543c353ee049325423 Mon Sep 17 00:00:00 2001 +From d90696c8b05f409f82c83d80d8f3e8d4bb3df986 Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 009/118] Allow mac address to be set in smsc95xx +Date: Fri, 26 Apr 2013 10:08:31 -0700 +Subject: [PATCH 09/99] Merge pull request #286 from + martinezjavier/rpi-3.6.y-dev -Signed-off-by: popcornmix +add mmap support and some cleanups to bcm2835 ALSA driver --- - drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 56 insertions(+) + 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/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index 9375b8c..f024562 100644 ---- a/drivers/net/usb/smsc95xx.c -+++ b/drivers/net/usb/smsc95xx.c -@@ -61,6 +61,7 @@ - #define SUSPEND_SUSPEND3 (0x08) - #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \ - SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3) -+#define MAC_ADDR_LEN (6) +diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c +index b5435fb..7f6d75e 100755 +--- a/sound/arm/bcm2835-pcm.c ++++ b/sound/arm/bcm2835-pcm.c +@@ -19,7 +19,8 @@ - struct smsc95xx_priv { - u32 mac_cr; -@@ -76,6 +77,10 @@ struct smsc95xx_priv { - module_param(turbo_mode, bool, 0644); - MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + /* 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) -+static char *macaddr = ":"; -+module_param(macaddr, charp, 0); -+MODULE_PARM_DESC(macaddr, "MAC address"); + audio_info(" .. IN\n"); + ++ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect)); + - static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, - u32 *data, int in_pm) - { -@@ -765,8 +770,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); ++ 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; } -+/* Check the macaddr module parameter for a MAC address */ -+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac) ++static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream, ++ struct snd_pcm_indirect *rec, size_t bytes) +{ -+ int i, j, got_num, num; -+ u8 mtbl[MAC_ADDR_LEN]; ++ 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; + -+ if (macaddr[0] == ':') -+ return 0; ++ err = bcm2835_audio_write(alsa_stream, bytes, src); ++ if (err) ++ audio_error(" Failed to transfer to alsa device (%d)\n", err); + -+ 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; ++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; + - /* try reading mac address from EEPROM */ - if (smsc95xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, - dev->net->dev_addr) == 0) { ++ 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 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) + 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 int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, + .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 + #include + #include ++#include + + #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 @@ + + 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 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) + 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 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) + 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 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) + 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 + #include + #include ++#include + #include + + /* +@@ -110,6 +111,7 @@ enum { + 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.8.5.5 -From 7f2a7eccaca9f5f92bb5867859c123d8549ea48a Mon Sep 17 00:00:00 2001 +From ae76bc9c9aeac3e3c3b216478d28c41b93e907d6 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 3 Jul 2013 00:51:55 +0100 +Subject: [PATCH 10/99] 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 ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#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.8.5.5 + + +From f18dd263ffb57929721c90d7069cc9cfe323995d Mon Sep 17 00:00:00 2001 +From: Aron Szabo +Date: Sat, 16 Jun 2012 12:15:55 +0200 +Subject: [PATCH 11/99] lirc: added support for RaspberryPi GPIO + +--- + drivers/staging/media/lirc/Kconfig | 6 + + drivers/staging/media/lirc/Makefile | 1 + + drivers/staging/media/lirc/lirc_rpi.c | 693 ++++++++++++++++++++++++++++++++++ + 3 files changed, 700 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..8aee83f +--- /dev/null ++++ b/drivers/staging/media/lirc/lirc_rpi.c +@@ -0,0 +1,693 @@ ++/* ++ * 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 , ++ * Michael Bishop ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define LIRC_DRIVER_NAME "lirc_rpi" ++#define RBUF_LEN 256 ++#define LIRC_TRANSMITTER_LATENCY 256 ++ ++#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) ++{ ++ /* ++ * period, pulse/space width are kept with 8 binary places - ++ * IE multiplied by 256. ++ */ ++ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= ++ LIRC_TRANSMITTER_LATENCY) ++ return -EINVAL; ++ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= ++ LIRC_TRANSMITTER_LATENCY) ++ return -EINVAL; ++ duty_cycle = new_duty_cycle; ++ freq = new_freq; ++ period = 256 * 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, d; ++ ++ length <<= 8; ++ ++ actual = 0; target = 0; flag = 0; ++ 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; ++ } ++ d = (target - actual - ++ LIRC_TRANSMITTER_LATENCY + 128) >> 8; ++ /* ++ * Note - we've checked in ioctl that the pulse/space ++ * widths are big enough so that d is > 0 ++ */ ++ udelay(d); ++ actual += (d << 8) + LIRC_TRANSMITTER_LATENCY; ++ flag = !flag; ++ } ++ return (actual-length) >> 8; ++} ++ ++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 "); ++MODULE_AUTHOR("Michael Bishop "); ++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.8.5.5 + + +From 48896e973101a3b12ed407bf024ac27872102f0f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 8 May 2012 23:12:13 +0100 -Subject: [PATCH 010/118] Fixes for sdhci-bcm2708 +Subject: [PATCH 12/99] Fixes for sdhci-bcm2708 possible fix for sdcard missing status. Thank naren @@ -85645,15 +87092,28 @@ The timeout is not handled well, and is believed to be a code path that causes c 872a8ff suggests that crappy cards can take up to 3 seconds to respond remove suspend/resume + +fix sign in sdhci_bcm2708_raw_writel wait calculation + +The ns_wait variable is intended to hold a lower bound on the number of nanoseconds that have elapsed since the last sdhci register write. However, the actual calculation of it was incorrect, as the subtraction was inverted. This commit fixes the calculation. + +Note that this correction has no bearing when running with the default cycle_delay of 2 and the default clock rate of 50 MHz, under which conditions ns_2clk is 40 nanoseconds and ns_wait, regardless of whether the subtraction is done correctly or incorrectly, cannot possibly be less than 40 except for during the one-microsecond period just before the tick counter wraps around to meet last_write_hpt (i.e., approximately 4295 seconds after the preceding sdhci register write). The correction in this commit only comes into play if ns_2clk > 1000, which requires a cycle_delay of 51 or greater when using the default clock rate. Under those conditions, sdhci_bcm2708_raw_writel will not wait for the full cycle_delay count if at least 1000 nanoseconds have elapsed since the last register write. + +sdhci: Only do one iteration of PIO reading loop + +Changed wording on logging. Previously, we received errors like this: +mmc0: could read SD Status register (SSR) at the 3th attempt +A more sensible response is now returned. +A typo also fixed in comments. --- drivers/mmc/card/block.c | 2 +- drivers/mmc/core/sd.c | 110 +++++++++++++++-- - drivers/mmc/host/sdhci-bcm2708.c | 252 ++++++++++++++++++--------------------- - drivers/mmc/host/sdhci.c | 179 ++++++++++++++++++++------- + drivers/mmc/host/sdhci-bcm2708.c | 254 ++++++++++++++++++--------------------- + drivers/mmc/host/sdhci.c | 180 ++++++++++++++++++++------- drivers/mmc/host/sdhci.h | 8 +- include/linux/mmc/host.h | 1 + include/linux/mmc/sdhci.h | 1 + - 7 files changed, 363 insertions(+), 190 deletions(-) + 7 files changed, 365 insertions(+), 191 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 7b5424f..687cccb 100644 @@ -85669,7 +87129,7 @@ index 7b5424f..687cccb 100644 * token, not a STOP_TRANSMISSION request. */ diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index 692fdb1..897cea6 100644 +index 692fdb1..ea11f9c 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -15,6 +15,8 @@ @@ -85719,7 +87179,7 @@ index 692fdb1..897cea6 100644 + + err = mmc_app_send_scr(card, card->raw_scr); + if( !err ) -+ break; // sucess!!! ++ break; // success!!! + + touch_nmi_watchdog(); // we are still alive! + @@ -85802,7 +87262,7 @@ index 692fdb1..897cea6 100644 + if( tries > 1 ) + { -+ pr_info("%s: could read SD Status register (SSR) at the %dth attempt\n", mmc_hostname(card->host), tries ); ++ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries ); + } + for (i = 0; i < 16; i++) @@ -85827,7 +87287,7 @@ index 692fdb1..897cea6 100644 /* diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c -index d8ef77c..1ebbe2d 100644 +index d8ef77c..3173c18 100644 --- a/drivers/mmc/host/sdhci-bcm2708.c +++ b/drivers/mmc/host/sdhci-bcm2708.c @@ -51,7 +51,6 @@ @@ -85883,7 +87343,8 @@ index d8ef77c..1ebbe2d 100644 { /* we must have waited at least this many ns: */ unsigned int ns_wait = HPTIME_CLK_NS * - (last_write_hpt - now - 1); +- (last_write_hpt - now - 1); ++ (now - last_write_hpt - 1); if (ns_wait < ns_2clk) - udelay((ns_2clk-ns_wait+500)/1000); + ndelay(ns_2clk - ns_wait); @@ -86327,7 +87788,7 @@ index d8ef77c..1ebbe2d 100644 + + diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 3cd62f2..0b44ccf 100644 +index b78afa2..db67be8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -131,6 +131,99 @@ static void sdhci_dumpregs(struct sdhci_host *host) @@ -86448,7 +87909,15 @@ index 3cd62f2..0b44ccf 100644 } #endif -@@ -1018,7 +1111,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) +@@ -457,6 +550,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host, u32 intstate) + break; + state = sdhci_readl(host, SDHCI_PRESENT_STATE); + available = state & mask; ++ break; + } + + DBG("PIO transfer complete - %d blocks left.\n", host->blocks); +@@ -1023,7 +1117,9 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) return; } timeout--; @@ -86458,7 +87927,7 @@ index 3cd62f2..0b44ccf 100644 } DBG("send cmd %d - wait 0x%X irq 0x%x\n", cmd->opcode, mask, sdhci_readl(host, SDHCI_INT_STATUS)); -@@ -1246,7 +1341,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) +@@ -1256,7 +1352,9 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) return; } timeout--; @@ -86468,7 +87937,7 @@ index 3cd62f2..0b44ccf 100644 } clk |= SDHCI_CLOCK_CARD_EN; -@@ -1347,7 +1444,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1357,7 +1455,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) sdhci_runtime_pm_get(host); @@ -86477,10 +87946,10 @@ index 3cd62f2..0b44ccf 100644 WARN_ON(host->mrq != NULL); -@@ -1405,9 +1502,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) - mmc->card->type == MMC_TYPE_MMC ? - MMC_SEND_TUNING_BLOCK_HS200 : - MMC_SEND_TUNING_BLOCK; +@@ -1422,9 +1520,9 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) + */ + host->mrq = NULL; + - spin_unlock_irqrestore(&host->lock, flags); + sdhci_spin_unlock_irqrestore(host, flags); sdhci_execute_tuning(mmc, tuning_opcode); @@ -86489,7 +87958,7 @@ index 3cd62f2..0b44ccf 100644 /* Restore original mmc_request structure */ host->mrq = mrq; -@@ -1421,7 +1518,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) +@@ -1438,7 +1536,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) } mmiowb(); @@ -86498,7 +87967,7 @@ index 3cd62f2..0b44ccf 100644 } static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) -@@ -1430,10 +1527,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +@@ -1447,10 +1545,10 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) int vdd_bit = -1; u8 ctrl; @@ -86511,7 +87980,7 @@ index 3cd62f2..0b44ccf 100644 if (host->vmmc && ios->power_mode == MMC_POWER_OFF) mmc_regulator_set_ocr(host->mmc, host->vmmc, 0); return; -@@ -1461,9 +1558,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +@@ -1478,9 +1576,9 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) vdd_bit = sdhci_set_power(host, ios->vdd); if (host->vmmc && vdd_bit != -1) { @@ -86523,7 +87992,7 @@ index 3cd62f2..0b44ccf 100644 } if (host->ops->platform_send_init_74_clocks) -@@ -1502,7 +1599,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +@@ -1519,7 +1617,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) else ctrl &= ~SDHCI_CTRL_HISPD; @@ -86532,7 +88001,7 @@ index 3cd62f2..0b44ccf 100644 u16 clk, ctrl_2; /* In case of UHS-I modes, set High Speed Enable */ -@@ -1600,7 +1697,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) +@@ -1617,7 +1715,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA); mmiowb(); @@ -86541,7 +88010,7 @@ index 3cd62f2..0b44ccf 100644 } static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) -@@ -1648,7 +1745,7 @@ static int sdhci_check_ro(struct sdhci_host *host) +@@ -1665,7 +1763,7 @@ static int sdhci_check_ro(struct sdhci_host *host) unsigned long flags; int is_readonly; @@ -86550,7 +88019,7 @@ index 3cd62f2..0b44ccf 100644 if (host->flags & SDHCI_DEVICE_DEAD) is_readonly = 0; -@@ -1658,7 +1755,7 @@ static int sdhci_check_ro(struct sdhci_host *host) +@@ -1675,7 +1773,7 @@ static int sdhci_check_ro(struct sdhci_host *host) is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_WRITE_PROTECT); @@ -86559,7 +88028,7 @@ index 3cd62f2..0b44ccf 100644 /* This quirk needs to be replaced by a callback-function later */ return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? -@@ -1731,9 +1828,9 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) +@@ -1748,9 +1846,9 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) struct sdhci_host *host = mmc_priv(mmc); unsigned long flags; @@ -86571,7 +88040,7 @@ index 3cd62f2..0b44ccf 100644 } static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, -@@ -2084,7 +2181,7 @@ static void sdhci_card_event(struct mmc_host *mmc) +@@ -2101,7 +2199,7 @@ static void sdhci_card_event(struct mmc_host *mmc) if (host->ops->card_event) host->ops->card_event(host); @@ -86580,7 +88049,7 @@ index 3cd62f2..0b44ccf 100644 /* Check host->mrq first in case we are runtime suspended */ if (host->mrq && !sdhci_do_get_cd(host)) { -@@ -2100,7 +2197,7 @@ static void sdhci_card_event(struct mmc_host *mmc) +@@ -2117,7 +2215,7 @@ static void sdhci_card_event(struct mmc_host *mmc) tasklet_schedule(&host->finish_tasklet); } @@ -86589,7 +88058,7 @@ index 3cd62f2..0b44ccf 100644 } static const struct mmc_host_ops sdhci_ops = { -@@ -2139,14 +2236,14 @@ static void sdhci_tasklet_finish(unsigned long param) +@@ -2156,14 +2254,14 @@ static void sdhci_tasklet_finish(unsigned long param) host = (struct sdhci_host*)param; @@ -86606,7 +88075,7 @@ index 3cd62f2..0b44ccf 100644 return; } -@@ -2184,7 +2281,7 @@ static void sdhci_tasklet_finish(unsigned long param) +@@ -2201,7 +2299,7 @@ static void sdhci_tasklet_finish(unsigned long param) #endif mmiowb(); @@ -86615,7 +88084,7 @@ index 3cd62f2..0b44ccf 100644 mmc_request_done(host->mmc, mrq); sdhci_runtime_pm_put(host); -@@ -2197,7 +2294,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2214,7 +2312,7 @@ static void sdhci_timeout_timer(unsigned long data) host = (struct sdhci_host*)data; @@ -86624,7 +88093,7 @@ index 3cd62f2..0b44ccf 100644 if (host->mrq) { pr_err("%s: Timeout waiting for hardware " -@@ -2218,7 +2315,7 @@ static void sdhci_timeout_timer(unsigned long data) +@@ -2235,7 +2333,7 @@ static void sdhci_timeout_timer(unsigned long data) } mmiowb(); @@ -86633,7 +88102,7 @@ index 3cd62f2..0b44ccf 100644 } static void sdhci_tuning_timer(unsigned long data) -@@ -2228,11 +2325,11 @@ static void sdhci_tuning_timer(unsigned long data) +@@ -2245,11 +2343,11 @@ static void sdhci_tuning_timer(unsigned long data) host = (struct sdhci_host *)data; @@ -86647,7 +88116,7 @@ index 3cd62f2..0b44ccf 100644 } /*****************************************************************************\ -@@ -2456,10 +2553,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2473,10 +2571,10 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) u32 intmask, unexpected = 0; int cardint = 0, max_loops = 16; @@ -86660,7 +88129,7 @@ index 3cd62f2..0b44ccf 100644 pr_warning("%s: got irq while runtime suspended\n", mmc_hostname(host->mmc)); return IRQ_HANDLED; -@@ -2571,7 +2668,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) +@@ -2588,7 +2686,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (intmask && --max_loops) goto again; out: @@ -86669,7 +88138,7 @@ index 3cd62f2..0b44ccf 100644 if (unexpected) { pr_err("%s: Unexpected interrupt 0x%08x.\n", -@@ -2657,7 +2754,7 @@ int sdhci_resume_host(struct sdhci_host *host) +@@ -2674,7 +2772,7 @@ int sdhci_resume_host(struct sdhci_host *host) } if (!device_may_wakeup(mmc_dev(host->mmc))) { @@ -86678,7 +88147,7 @@ index 3cd62f2..0b44ccf 100644 mmc_hostname(host->mmc), host); if (ret) return ret; -@@ -2733,15 +2830,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) +@@ -2750,15 +2848,15 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host) host->flags &= ~SDHCI_NEEDS_RETUNING; } @@ -86698,7 +88167,7 @@ index 3cd62f2..0b44ccf 100644 return ret; } -@@ -2767,16 +2864,16 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) +@@ -2784,16 +2882,16 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); if ((host_flags & SDHCI_PV_ENABLED) && !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { @@ -86718,7 +88187,7 @@ index 3cd62f2..0b44ccf 100644 host->runtime_suspended = false; -@@ -2787,7 +2884,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) +@@ -2804,7 +2902,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) /* Enable Card Detection */ sdhci_enable_card_detection(host); @@ -86727,7 +88196,7 @@ index 3cd62f2..0b44ccf 100644 return ret; } -@@ -3283,8 +3380,8 @@ int sdhci_add_host(struct sdhci_host *host) +@@ -3300,8 +3398,8 @@ int sdhci_add_host(struct sdhci_host *host) sdhci_init(host, 0); @@ -86738,7 +88207,7 @@ index 3cd62f2..0b44ccf 100644 if (ret) { pr_err("%s: Failed to request IRQ %d: %d\n", mmc_hostname(mmc), host->irq, ret); -@@ -3345,7 +3442,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) +@@ -3362,7 +3460,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) unsigned long flags; if (dead) { @@ -86747,7 +88216,7 @@ index 3cd62f2..0b44ccf 100644 host->flags |= SDHCI_DEVICE_DEAD; -@@ -3357,7 +3454,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) +@@ -3374,7 +3472,7 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) tasklet_schedule(&host->finish_tasklet); } @@ -86808,10 +88277,940 @@ index e23fffb..b1b6537 100644 1.8.5.5 -From b1b2f1f4d1f2b82f55f62dbb76a97852470dacf3 Mon Sep 17 00:00:00 2001 +From 47b6a43161c0643904dd248a8effd1ab3d7fa2f1 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 3 Jul 2013 00:49:20 +0100 +Subject: [PATCH 13/99] 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 14252d3..bbb9856 100644 +--- a/arch/arm/Kconfig ++++ b/arch/arm/Kconfig +@@ -388,6 +388,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 7494565..228317f 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 ++#include ++#include ++#include ++#include ++ ++/* ---------- 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.8.5.5 + + +From 1b14fb19ec8a6aa3c8a07038ce1795a01cf414c3 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 26 Mar 2013 19:24:24 +0000 +Subject: [PATCH 14/99] 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 + +diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c +index ac4c11d6..61457cc 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -483,6 +483,14 @@ struct platform_device bcm2708_powerman_device = { + }, + }; + ++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 @@ void __init bcm2708_init(void) + 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); +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 5ce43d8..193c496 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -1556,6 +1556,16 @@ config SENSORS_MC13783_ADC + 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" +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index ec7cde0..a06e078 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o + obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o + obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o + obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o ++obj-$(CONFIG_SENSORS_BCM2835) += bcm2835-hwmon.o + + obj-$(CONFIG_PMBUS) += pmbus/ + +diff --git a/drivers/hwmon/bcm2835-hwmon.c b/drivers/hwmon/bcm2835-hwmon.c +new file mode 100644 +index 0000000..5bbed45 +--- /dev/null ++++ b/drivers/hwmon/bcm2835-hwmon.c +@@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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); +diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig +index 5f88d76..2f8c704 100644 +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -196,6 +196,12 @@ config INTEL_POWERCLAMP + enforce idle time which results in more package C-state residency. The + user interface is exposed via generic thermal framework. + ++config THERMAL_BCM2835 ++ 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 +diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile +index 54e4ec9..dbbf4e4 100644 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -28,6 +28,7 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o + 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 +diff --git a/drivers/thermal/bcm2835-thermal.c b/drivers/thermal/bcm2835-thermal.c +new file mode 100644 +index 0000000..85fceb5 +--- /dev/null ++++ b/drivers/thermal/bcm2835-thermal.c +@@ -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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++/* --- 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); +-- +1.8.5.5 + + +From 4a859e645805f0af66b5fe708e47a3f892e0acd1 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Tue, 26 Mar 2013 17:26:38 +0000 +Subject: [PATCH 15/99] Allow mac address to be set in smsc95xx + +Signed-off-by: popcornmix +--- + 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 @@ struct smsc95xx_priv { + 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.8.5.5 + + +From 50738ad9a4bf7c1ab491ad12f3206a65bf574d52 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 4 Nov 2013 18:56:10 +0000 -Subject: [PATCH 011/118] Add Chris Boot's i2c and spi drivers. +Subject: [PATCH 16/99] Add Chris Boot's i2c and spi drivers. --- arch/arm/configs/bcmrpi_cutdown_defconfig | 9 + @@ -86880,7 +89279,7 @@ index 9355841..e151ed4 100644 + Binds spidev driver to the SPI0 master endmenu diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index db1b7b5..63b8273 100644 +index 61457cc..624415b 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -31,6 +31,7 @@ @@ -86891,7 +89290,7 @@ index db1b7b5..63b8273 100644 #include #include -@@ -203,7 +204,6 @@ static void __init bcm2708_clocksource_init(void) +@@ -205,7 +206,6 @@ static void __init bcm2708_clocksource_init(void) /* warning - the USB needs a clock > 34MHz */ @@ -86899,7 +89298,7 @@ index db1b7b5..63b8273 100644 static struct clk sdhost_clk = { #ifdef CONFIG_ARCH_BCM2708_CHIPIT .rate = 4000000, /* 4MHz */ -@@ -211,7 +211,6 @@ static void __init bcm2708_clocksource_init(void) +@@ -213,7 +213,6 @@ static void __init bcm2708_clocksource_init(void) .rate = 250000000, /* 250MHz */ #endif }; @@ -86907,7 +89306,7 @@ index db1b7b5..63b8273 100644 static struct clk_lookup lookups[] = { { /* UART0 */ -@@ -221,6 +220,15 @@ static void __init bcm2708_clocksource_init(void) +@@ -223,6 +222,15 @@ static void __init bcm2708_clocksource_init(void) { /* USB */ .dev_id = "bcm2708_usb", .clk = &osc_clk, @@ -86923,8 +89322,8 @@ index db1b7b5..63b8273 100644 } }; -@@ -439,6 +447,89 @@ struct platform_device bcm2708_powerman_device = { - }, +@@ -483,6 +491,89 @@ struct platform_device bcm2708_powerman_device = { + }, }; +static struct resource bcm2708_spi_resources[] = { @@ -87010,10 +89409,10 @@ index db1b7b5..63b8273 100644 + .resource = bcm2708_bsc1_resources, +}; + - int __init bcm_register_device(struct platform_device *pdev) - { - int ret; -@@ -550,12 +641,21 @@ void __init bcm2708_init(void) + static struct platform_device bcm2835_hwmon_device = { + .name = "bcm2835_hwmon", + }; +@@ -602,6 +693,10 @@ void __init bcm2708_init(void) for (i = 0; i < ARRAY_SIZE(bcm2708_alsa_devices); i++) bcm_register_device(&bcm2708_alsa_devices[i]); @@ -87021,9 +89420,10 @@ index db1b7b5..63b8273 100644 + bcm_register_device(&bcm2708_bsc0_device); + bcm_register_device(&bcm2708_bsc1_device); + - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { - struct amba_device *d = amba_devs[i]; - amba_device_register(d, &iomem_resource); + bcm_register_device(&bcm2835_hwmon_device); + bcm_register_device(&bcm2835_thermal_device); + +@@ -611,6 +706,11 @@ void __init bcm2708_init(void) } system_rev = boardrev; system_serial_low = serial; @@ -87036,10 +89436,10 @@ index db1b7b5..63b8273 100644 static void timer_set_mode(enum clock_event_mode mode, diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h -index 110ce07..4d3c15d 100644 +index ecd854e..f4bb733 100644 --- a/arch/arm/mach-bcm2708/include/mach/platform.h +++ b/arch/arm/mach-bcm2708/include/mach/platform.h -@@ -63,9 +63,12 @@ +@@ -64,9 +64,12 @@ #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 */ @@ -87053,7 +89453,7 @@ index 110ce07..4d3c15d 100644 #define MCORE_BASE (BCM2708_PERI_BASE + 0x0000) /* Fake frame buffer device (actually the multicore sync block*/ diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig -index 2469ee0..91562c1 100644 +index de17c55..c9280e7 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -347,6 +347,25 @@ config I2C_BCM2835 @@ -87083,7 +89483,7 @@ index 2469ee0..91562c1 100644 tristate "BCM Kona I2C adapter" depends on ARCH_BCM_MOBILE diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile -index c73eb0e..9c46931 100644 +index a08931f..a62fadf 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o @@ -87509,7 +89909,7 @@ index 0000000..98bc4e7 +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig -index eb1f1ef..e8b4f04 100644 +index 581ee2a..6029f6f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -85,6 +85,14 @@ config SPI_BCM2835 @@ -87528,11 +89928,11 @@ index eb1f1ef..e8b4f04 100644 tristate "SPI controller driver for ADI Blackfin5xx" depends on BLACKFIN && !BF60x diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile -index ab8d864..a011073 100644 +index 95af48d..51996c2 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile -@@ -18,6 +18,7 @@ obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o - obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o +@@ -19,6 +19,7 @@ obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o + obj-$(CONFIG_SPI_BCM63XX_HSSPI) += spi-bcm63xx-hsspi.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o +obj-$(CONFIG_SPI_BCM2708) += spi-bcm2708.o @@ -88175,18 +90575,28 @@ index 0000000..180264a 1.8.5.5 -From e677388002600cccbb23dde2c8f0ad2437e3f06c Mon Sep 17 00:00:00 2001 +From a02114887a6713b9a2ab58241755f3e952108372 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 8 May 2013 11:46:50 +0100 -Subject: [PATCH 012/118] enabling the realtime clock 1-wire chip DS1307 and +Subject: [PATCH 17/99] 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 --- - arch/arm/mach-bcm2708/bcm2708.c | 20 ++++++++++++++++++++ - 1 file changed, 20 insertions(+) + arch/arm/mach-bcm2708/bcm2708.c | 23 +++++++++++++++++++++++ + drivers/w1/masters/w1-gpio.c | 20 ++++++++++++++++++++ + drivers/w1/w1.h | 6 ++++++ + drivers/w1/w1_int.c | 14 ++++++++++++++ + drivers/w1/w1_io.c | 18 +++++++++++++++--- + 5 files changed, 78 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 63b8273..2a36411 100644 +index 624415b..d315c19 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c @@ -32,6 +32,7 @@ @@ -88197,7 +90607,7 @@ index 63b8273..2a36411 100644 #include #include -@@ -76,6 +77,9 @@ +@@ -76,12 +77,16 @@ */ #define DMA_MASK_BITS_COMMON 32 @@ -88207,7 +90617,14 @@ index 63b8273..2a36411 100644 /* command line parameters */ static unsigned boardrev, serial; static unsigned uart_clock; -@@ -256,6 +260,19 @@ static void __init bcm2708_clocksource_init(void) + 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 void __init bcm2708_init_led(void); + +@@ -258,6 +263,19 @@ static void __init bcm2708_clocksource_init(void) .num_resources = ARRAY_SIZE(bcm2708_dmaman_resources), }; @@ -88227,24 +90644,147 @@ index 63b8273..2a36411 100644 static u64 fb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); static struct platform_device bcm2708_fb_device = { -@@ -628,6 +645,9 @@ void __init bcm2708_init(void) +@@ -680,6 +698,10 @@ 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; + platform_device_register(&w1_device); +#endif bcm_register_device(&bcm2708_systemtimer_device); bcm_register_device(&bcm2708_fb_device); bcm_register_device(&bcm2708_usb_device); +@@ -880,3 +902,4 @@ static void __init board_reserve(void) + 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); +diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c +index 9709b8b..f8b769a 100644 +--- a/drivers/w1/masters/w1-gpio.c ++++ b/drivers/w1/masters/w1-gpio.c +@@ -23,6 +23,9 @@ + #include "../w1.h" + #include "../w1_int.h" + ++static int w1_gpio_pullup = 0; ++module_param_named(pullup, w1_gpio_pullup, int, 0); ++ + static u8 w1_gpio_set_pullup(void *data, int delay) + { + struct w1_gpio_platform_data *pdata = data; +@@ -67,6 +70,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" }, +@@ -156,6 +169,13 @@ static int w1_gpio_probe(struct platform_device *pdev) + master->set_pullup = w1_gpio_set_pullup; + } + ++ if (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"); +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.8.5.5 -From a11c4058fffd7006238b732f8edf07b68bda5a5e Mon Sep 17 00:00:00 2001 +From 70f7054af0acc75fc6ab5f54e44c53aa8c44deb9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 00:46:42 +0100 -Subject: [PATCH 013/118] Add FIQ patch to dwc_otg driver. Enable with +Subject: [PATCH 18/99] Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. Thanks to Gordon and Costas @@ -88275,10 +90815,10 @@ Subject: [PATCH 013/118] Add FIQ patch to dwc_otg driver. Enable with create mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig -index 99605f2..97ad2d2 100644 +index bbb9856..2f02b72 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig -@@ -386,6 +386,7 @@ config ARCH_BCM2708 +@@ -393,6 +393,7 @@ config ARCH_BCM2708 select ARM_ERRATA_411920 select MACH_BCM2708 select VC4 @@ -88376,10 +90916,10 @@ index da18725..274aa30 100644 return 0; } diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 2a36411..0836685 100644 +index d315c19..2b11e9d 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -314,12 +314,32 @@ static void __init bcm2708_clocksource_init(void) +@@ -317,12 +317,32 @@ static void __init bcm2708_clocksource_init(void) .flags = IORESOURCE_MEM, }, [1] = { @@ -88414,7 +90954,7 @@ index 2a36411..0836685 100644 static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); static struct platform_device bcm2708_usb_device = { -@@ -650,6 +670,11 @@ void __init bcm2708_init(void) +@@ -704,6 +724,11 @@ void __init bcm2708_init(void) #endif bcm_register_device(&bcm2708_systemtimer_device); bcm_register_device(&bcm2708_fb_device); @@ -88604,7 +91144,7 @@ index e8bb068..9aaedf1 100644 #endif /* _BCM2708_IRQS_H_ */ diff --git a/arch/arm/mach-bcm2708/include/mach/platform.h b/arch/arm/mach-bcm2708/include/mach/platform.h -index 4d3c15d..89e72d1 100644 +index f4bb733..992a630 100644 --- a/arch/arm/mach-bcm2708/include/mach/platform.h +++ b/arch/arm/mach-bcm2708/include/mach/platform.h @@ -56,7 +56,9 @@ @@ -88618,7 +91158,7 @@ index 4d3c15d..89e72d1 100644 #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 */ diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile -index 5748f7d..8d177b1 100644 +index 236c47c..a56f193 100644 --- a/drivers/usb/host/dwc_otg/Makefile +++ b/drivers/usb/host/dwc_otg/Makefile @@ -36,6 +36,7 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o @@ -88675,7 +91215,7 @@ index 8900318..ccc24e0 100644 #define DBG_CIL (0x2) /** When debug level has the DBG_CILV bit set, display CIL Verbose debug diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index dcfbd66..89cc25e 100644 +index ac2c846..97f150b 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c @@ -64,6 +64,8 @@ @@ -89404,11 +91944,11 @@ index e46d9bb..6b2c7d0 100644 1.8.5.5 -From d8fd0c98550d39b967174d5359e20a637afc7925 Mon Sep 17 00:00:00 2001 +From 52c64dc4386c2596111d1ea7134a902a2546a181 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Sat, 8 Sep 2012 15:17:53 +0100 -Subject: [PATCH 016/118] Avoid dynamic memory allocation for channel lock in - USB driver. Thanks ddv2005. +Subject: [PATCH 21/99] Avoid dynamic memory allocation for channel lock in USB + driver. Thanks ddv2005. --- drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 6 +++--- @@ -89514,322 +92054,17 @@ index b7b6b0c..76b5085 100644 1.8.5.5 -From d8e89ec2e7ca815a752bd3494693cad10539157e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 3 Jul 2013 00:49:20 +0100 -Subject: [PATCH 017/118] 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 97ad2d2..2d051ab 100644 ---- a/arch/arm/Kconfig -+++ b/arch/arm/Kconfig -@@ -382,6 +382,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 ce52ed9..ee72801 100644 ---- a/drivers/cpufreq/Kconfig.arm -+++ b/drivers/cpufreq/Kconfig.arm -@@ -218,6 +218,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 7494565..228317f 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 -+#include -+#include -+#include -+#include -+ -+/* ---------- 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.8.5.5 - - -From 1d76275b7ebebe837fc27dd97fd4d30050083372 Mon Sep 17 00:00:00 2001 +From d75d35ad1b63a1191d567c43e2d33892826d56d4 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 12 Apr 2013 23:58:47 +0100 -Subject: [PATCH 018/118] config: add missing options from 3.6.y kernel +Subject: [PATCH 22/99] config: add missing options from 3.6.y kernel --- - arch/arm/configs/bcmrpi_defconfig | 742 ++++++++++++++++++++++++++++++++------ - 1 file changed, 637 insertions(+), 105 deletions(-) + arch/arm/configs/bcmrpi_defconfig | 748 ++++++++++++++++++++++++++++++++------ + 1 file changed, 643 insertions(+), 105 deletions(-) diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 31f5afaa..88f930c 100644 +index 31f5afaa..88692be 100644 --- a/arch/arm/configs/bcmrpi_defconfig +++ b/arch/arm/configs/bcmrpi_defconfig @@ -1,11 +1,17 @@ @@ -89902,7 +92137,7 @@ index 31f5afaa..88f930c 100644 CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_BINFMT_MISC=m -@@ -48,19 +68,275 @@ CONFIG_XFRM_USER=y +@@ -48,19 +68,278 @@ CONFIG_XFRM_USER=y CONFIG_NET_KEY=m CONFIG_INET=y CONFIG_IP_MULTICAST=y @@ -90111,6 +92346,9 @@ index 31f5afaa..88f930c 100644 +CONFIG_BRIDGE_EBT_NFLOG=m +CONFIG_SCTP_COOKIE_HMAC_SHA1=y +CONFIG_L2TP=m ++CONFIG_L2TP_V3=y ++CONFIG_L2TP_IP=m ++CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_VLAN_8021Q_GVRP=y @@ -90184,7 +92422,7 @@ index 31f5afaa..88f930c 100644 CONFIG_IRCOMM=m CONFIG_IRDA_ULTRA=y CONFIG_IRDA_CACHE_LAST_LSAP=y -@@ -73,8 +349,6 @@ CONFIG_USB_IRDA=m +@@ -73,8 +352,6 @@ CONFIG_USB_IRDA=m CONFIG_SIGMATEL_FIR=m CONFIG_MCS_FIR=m CONFIG_BT=m @@ -90193,7 +92431,7 @@ index 31f5afaa..88f930c 100644 CONFIG_BT_RFCOMM=m CONFIG_BT_RFCOMM_TTY=y CONFIG_BT_BNEP=m -@@ -89,35 +363,101 @@ CONFIG_BT_HCIVHCI=m +@@ -89,35 +366,102 @@ CONFIG_BT_HCIVHCI=m CONFIG_BT_MRVL=m CONFIG_BT_MRVL_SDIO=m CONFIG_BT_ATH3K=m @@ -90251,6 +92489,7 @@ index 31f5afaa..88f930c 100644 +CONFIG_NETCONSOLE=m CONFIG_TUN=m -CONFIG_PHYLIB=m ++CONFIG_VETH=m CONFIG_MDIO_BITBANG=m -CONFIG_NET_ETHERNET=y -# CONFIG_NETDEV_1000 is not set @@ -90303,7 +92542,7 @@ index 31f5afaa..88f930c 100644 CONFIG_LIBERTAS_THINFIRM=m CONFIG_LIBERTAS_THINFIRM_USB=m CONFIG_AT76C50X_USB=m -@@ -125,14 +465,17 @@ CONFIG_USB_ZD1201=m +@@ -125,14 +469,17 @@ CONFIG_USB_ZD1201=m CONFIG_USB_NET_RNDIS_WLAN=m CONFIG_RTL8187=m CONFIG_MAC80211_HWSIM=m @@ -90323,10 +92562,13 @@ index 31f5afaa..88f930c 100644 CONFIG_LIBERTAS=m CONFIG_LIBERTAS_USB=m CONFIG_LIBERTAS_SDIO=m -@@ -143,56 +486,25 @@ CONFIG_RT2500USB=m +@@ -142,57 +489,28 @@ CONFIG_RT2X00=m + CONFIG_RT2500USB=m CONFIG_RT73USB=m CONFIG_RT2800USB=m ++CONFIG_RT2800USB_RT3573=y CONFIG_RT2800USB_RT53XX=y ++CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y CONFIG_RTL8192CU=m -CONFIG_WL1251=m @@ -90386,7 +92628,7 @@ index 31f5afaa..88f930c 100644 CONFIG_INPUT_ATI_REMOTE2=m CONFIG_INPUT_KEYSPAN_REMOTE=m CONFIG_INPUT_POWERMATE=m -@@ -207,26 +519,191 @@ CONFIG_SERIO_RAW=m +@@ -207,26 +525,191 @@ CONFIG_SERIO_RAW=m CONFIG_GAMEPORT=m CONFIG_GAMEPORT_NS558=m CONFIG_GAMEPORT_L4=m @@ -90582,7 +92824,7 @@ index 31f5afaa..88f930c 100644 CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y # CONFIG_LOGO_LINUX_MONO is not set -@@ -249,10 +726,10 @@ CONFIG_SND_BCM2835=m +@@ -249,10 +732,10 @@ CONFIG_SND_BCM2835=m CONFIG_SND_USB_AUDIO=m CONFIG_SND_USB_UA101=m CONFIG_SND_USB_CAIAQ=m @@ -90595,7 +92837,7 @@ index 31f5afaa..88f930c 100644 CONFIG_HID_A4TECH=m CONFIG_HID_ACRUX=m CONFIG_HID_APPLE=m -@@ -283,7 +760,6 @@ CONFIG_HID_ORTEK=m +@@ -283,7 +766,6 @@ CONFIG_HID_ORTEK=m CONFIG_HID_PANTHERLORD=m CONFIG_HID_PETALYNX=m CONFIG_HID_PICOLCD=m @@ -90603,7 +92845,7 @@ index 31f5afaa..88f930c 100644 CONFIG_HID_ROCCAT=m CONFIG_HID_SAMSUNG=m CONFIG_HID_SONY=m -@@ -292,15 +768,19 @@ CONFIG_HID_SUNPLUS=m +@@ -292,15 +774,19 @@ CONFIG_HID_SUNPLUS=m CONFIG_HID_GREENASIA=m CONFIG_HID_SMARTJOYPLUS=m CONFIG_HID_TOPSEED=m @@ -90623,7 +92865,7 @@ index 31f5afaa..88f930c 100644 CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_REALTEK=m CONFIG_USB_STORAGE_DATAFAB=m -@@ -315,8 +795,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m +@@ -315,8 +801,6 @@ CONFIG_USB_STORAGE_ONETOUCH=m CONFIG_USB_STORAGE_KARMA=m CONFIG_USB_STORAGE_CYPRESS_ATACB=m CONFIG_USB_STORAGE_ENE_UB6250=m @@ -90632,7 +92874,7 @@ index 31f5afaa..88f930c 100644 CONFIG_USB_MDC800=m CONFIG_USB_MICROTEK=m CONFIG_USB_SERIAL=m -@@ -331,12 +809,12 @@ CONFIG_USB_SERIAL_CP210X=m +@@ -331,12 +815,12 @@ CONFIG_USB_SERIAL_CP210X=m CONFIG_USB_SERIAL_CYPRESS_M8=m CONFIG_USB_SERIAL_EMPEG=m CONFIG_USB_SERIAL_FTDI_SIO=m @@ -90646,7 +92888,7 @@ index 31f5afaa..88f930c 100644 CONFIG_USB_SERIAL_GARMIN=m CONFIG_USB_SERIAL_IPW=m CONFIG_USB_SERIAL_IUU=m -@@ -345,18 +823,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m +@@ -345,18 +829,16 @@ CONFIG_USB_SERIAL_KEYSPAN=m CONFIG_USB_SERIAL_KLSI=m CONFIG_USB_SERIAL_KOBIL_SCT=m CONFIG_USB_SERIAL_MCT_U232=m @@ -90666,7 +92908,7 @@ index 31f5afaa..88f930c 100644 CONFIG_USB_SERIAL_SIERRAWIRELESS=m CONFIG_USB_SERIAL_SYMBOL=m CONFIG_USB_SERIAL_TI=m -@@ -365,9 +841,11 @@ CONFIG_USB_SERIAL_XIRCOM=m +@@ -365,9 +847,11 @@ CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_OPTION=m CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OPTICON=m @@ -90680,7 +92922,7 @@ index 31f5afaa..88f930c 100644 CONFIG_USB_SERIAL_DEBUG=m CONFIG_USB_EMI62=m CONFIG_USB_EMI26=m -@@ -389,17 +867,71 @@ CONFIG_USB_TEST=m +@@ -389,17 +873,71 @@ CONFIG_USB_TEST=m CONFIG_USB_ISIGHTFW=m CONFIG_USB_YUREX=m CONFIG_MMC=y @@ -90757,7 +92999,7 @@ index 31f5afaa..88f930c 100644 # CONFIG_IOMMU_SUPPORT is not set CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y -@@ -422,6 +954,8 @@ CONFIG_BTRFS_FS=m +@@ -422,6 +960,8 @@ CONFIG_BTRFS_FS=m CONFIG_BTRFS_FS_POSIX_ACL=y CONFIG_NILFS2_FS=m CONFIG_FANOTIFY=y @@ -90766,7 +93008,7 @@ index 31f5afaa..88f930c 100644 CONFIG_AUTOFS4_FS=y CONFIG_FUSE_FS=m CONFIG_CUSE=m -@@ -437,28 +971,32 @@ CONFIG_MSDOS_FS=y +@@ -437,28 +977,32 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_IOCHARSET="ascii" CONFIG_NTFS_FS=m @@ -90803,7 +93045,7 @@ index 31f5afaa..88f930c 100644 CONFIG_NLS_DEFAULT="utf8" CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_CODEPAGE_737=m -@@ -497,39 +1035,33 @@ CONFIG_NLS_ISO8859_14=m +@@ -497,39 +1041,33 @@ CONFIG_NLS_ISO8859_14=m CONFIG_NLS_ISO8859_15=m CONFIG_NLS_KOI8_R=m CONFIG_NLS_KOI8_U=m @@ -90859,10 +93101,10 @@ index 31f5afaa..88f930c 100644 1.8.5.5 -From 9fb25e7329b5f67f918b35253b25778656c6317c Mon Sep 17 00:00:00 2001 +From b5d278cf417ac5de9f3bd7b0886cbf8f570e6d9f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 8 Apr 2013 21:12:48 +0100 -Subject: [PATCH 019/118] Add NAK holdoff scheme. Enabled by default, disable +Subject: [PATCH 23/99] Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh --- @@ -90874,7 +93116,7 @@ Subject: [PATCH 019/118] Add NAK holdoff scheme. Enabled by default, disable 5 files changed, 70 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index 89cc25e..d58ebd7 100644 +index 97f150b..c2bb596 100644 --- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c +++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c @@ -243,6 +243,9 @@ struct dwc_otg_driver_module_params { @@ -91072,639 +93314,10 @@ index a9dea55..ebee73a 100644 1.8.5.5 -From 3eb94600c9feb5566b3e03e9f48eea4a1dbf6020 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 26 Mar 2013 19:24:24 +0000 -Subject: [PATCH 020/118] 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 | 208 ++++++++++++++++++++++++++++++++++++ - 7 files changed, 456 insertions(+) - create mode 100644 drivers/hwmon/bcm2835-hwmon.c - create mode 100644 drivers/thermal/bcm2835-thermal.c - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 0836685..8b6ff52 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -567,6 +567,14 @@ struct platform_device bcm2708_powerman_device = { - .resource = bcm2708_bsc1_resources, - }; - -+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; -@@ -690,6 +698,9 @@ void __init bcm2708_init(void) - bcm_register_device(&bcm2708_bsc0_device); - bcm_register_device(&bcm2708_bsc1_device); - -+ 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); -diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig -index 52d548f..c0d94f9 100644 ---- a/drivers/hwmon/Kconfig -+++ b/drivers/hwmon/Kconfig -@@ -1554,6 +1554,16 @@ config SENSORS_MC13783_ADC - 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" -diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile -index ec7cde0..a06e078 100644 ---- a/drivers/hwmon/Makefile -+++ b/drivers/hwmon/Makefile -@@ -142,6 +142,7 @@ obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o - obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o - obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o - obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o -+obj-$(CONFIG_SENSORS_BCM2835) += bcm2835-hwmon.o - - obj-$(CONFIG_PMBUS) += pmbus/ - -diff --git a/drivers/hwmon/bcm2835-hwmon.c b/drivers/hwmon/bcm2835-hwmon.c -new file mode 100644 -index 0000000..5bbed45 ---- /dev/null -+++ b/drivers/hwmon/bcm2835-hwmon.c -@@ -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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#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); -diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig -index f35a1f7..0839a16 100644 ---- a/drivers/thermal/Kconfig -+++ b/drivers/thermal/Kconfig -@@ -181,6 +181,12 @@ config INTEL_POWERCLAMP - enforce idle time which results in more package C-state residency. The - user interface is exposed via generic thermal framework. - -+config THERMAL_BCM2835 -+ 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 -diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile -index 584b363..97e5a03 100644 ---- a/drivers/thermal/Makefile -+++ b/drivers/thermal/Makefile -@@ -27,5 +27,6 @@ obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o - 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/ -diff --git a/drivers/thermal/bcm2835-thermal.c b/drivers/thermal/bcm2835-thermal.c -new file mode 100644 -index 0000000..3f9a733 ---- /dev/null -+++ b/drivers/thermal/bcm2835-thermal.c -@@ -0,0 +1,208 @@ -+/***************************************************************************** -+* 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+/* --- 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 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 -+ -+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; -+}; -+ -+/* --- PROTOTYPES --- */ -+static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *); -+static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int, unsigned long *); -+static int bcm2835_get_trip_type(struct thermal_zone_device *thermal_dev, int trip_num, enum thermal_trip_type *trip_type); -+static int bcm2835_get_mode(struct thermal_zone_device *thermal_dev, enum thermal_device_mode *dev_mode); -+ -+/* --- GLOBALS --- */ -+static struct bcm2835_thermal_data bcm2835_data; -+ -+/* Thermal Device Operations */ -+static struct thermal_zone_device_ops ops; -+ -+/* --- FUNCTIONS --- */ -+static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int trip_num, unsigned long *temp) -+{ -+ int result; -+ -+ print_debug("IN"); -+ -+ /* 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 = VC_TAG_GET_MAX_TEMP; -+ -+ /* send the message */ -+ result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg); -+ -+ /* check if it was all ok and return the rate in milli degrees C */ -+ if (result == 0 && (bcm2835_data.msg.request_code & 0x80000000)) -+ *temp = (uint)bcm2835_data.msg.tag.val; -+ #ifdef THERMAL_DEBUG_ENABLE -+ else -+ print_debug("Failed to get temperature!"); -+ #endif -+ print_debug("Got temperature as %u",(uint)*temp); -+ print_debug("OUT"); -+ return 0; -+} -+ -+static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *temp) -+{ -+ int result; -+ -+ print_debug("IN"); -+ -+ /* 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 = VC_TAG_GET_TEMP; -+ -+ /* send the message */ -+ result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg); -+ -+ /* check if it was all ok and return the rate in milli degrees C */ -+ if (result == 0 && (bcm2835_data.msg.request_code & 0x80000000)) -+ *temp = (uint)bcm2835_data.msg.tag.val; -+ #ifdef THERMAL_DEBUG_ENABLE -+ else -+ print_debug("Failed to get temperature!"); -+ #endif -+ print_debug("Got temperature as %u",(uint)*temp); -+ print_debug("OUT"); -+ return 0; -+} -+ -+ -+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); --- -1.8.5.5 - - -From 07ad0788db5094fb8d622f3dea58eeade391df0e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 17 Apr 2013 12:16:36 +0100 -Subject: [PATCH 021/118] Enable multiple ALSA channels - ---- - arch/arm/mach-bcm2708/bcm2708.c | 54 ++++++++++++++++++++++++++++++++++++----- - 1 file changed, 48 insertions(+), 6 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 8b6ff52..b4d94bf 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -476,12 +476,54 @@ struct platform_device bcm2708_powerman_device = { - - - static struct platform_device bcm2708_alsa_devices[] = { -- [0] = { -- .name = "bcm2835_AUD0", -- .id = 0, /* first audio device */ -- .resource = 0, -- .num_resources = 0, -- }, -+ [0] = { -+ .name = "bcm2835_AUD0", -+ .id = 0, /* first audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [1] = { -+ .name = "bcm2835_AUD1", -+ .id = 1, /* second audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [2] = { -+ .name = "bcm2835_AUD2", -+ .id = 2, /* third audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [3] = { -+ .name = "bcm2835_AUD3", -+ .id = 3, /* forth audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [4] = { -+ .name = "bcm2835_AUD4", -+ .id = 4, /* fifth audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [5] = { -+ .name = "bcm2835_AUD5", -+ .id = 5, /* sixth audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [6] = { -+ .name = "bcm2835_AUD6", -+ .id = 6, /* seventh audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, -+ [7] = { -+ .name = "bcm2835_AUD7", -+ .id = 7, /* eighth audio device */ -+ .resource = 0, -+ .num_resources = 0, -+ }, - }; - - static struct resource bcm2708_spi_resources[] = { --- -1.8.5.5 - - -From 20f223d7e15226ff90de5a3367563f90731706fd Mon Sep 17 00:00:00 2001 +From 0716fec09f8c734a9dfda331c7f58bd21268190e Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Sun, 4 Nov 2012 15:55:01 +0000 -Subject: [PATCH 022/118] Make sure we wait for the reset to finish +Subject: [PATCH 24/99] Make sure we wait for the reset to finish --- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2 ++ @@ -91727,780 +93340,10 @@ index aff59df..1a23d4b 100644 1.8.5.5 -From f7ed2c5705d6846b3362cc376fa8ffda87cf6cc3 Mon Sep 17 00:00:00 2001 -From: Aron Szabo -Date: Sat, 16 Jun 2012 12:15:55 +0200 -Subject: [PATCH 023/118] lirc: added support for RaspberryPi GPIO - ---- - drivers/staging/media/lirc/Kconfig | 6 + - drivers/staging/media/lirc/Makefile | 1 + - drivers/staging/media/lirc/lirc_rpi.c | 693 ++++++++++++++++++++++++++++++++++ - 3 files changed, 700 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..c76f696 ---- /dev/null -+++ b/drivers/staging/media/lirc/lirc_rpi.c -@@ -0,0 +1,693 @@ -+/* -+ * 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 , -+ * Michael Bishop -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define LIRC_DRIVER_NAME "lirc_rpi" -+#define RBUF_LEN 256 -+#define LIRC_TRANSMITTER_LATENCY 256 -+ -+#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, 4, 8, 7, 9, 10, 11, 14, 15, 17, 18, 21, 22, 23, -+ 24, 25 }; -+ -+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) -+{ -+ /* -+ * period, pulse/space width are kept with 8 binary places - -+ * IE multiplied by 256. -+ */ -+ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= -+ LIRC_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= -+ LIRC_TRANSMITTER_LATENCY) -+ return -EINVAL; -+ duty_cycle = new_duty_cycle; -+ freq = new_freq; -+ period = 256 * 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, d; -+ -+ length <<= 8; -+ -+ actual = 0; target = 0; flag = 0; -+ 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; -+ } -+ d = (target - actual - -+ LIRC_TRANSMITTER_LATENCY + 128) >> 8; -+ /* -+ * Note - we've checked in ioctl that the pulse/space -+ * widths are big enough so that d is > 0 -+ */ -+ udelay(d); -+ actual += (d << 8) + LIRC_TRANSMITTER_LATENCY; -+ flag = !flag; -+ } -+ return (actual-length) >> 8; -+} -+ -+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 "); -+MODULE_AUTHOR("Michael Bishop "); -+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.8.5.5 - - -From f3886f0063216ef7dbc435cf9351202b1c95eec2 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 11 Dec 2012 18:23:03 +0000 -Subject: [PATCH 024/118] Default to dwc_otp.lpm_enable=0 - ---- - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.c b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -index d58ebd7..c2bb596 100644 ---- a/drivers/usb/host/dwc_otg/dwc_otg_driver.c -+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.c -@@ -228,7 +228,7 @@ struct dwc_otg_driver_module_params { - .rx_thr_length = -1, - .pti_enable = -1, - .mpi_enable = -1, -- .lpm_enable = -1, -+ .lpm_enable = 0, - .ic_usb_cap = -1, - .ahb_thr_ratio = -1, - .power_down = -1, --- -1.8.5.5 - - -From 545f11fa079a2ecd458798ca34d8da1496ca29a8 Mon Sep 17 00:00:00 2001 +From d423f60ca746638683ed0e4d1908e0f9994085f8 Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 9 Jan 2013 16:12:04 +0000 -Subject: [PATCH 025/118] dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent +Subject: [PATCH 25/99] dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel memory corruption, escalating to OOPS under high USB load. --- @@ -92537,232 +93380,10 @@ index ebee73a..b3efaf4 100644 1.8.5.5 -From 09edc4634fb1b5c8b4b030a6727b6258f9020d8e Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 3 Jul 2013 00:51:55 +0100 -Subject: [PATCH 026/118] 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 89e72d1..992a630 100644 ---- a/arch/arm/mach-bcm2708/include/mach/platform.h -+++ b/arch/arm/mach-bcm2708/include/mach/platform.h -@@ -62,6 +62,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 -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+#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.8.5.5 - - -From 8981b8d18960aee68f42504f05b8f90bf0993e08 Mon Sep 17 00:00:00 2001 -From: Technion -Date: Mon, 11 Feb 2013 22:08:53 +1100 -Subject: [PATCH 027/118] Changed wording on logging. Previously, we received - errors like this: mmc0: could read SD Status register (SSR) at the 3th - attempt A more sensible response is now returned. A typo also fixed in - comments. - ---- - drivers/mmc/core/sd.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c -index 897cea6..ea11f9c 100644 ---- a/drivers/mmc/core/sd.c -+++ b/drivers/mmc/core/sd.c -@@ -247,7 +247,7 @@ static int mmc_read_scr(struct mmc_card *card) - - err = mmc_app_send_scr(card, card->raw_scr); - if( !err ) -- break; // sucess!!! -+ break; // success!!! - - touch_nmi_watchdog(); // we are still alive! - -@@ -330,7 +330,7 @@ static int mmc_read_ssr(struct mmc_card *card) - - if( tries > 1 ) - { -- pr_info("%s: could read SD Status register (SSR) at the %dth attempt\n", mmc_hostname(card->host), tries ); -+ pr_info("%s: read SD Status register (SSR) after %d attempts\n", mmc_hostname(card->host), tries ); - } - - for (i = 0; i < 16; i++) --- -1.8.5.5 - - -From 317b349cffa0055c73d7220557edfc225a53efce Mon Sep 17 00:00:00 2001 +From 333a6d91d68e2b87cdafa70ebc52154baf6eb03e Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 15 Feb 2013 22:36:47 +0000 -Subject: [PATCH 028/118] dwc_otg: Fix unsafe access of QTD during URB enqueue +Subject: [PATCH 26/99] dwc_otg: Fix unsafe access of QTD during URB enqueue In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the transaction could complete almost immediately after the qtd was assigned @@ -92849,10 +93470,10 @@ index b3efaf4..1554be5 100644 1.8.5.5 -From 110a5ae130cfa68eb37a19d6aa855a1e5f077980 Mon Sep 17 00:00:00 2001 +From 351e191855af8b456f1694936bdfc87e65fab322 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 15 Feb 2013 22:38:40 +0000 -Subject: [PATCH 029/118] dwc_otg: Fix incorrect URB allocation error handling +Subject: [PATCH 27/99] dwc_otg: Fix incorrect URB allocation error handling If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS because for some reason a member of the *unallocated* struct was set to @@ -92893,141 +93514,11 @@ index 35d03d1..6fe30e3 100644 1.8.5.5 -From b35d631f88561c4b98ad8c34a620f5a288aa557a Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Sun, 24 Feb 2013 16:30:57 +0000 -Subject: [PATCH 030/118] Add retry on error and tidy of temperature driver - ---- - drivers/thermal/bcm2835-thermal.c | 78 ++++++++++++++------------------------- - 1 file changed, 27 insertions(+), 51 deletions(-) - -diff --git a/drivers/thermal/bcm2835-thermal.c b/drivers/thermal/bcm2835-thermal.c -index 3f9a733..85fceb5 100644 ---- a/drivers/thermal/bcm2835-thermal.c -+++ b/drivers/thermal/bcm2835-thermal.c -@@ -33,7 +33,6 @@ - #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 -@@ -66,12 +65,6 @@ struct bcm2835_thermal_data { - struct vc_msg msg; - }; - --/* --- PROTOTYPES --- */ --static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *); --static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int, unsigned long *); --static int bcm2835_get_trip_type(struct thermal_zone_device *thermal_dev, int trip_num, enum thermal_trip_type *trip_type); --static int bcm2835_get_mode(struct thermal_zone_device *thermal_dev, enum thermal_device_mode *dev_mode); -- - /* --- GLOBALS --- */ - static struct bcm2835_thermal_data bcm2835_data; - -@@ -79,64 +72,47 @@ struct bcm2835_thermal_data { - static struct thermal_zone_device_ops ops; - - /* --- FUNCTIONS --- */ --static int bcm2835_get_max_temp(struct thermal_zone_device *thermal_dev, int trip_num, unsigned long *temp) --{ -- int result; - -+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"); - -- /* 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 = VC_TAG_GET_MAX_TEMP; -- -- /* send the message */ -- result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg); -+ *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 && (bcm2835_data.msg.request_code & 0x80000000)) -+ if (result == 0) - *temp = (uint)bcm2835_data.msg.tag.val; -- #ifdef THERMAL_DEBUG_ENABLE - else -- print_debug("Failed to get temperature!"); -- #endif -- print_debug("Got temperature as %u",(uint)*temp); -+ print_err("Failed to get temperature! (%x:%d)\n", tag_id, result); - print_debug("OUT"); -- return 0; -+ return result; - } - - static int bcm2835_get_temp(struct thermal_zone_device *thermal_dev, unsigned long *temp) - { -- int result; -- -- print_debug("IN"); -- -- /* 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 = VC_TAG_GET_TEMP; -- -- /* send the message */ -- result = bcm_mailbox_property(&bcm2835_data.msg, sizeof bcm2835_data.msg); -- -- /* check if it was all ok and return the rate in milli degrees C */ -- if (result == 0 && (bcm2835_data.msg.request_code & 0x80000000)) -- *temp = (uint)bcm2835_data.msg.tag.val; -- #ifdef THERMAL_DEBUG_ENABLE -- else -- print_debug("Failed to get temperature!"); -- #endif -- print_debug("Got temperature as %u",(uint)*temp); -- print_debug("OUT"); -- return 0; -+ 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) - { --- -1.8.5.5 - - -From ee657da96982efef20ebaab6342c46c7e5c7af29 Mon Sep 17 00:00:00 2001 +From dbab3bc84284fa85a7cefac4f64361e9a6168e35 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 28 Feb 2013 16:52:51 +0000 -Subject: [PATCH 031/118] dwc_otg: fix potential use-after-free case in - interrupt handler +Subject: [PATCH 28/99] dwc_otg: fix potential use-after-free case in interrupt + handler If a transaction had previously aborted, certain interrupts are enabled to track error counts and reset where necessary. On IN @@ -93058,11 +93549,11 @@ index 1a23d4b..7af455d 100644 1.8.5.5 -From ce210021215a608a69375ab2aacd1137eedc57f8 Mon Sep 17 00:00:00 2001 +From 24491a9720fd180f17ed03e0bde8b8fae813bc05 Mon Sep 17 00:00:00 2001 From: P33M Date: Sun, 3 Mar 2013 14:45:53 +0000 -Subject: [PATCH 032/118] dwc_otg: add handling of SPLIT transaction data - toggle errors +Subject: [PATCH 29/99] dwc_otg: add handling of SPLIT transaction data toggle + errors Previously a data toggle error on packets from a USB1.1 device behind a TT would result in the Pi locking up as the driver never handled @@ -93116,152 +93607,10 @@ index 7af455d..a27dacd 100644 1.8.5.5 -From e526afa3a38131cefb76a8b9b629b781950b2e32 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 1 May 2013 21:14:28 +0100 -Subject: [PATCH 033/118] Add bitbanging pullups, use them for w1-gpio - -Allows parasite power to work, uses module option pullup=1 ---- - drivers/w1/masters/w1-gpio.c | 20 ++++++++++++++++++++ - drivers/w1/w1.h | 6 ++++++ - drivers/w1/w1_int.c | 16 +++++++++------- - drivers/w1/w1_io.c | 18 +++++++++++++++--- - 4 files changed, 50 insertions(+), 10 deletions(-) - -diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c -index e36b18b..3406a5a 100644 ---- a/drivers/w1/masters/w1-gpio.c -+++ b/drivers/w1/masters/w1-gpio.c -@@ -22,6 +22,9 @@ - #include "../w1.h" - #include "../w1_int.h" - -+static int w1_gpio_pullup = 0; -+module_param_named(pullup, w1_gpio_pullup, int, 0); -+ - static void w1_gpio_write_bit_dir(void *data, u8 bit) - { - struct w1_gpio_platform_data *pdata = data; -@@ -46,6 +49,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" }, -@@ -134,6 +147,13 @@ static int w1_gpio_probe(struct platform_device *pdev) - master->write_bit = w1_gpio_write_bit_dir; - } - -+ if (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"); -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 5a98649..a4d69b6 100644 ---- a/drivers/w1/w1_int.c -+++ b/drivers/w1/w1_int.c -@@ -117,19 +117,21 @@ int w1_add_master_device(struct w1_bus_master *master) - printk(KERN_ERR "w1_add_master_device: invalid function set\n"); - return(-EINVAL); - } -- /* While it would be electrically possible to make a device that -- * generated a strong pullup in bit bang mode, only hardware that -- * controls 1-wire time frames are even expected to support a strong -- * pullup. w1_io.c would need to support calling set_pullup before -- * the last write_bit operation of a w1_write_8 which it currently -- * doesn't. -- */ -+ -+ /* 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.8.5.5 - - -From c4100fa6d20d6e7931f23137bdd0a4e4c98b139f Mon Sep 17 00:00:00 2001 +From 6dcffadb2b56080b569c20528cb16d438ba57493 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 21 Mar 2013 19:36:17 +0000 -Subject: [PATCH 034/118] dwc_otg: implement tasklet for returning URBs to +Subject: [PATCH 30/99] dwc_otg: implement tasklet for returning URBs to usbcore hcd layer The dwc_otg driver interrupt handler for transfer completion will spend @@ -93503,10 +93852,10 @@ index 2b4a14e..39787e3 100644 1.8.5.5 -From 9efa748025e94bc8b25dbe56b0c6db76fd4f4684 Mon Sep 17 00:00:00 2001 +From 4195309af633ae7db0cb2e789d89cacfbb4e57b0 Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 22 Apr 2013 00:08:36 +0100 -Subject: [PATCH 036/118] dwc_otg: fix NAK holdoff and allow on split +Subject: [PATCH 32/99] dwc_otg: fix NAK holdoff and allow on split transactions only This corrects a bug where if a single active non-periodic endpoint @@ -93576,494 +93925,10 @@ index 533b17d..73f7643 100644 1.8.5.5 -From d8e5907645efd608cbe53b06f0e9f19c30e259d5 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 26 Apr 2013 10:08:31 -0700 -Subject: [PATCH 037/118] Merge pull request #286 from - martinezjavier/rpi-3.6.y-dev - -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 ef775a4..7e8b8d9 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 @@ static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd) - 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 int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream, - .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 9801410..4013d83 100755 ---- a/sound/arm/bcm2835-vchiq.c -+++ b/sound/arm/bcm2835-vchiq.c -@@ -27,6 +27,7 @@ - #include - #include - #include -+#include - - #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 @@ - - 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 @@ int bcm2835_audio_close(bcm2835_alsa_stream_t * alsa_stream) - 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 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - 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 @@ static int snd_bcm2835_alsa_probe(struct platform_device *pdev) - 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 - #include - #include -+#include - #include - - /* -@@ -110,6 +111,7 @@ enum { - 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.8.5.5 - - -From 304ada252c78a4b22e3e02b976d2f275f32a0a5e Mon Sep 17 00:00:00 2001 +From 59d748ec119f01d10e2a5c6c7ab1d9f8974e9394 Mon Sep 17 00:00:00 2001 From: Harm Hanemaaijer Date: Thu, 20 Jun 2013 20:21:39 +0200 -Subject: [PATCH 038/118] Speed up console framebuffer imageblit function +Subject: [PATCH 33/99] 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 @@ -94275,10 +94140,10 @@ index a2bb276..436494f 100644 1.8.5.5 -From 01c3d29758999e4878e810d2c3393bfd46a69020 Mon Sep 17 00:00:00 2001 +From f39e802bd68b2e12434eda71c0453cd998173187 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 13:32:11 +0300 -Subject: [PATCH 039/118] fbdev: add FBIOCOPYAREA ioctl +Subject: [PATCH 34/99] fbdev: add FBIOCOPYAREA ioctl Based on the patch authored by Ali Gholami Rudi at https://lkml.org/lkml/2009/7/13/153 @@ -94293,7 +94158,7 @@ Signed-off-by: Siarhei Siamashka 2 files changed, 35 insertions(+) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c -index 010d191..6545ce5 100644 +index 7309ac7..46984cc 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1083,6 +1083,25 @@ static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, @@ -94374,10 +94239,10 @@ index fb795c3..fa72af0 100644 1.8.5.5 -From 7a99de43320c0a65946df554f571da04e3b923fa Mon Sep 17 00:00:00 2001 +From 45c67ee11022c609f1c6c3fec98ca0c5719f658a Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Mon, 17 Jun 2013 16:00:25 +0300 -Subject: [PATCH 040/118] bcm2708_fb: DMA acceleration for fb_copyarea +Subject: [PATCH 35/99] 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 @@ -94416,8 +94281,8 @@ Signed-off-by: Luke Diamand --- arch/arm/mach-bcm2708/dma.c | 8 + arch/arm/mach-bcm2708/include/mach/dma.h | 2 + - drivers/video/bcm2708_fb.c | 277 ++++++++++++++++++++++++++++++- - 3 files changed, 282 insertions(+), 5 deletions(-) + 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 @@ -94457,7 +94322,7 @@ index ac7a4a0..6d2f9a0 100644 /* 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 08d9238..5758146 100644 +index 54cd760..798eb52 100644 --- a/drivers/video/bcm2708_fb.c +++ b/drivers/video/bcm2708_fb.c @@ -21,13 +21,16 @@ @@ -94477,19 +94342,18 @@ index 08d9238..5758146 100644 #include #include -@@ -46,6 +49,11 @@ - - #define DRIVER_NAME "bcm2708_fb" +@@ -51,6 +54,10 @@ + 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 { -@@ -57,16 +65,73 @@ struct fbinfo_s { +@@ -62,16 +69,73 @@ struct fbinfo_s { u16 cmap[256]; }; @@ -94563,7 +94427,7 @@ index 08d9238..5758146 100644 static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var) { int ret = 0; -@@ -312,11 +377,148 @@ static void bcm2708_fb_fillrect(struct fb_info *info, +@@ -322,11 +386,148 @@ static void bcm2708_fb_fillrect(struct fb_info *info, cfb_fillrect(info, rect); } @@ -94607,7 +94471,7 @@ index 08d9238..5758146 100644 + + /* Fallback to cfb_copyarea() if we don't like something */ + if (bytes_per_pixel > 4 || -+ info->var.xres > 1920 || info->var.yres > 1200 || ++ 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 || @@ -94714,7 +94578,7 @@ index 08d9238..5758146 100644 } static void bcm2708_fb_imageblit(struct fb_info *info, -@@ -326,6 +528,24 @@ 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); } @@ -94739,7 +94603,7 @@ index 08d9238..5758146 100644 static struct fb_ops bcm2708_fb_ops = { .owner = THIS_MODULE, .fb_check_var = bcm2708_fb_check_var, -@@ -359,7 +579,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) +@@ -365,7 +584,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) fb->dma = dma; } fb->fb.fbops = &bcm2708_fb_ops; @@ -94748,7 +94612,7 @@ index 08d9238..5758146 100644 fb->fb.pseudo_palette = fb->cmap; strncpy(fb->fb.fix.id, bcm2708_name, sizeof(fb->fb.fix.id)); -@@ -390,6 +610,7 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) +@@ -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); @@ -94756,7 +94620,7 @@ index 08d9238..5758146 100644 /* * Allocate colourmap. -@@ -415,14 +636,48 @@ static int bcm2708_fb_probe(struct platform_device *dev) +@@ -421,14 +641,45 @@ static int bcm2708_fb_probe(struct platform_device *dev) struct bcm2708_fb *fb; int ret; @@ -94772,9 +94636,6 @@ index 08d9238..5758146 100644 + + bcm2708_fb_debugfs_init(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) { @@ -94807,7 +94668,7 @@ index 08d9238..5758146 100644 fb->dev = dev; -@@ -432,6 +687,11 @@ static int bcm2708_fb_probe(struct platform_device *dev) +@@ -438,6 +689,11 @@ static int bcm2708_fb_probe(struct platform_device *dev) goto out; } @@ -94819,7 +94680,7 @@ index 08d9238..5758146 100644 kfree(fb); free_region: dev_err(&dev->dev, "probe failed, err %d\n", ret); -@@ -449,8 +709,15 @@ static int bcm2708_fb_remove(struct platform_device *dev) +@@ -455,8 +711,15 @@ static int bcm2708_fb_remove(struct platform_device *dev) iounmap(fb->fb.screen_base); unregister_framebuffer(&fb->fb); @@ -94839,11 +94700,11 @@ index 08d9238..5758146 100644 1.8.5.5 -From a5c2e4372e5b892aadcf6eb5ea08e355a991c1a5 Mon Sep 17 00:00:00 2001 +From bd56f4f39703a8f6f46d2f63ac23b486dacd10b4 Mon Sep 17 00:00:00 2001 From: Mike Bradley Date: Mon, 17 Jun 2013 11:31:42 -0700 -Subject: [PATCH 041/118] dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock - held in completion handler +Subject: [PATCH 36/99] dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held + in completion handler usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it asynchronously in the tasklet was not safe (regression in @@ -94929,10 +94790,10 @@ index 39787e3..5e6a26a 100644 1.8.5.5 -From c82a3807e407eefbcf3d02269db68aeffe275fb1 Mon Sep 17 00:00:00 2001 +From a7f55afed48de1afa47097cf7d4dc314dea44946 Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Thu, 4 Apr 2013 11:05:21 +0100 -Subject: [PATCH 042/118] USB fix using a FIQ to implement split transactions +Subject: [PATCH 37/99] USB fix using a FIQ to implement split transactions This commit adds a FIQ implementaion that schedules the split transactions using a FIQ so we don't get @@ -96335,10 +96196,10 @@ index 1b1f83c..c8590b5 100644 1.8.5.5 -From 33225b47385659254dffa2f5f90ae5ae957fd7c6 Mon Sep 17 00:00:00 2001 +From b7fc5de2d54dae4b3889384e524f863ce7cb58d1 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Wed, 3 Jul 2013 11:39:46 +0100 -Subject: [PATCH 043/118] dwc_otg: fix device attributes and avoid kernel +Subject: [PATCH 38/99] dwc_otg: fix device attributes and avoid kernel warnings on boot --- @@ -96407,10 +96268,10 @@ index fab2961..af1cd4d 100644 1.8.5.5 -From 6715dbdc6c42689ff113319eb296f5c251a47842 Mon Sep 17 00:00:00 2001 +From d58a8048d44a07bd96fc424494030f68fdb3424f Mon Sep 17 00:00:00 2001 From: popcornmix Date: Mon, 15 Jul 2013 23:55:52 +0100 -Subject: [PATCH 044/118] dcw_otg: avoid logging function that can cause panics +Subject: [PATCH 39/99] dcw_otg: avoid logging function that can cause panics See: https://github.com/raspberrypi/firmware/issues/21 Thanks to cleverca22 for fix @@ -96435,10 +96296,10 @@ index af1cd4d..9da0c92 100644 1.8.5.5 -From 7956897b4cb174b4bdfdf3c1b64e64462ce167de Mon Sep 17 00:00:00 2001 +From f0a3071aee6b34f28a0a9d80f17bf6954c53f6a9 Mon Sep 17 00:00:00 2001 From: P33M Date: Sat, 13 Jul 2013 20:41:26 +0100 -Subject: [PATCH 045/118] dwc_otg: mask correct interrupts after transaction +Subject: [PATCH 40/99] dwc_otg: mask correct interrupts after transaction error recovery The dwc_otg driver will unmask certain interrupts on a transaction @@ -96505,10 +96366,10 @@ index 8e5789f..fd73e41 100644 1.8.5.5 -From 724a3815cc971ed359f6c428ed97f63c6af7ef3d Mon Sep 17 00:00:00 2001 +From c58f0588a7dc634988251890ca78338822608f09 Mon Sep 17 00:00:00 2001 From: P33M Date: Sat, 13 Jul 2013 21:48:41 +0100 -Subject: [PATCH 046/118] dwc_otg: fiq: prevent FIQ thrash and incorrect state +Subject: [PATCH 41/99] dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ In the case of a transaction to a device that had previously aborted @@ -96565,10 +96426,10 @@ index fd73e41..2ec0565 100644 1.8.5.5 -From 70d4491a918dc3c707a457c30613f7e15684e6da Mon Sep 17 00:00:00 2001 +From b1c52d48103059a6a4b93155d75a15cb36b6c42c Mon Sep 17 00:00:00 2001 From: Gordon Hollingworth Date: Mon, 8 Jul 2013 04:12:19 +0100 -Subject: [PATCH 047/118] Fix function tracing +Subject: [PATCH 42/99] Fix function tracing --- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 12 ++++++------ @@ -96633,10 +96494,10 @@ index 2ec0565..083b1c3 100644 1.8.5.5 -From 1b9ee97106009cb77a72576fc9e29a70d9cdad8d Mon Sep 17 00:00:00 2001 +From 5e97aa39101eff9509e8357d4ed67139e0bc7939 Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 18 Jul 2013 16:32:41 +0100 -Subject: [PATCH 048/118] dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue +Subject: [PATCH 43/99] dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue --- drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 53 ++++++++++++++-------------- @@ -96723,10 +96584,10 @@ index d1c5c2b..315c803 100644 1.8.5.5 -From 828d4e2b7b3896b353cc825a981e89114f1e8e59 Mon Sep 17 00:00:00 2001 +From 63964d241251a31790aba16abd383882f6c2a2db Mon Sep 17 00:00:00 2001 From: P33M Date: Thu, 18 Jul 2013 17:07:26 +0100 -Subject: [PATCH 049/118] dwc_otg: prevent OOPSes during device disconnects +Subject: [PATCH 44/99] dwc_otg: prevent OOPSes during device disconnects The dwc_otg_urb_enqueue function is thread-unsafe. In particular the access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and @@ -96867,11 +96728,11 @@ index 7b92025..db95851 100644 1.8.5.5 -From e0db7b3195299165df9171196594ad534774418d Mon Sep 17 00:00:00 2001 +From d4856e0a30f5a31f905ed5561e7f610b6cad3c6b Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 22 Jul 2013 14:08:26 +0100 -Subject: [PATCH 050/118] dwc_otg: prevent BUG() in TT allocation if hub - address is > 16 +Subject: [PATCH 45/99] dwc_otg: prevent BUG() in TT allocation if hub address + is > 16 A fixed-size array is used to track TT allocation. This was previously set to 16 which caused a crash because @@ -96960,10 +96821,10 @@ index 083b1c3..c76910d 100644 1.8.5.5 -From 0fedfce7e6a3cde771ca27059257ec86d1efb86d Mon Sep 17 00:00:00 2001 +From 1c1e2b546778044e32a989ccb07f638ec5e8eadf Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 23 Jul 2013 14:15:32 +0100 -Subject: [PATCH 051/118] dwc_otg: make channel halts with unknown state less +Subject: [PATCH 46/99] dwc_otg: make channel halts with unknown state less damaging If the IRQ received a channel halt interrupt through the FIQ @@ -97008,10 +96869,10 @@ index c76910d..5fd8613 100644 1.8.5.5 -From f1f3ec6fb1fd086b99a07baab3ba15426aae3498 Mon Sep 17 00:00:00 2001 +From 85b9d9d3593dbc845eeeeb5ecc90e64d457216d5 Mon Sep 17 00:00:00 2001 From: P33M Date: Tue, 30 Jul 2013 09:58:48 +0100 -Subject: [PATCH 052/118] dwc_otg: fiq_split: use TTs with more granularity +Subject: [PATCH 47/99] dwc_otg: fiq_split: use TTs with more granularity This fixes certain issues with split transaction scheduling. @@ -97131,10 +96992,10 @@ index 5fd8613..a959a49 100644 1.8.5.5 -From d5b29b9e5d5b406defbb02ffa1b7bd1463704683 Mon Sep 17 00:00:00 2001 +From 1f2a0a8c019181b0d1c6068d0810c7a2f2982c35 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 2 Aug 2013 10:04:18 +0100 -Subject: [PATCH 053/118] dwc_otg: fix potential sleep while atomic during urb +Subject: [PATCH 48/99] dwc_otg: fix potential sleep while atomic during urb enqueue Fixes a regression introduced with eb1b482a. Kmalloc called from @@ -97163,10 +97024,10 @@ index 87e517d..88c0544 100644 1.8.5.5 -From d507486937ab5ed022ca94f5ee961fbeb26f5bd2 Mon Sep 17 00:00:00 2001 +From c73caf9c9004469745cc90fc639d0407f93ede4a Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 5 Aug 2013 11:42:12 +0100 -Subject: [PATCH 054/118] dwc_otg: make fiq_split_enable imply fiq_fix_enable +Subject: [PATCH 49/99] dwc_otg: make fiq_split_enable imply fiq_fix_enable Failing to set up the FIQ correctly would result in "IRQ 32: nobody cared" errors in dmesg. @@ -97195,10 +97056,10 @@ index 176dc14..f06c3d22 100644 1.8.5.5 -From f9d8ce418fcfbf659080642128342292f1eb6aa6 Mon Sep 17 00:00:00 2001 +From 112427bd8d221af2c710141f288c1de732027cae Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 5 Aug 2013 11:47:12 +0100 -Subject: [PATCH 055/118] dwc_otg: prevent crashes on host port disconnects +Subject: [PATCH 50/99] dwc_otg: prevent crashes on host port disconnects Fix several issues resulting in crashes or inconsistent state if a Model A root port was disconnected. @@ -97356,10 +97217,10 @@ index 88c0544..ae4271a 100644 1.8.5.5 -From 18bcab977236ee34c9ca63238ad0f5bba82cbdf4 Mon Sep 17 00:00:00 2001 +From e33517d8bd9cfb06814f672cbf0c986c057ef160 Mon Sep 17 00:00:00 2001 From: P33M Date: Mon, 5 Aug 2013 13:17:58 +0100 -Subject: [PATCH 056/118] dwc_otg: prevent leaking URBs during enqueue +Subject: [PATCH 51/99] dwc_otg: prevent leaking URBs during enqueue A dwc_otg_urb would get leaked if the HCD enqueue function failed for any reason. Free the URB at the appropriate points. @@ -97395,10 +97256,10 @@ index ae4271a..ee8eec9 100644 1.8.5.5 -From c0e38a3d105f84860b73b327ac02b5cbee036938 Mon Sep 17 00:00:00 2001 +From e3129c44448e5b007a4a888c7f5c44b24a53a498 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 20 Sep 2013 16:08:27 +0100 -Subject: [PATCH 057/118] dwc_otg: Enable NAK holdoff for control split +Subject: [PATCH 52/99] dwc_otg: Enable NAK holdoff for control split transactions Certain low-speed devices take a very long time to complete a @@ -97431,11 +97292,11 @@ index 3a549a1..f8dc4be 100644 1.8.5.5 -From abdb20fe85a4dcaaf877c2778734c054f701a9e3 Mon Sep 17 00:00:00 2001 +From 22679a405b4fed3f7bb1c3ab77eac98777b72d21 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Fri, 20 Sep 2013 19:07:56 +0100 -Subject: [PATCH 058/118] dwc_otg: Fix for occasional lockup on boot when doing - a USB reset +Subject: [PATCH 53/99] dwc_otg: Fix for occasional lockup on boot when doing a + USB reset --- drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 4 ++-- @@ -97460,10 +97321,10 @@ index f8dc4be..64d33a5 100644 1.8.5.5 -From 3dbbefad45b95e9435b23478c964f535f6f86e01 Mon Sep 17 00:00:00 2001 +From c30038e0d03a58de9014899834565d7abdd21bc7 Mon Sep 17 00:00:00 2001 From: P33M Date: Fri, 27 Sep 2013 14:42:24 +0100 -Subject: [PATCH 059/118] dwc_otg: Don't issue traffic to LS devices in FS mode +Subject: [PATCH 54/99] dwc_otg: Don't issue traffic to LS devices in FS mode Issuing low-speed packets when the root port is in full-speed mode causes the root port to stop responding. Explicitly fail when @@ -97505,332 +97366,10 @@ index 1904f6a..22300f0 100644 1.8.5.5 -From 735c2ecc454d92796356c38b5a433351c4f8717a Mon Sep 17 00:00:00 2001 -From: Andrey Vagin -Date: Wed, 6 Nov 2013 13:25:20 +0400 -Subject: [PATCH 060/118] ARM: bcm2708: PL01X debug include was moved into - arch/arm/include/debug/ - ---- - arch/arm/mach-bcm2708/include/mach/debug-macro.S | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/arch/arm/mach-bcm2708/include/mach/debug-macro.S b/arch/arm/mach-bcm2708/include/mach/debug-macro.S -index 2d0dc1c..b24304a 100644 ---- a/arch/arm/mach-bcm2708/include/mach/debug-macro.S -+++ b/arch/arm/mach-bcm2708/include/mach/debug-macro.S -@@ -19,4 +19,4 @@ - ldr \rv, =IO_ADDRESS(UART0_BASE) - .endm - --#include -+#include --- -1.8.5.5 - - -From c6ec0b565d1ba18d2b76fc8bc4371bfa09353272 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 20 Nov 2013 11:22:05 +0000 -Subject: [PATCH 062/118] sdhci: Only do one iteration of PIO reading loop - ---- - drivers/mmc/host/sdhci.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c -index 0b44ccf..51bb441 100644 ---- a/drivers/mmc/host/sdhci.c -+++ b/drivers/mmc/host/sdhci.c -@@ -550,6 +550,7 @@ static void sdhci_transfer_pio(struct sdhci_host *host, u32 intstate) - break; - state = sdhci_readl(host, SDHCI_PRESENT_STATE); - available = state & mask; -+ break; - } - - DBG("PIO transfer complete - %d blocks left.\n", host->blocks); --- -1.8.5.5 - - -From 8cfcfbb7919f5b34739e2427d9485c55d758ef32 Mon Sep 17 00:00:00 2001 -From: Vincent Sanders -Date: Mon, 2 Sep 2013 16:44:57 +0100 -Subject: [PATCH 063/118] vchiq: create_pagelist copes with vmalloc memory - -Signed-off-by: Daniel Stone ---- - .../interface/vchiq_arm/vchiq_2835_arm.c | 83 ++++++++++++++-------- - 1 file changed, 53 insertions(+), 30 deletions(-) - -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 2b5fa56..b3bdaa2 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 -@@ -374,6 +374,7 @@ - unsigned int num_pages, offset, i; - char *addr, *base_addr, *next_addr; - int run, addridx, actual_pages; -+ unsigned long *need_release; - - offset = (unsigned int)buf & (PAGE_SIZE - 1); - num_pages = (count + offset + PAGE_SIZE - 1) / PAGE_SIZE; -@@ -384,9 +385,10 @@ - ** list - */ - pagelist = kmalloc(sizeof(PAGELIST_T) + -- (num_pages * sizeof(unsigned long)) + -- (num_pages * sizeof(pages[0])), -- GFP_KERNEL); -+ (num_pages * sizeof(unsigned long)) + -+ sizeof(unsigned long) + -+ (num_pages * sizeof(pages[0])), -+ GFP_KERNEL); - - vchiq_log_trace(vchiq_arm_log_level, - "create_pagelist - %x", (unsigned int)pagelist); -@@ -394,28 +396,44 @@ - return -ENOMEM; - - addrs = pagelist->addrs; -- pages = (struct page **)(addrs + num_pages); -+ need_release = (unsigned long *)(addrs + num_pages); -+ pages = (struct page **)(addrs + num_pages + 1); - -- down_read(&task->mm->mmap_sem); -- actual_pages = get_user_pages(task, task->mm, -- (unsigned long)buf & ~(PAGE_SIZE - 1), num_pages, -- (type == PAGELIST_READ) /*Write */ , 0 /*Force */ , -- pages, NULL /*vmas */); -- up_read(&task->mm->mmap_sem); -- -- if (actual_pages != num_pages) -- { -- /* This is probably due to the process being killed */ -- while (actual_pages > 0) -- { -- actual_pages--; -- page_cache_release(pages[actual_pages]); -- } -- kfree(pagelist); -- if (actual_pages == 0) -- actual_pages = -ENOMEM; -- return actual_pages; -- } -+ if (is_vmalloc_addr(buf)) { -+ for (actual_pages = 0; actual_pages < num_pages; actual_pages++) { -+ pages[actual_pages] = vmalloc_to_page(buf + (actual_pages * PAGE_SIZE)); -+ } -+ *need_release = 0; /* do not try and release vmalloc pages */ -+ } else { -+ down_read(&task->mm->mmap_sem); -+ actual_pages = get_user_pages(task, task->mm, -+ (unsigned long)buf & ~(PAGE_SIZE - 1), -+ num_pages, -+ (type == PAGELIST_READ) /*Write */ , -+ 0 /*Force */ , -+ pages, -+ NULL /*vmas */); -+ up_read(&task->mm->mmap_sem); -+ -+ if (actual_pages != num_pages) { -+ vchiq_log_info(vchiq_arm_log_level, -+ "create_pagelist - only %d/%d pages locked", -+ actual_pages, -+ num_pages); -+ -+ /* This is probably due to the process being killed */ -+ while (actual_pages > 0) -+ { -+ actual_pages--; -+ page_cache_release(pages[actual_pages]); -+ } -+ kfree(pagelist); -+ if (actual_pages == 0) -+ actual_pages = -ENOMEM; -+ return actual_pages; -+ } -+ *need_release = 1; /* release user pages */ -+ } - - pagelist->length = count; - pagelist->type = type; -@@ -482,6 +500,7 @@ - static void - free_pagelist(PAGELIST_T *pagelist, int actual) - { -+ unsigned long *need_release; - struct page **pages; - unsigned int num_pages, i; - -@@ -492,7 +511,8 @@ - (pagelist->length + pagelist->offset + PAGE_SIZE - 1) / - PAGE_SIZE; - -- pages = (struct page **)(pagelist->addrs + num_pages); -+ need_release = (unsigned long *)(pagelist->addrs + num_pages); -+ pages = (struct page **)(pagelist->addrs + num_pages + 1); - - /* Deal with any partial cache lines (fragments) */ - if (pagelist->type >= PAGELIST_READ_WITH_FRAGMENTS) { -@@ -528,11 +548,14 @@ - up(&g_free_fragments_sema); - } - -- for (i = 0; i < num_pages; i++) { -- if (pagelist->type != PAGELIST_WRITE) -- set_page_dirty(pages[i]); -- page_cache_release(pages[i]); -- } -+ if (*need_release) { -+ for (i = 0; i < num_pages; i++) { -+ if (pagelist->type != PAGELIST_WRITE) -+ set_page_dirty(pages[i]); -+ -+ page_cache_release(pages[i]); -+ } -+ } - - kfree(pagelist); - } --- -1.8.5.5 - - -From 6e50439b3e683c94c6dd281a540437acb745e0df Mon Sep 17 00:00:00 2001 -From: Vincent Sanders -Date: Mon, 30 Sep 2013 17:04:55 +0100 -Subject: [PATCH 064/118] vchiq: fix the shim message release - -Signed-off-by: Daniel Stone ---- - .../vc04_services/interface/vchiq_arm/vchiq_shim.c | 47 +++++++++++++--------- - 1 file changed, 29 insertions(+), 18 deletions(-) - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -index f752f8d..fe9bd80 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -@@ -545,47 +545,58 @@ static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, - SHIM_SERVICE_T *service = - (SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle); - -+ if (!service->callback) -+ goto release; -+ - switch (reason) { - case VCHIQ_MESSAGE_AVAILABLE: - vchiu_queue_push(&service->queue, header); - -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_MSG_AVAILABLE, NULL); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_MSG_AVAILABLE, NULL); -+ -+ goto done; - break; -+ - case VCHIQ_BULK_TRANSMIT_DONE: -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_BULK_SENT, bulk_user); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_SENT, bulk_user); - break; -+ - case VCHIQ_BULK_RECEIVE_DONE: -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_BULK_RECEIVED, bulk_user); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_RECEIVED, bulk_user); - break; -+ - case VCHIQ_SERVICE_CLOSED: -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_SERVICE_CLOSED, NULL); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_SERVICE_CLOSED, NULL); - break; -+ - case VCHIQ_SERVICE_OPENED: - /* No equivalent VCHI reason */ - break; -+ - case VCHIQ_BULK_TRANSMIT_ABORTED: -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, bulk_user); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, -+ bulk_user); - break; -+ - case VCHIQ_BULK_RECEIVE_ABORTED: -- if (service->callback) -- service->callback(service->callback_param, -- VCHI_CALLBACK_BULK_RECEIVE_ABORTED, bulk_user); -+ service->callback(service->callback_param, -+ VCHI_CALLBACK_BULK_RECEIVE_ABORTED, -+ bulk_user); - break; -+ - default: - WARN(1, "not supported\n"); - break; - } - -+release: -+ vchiq_release_message(service->handle, header); -+done: - return VCHIQ_SUCCESS; - } - --- -1.8.5.5 - - -From 785f412f8c6c490697f01f301e5e7cd5b49047a7 Mon Sep 17 00:00:00 2001 -From: Vincent Sanders -Date: Sat, 9 Nov 2013 22:37:21 +0000 -Subject: [PATCH 065/118] vchiq: export additional symbols - -Signed-off-by: Daniel Stone ---- - drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -index fe9bd80..a0b069d 100644 ---- a/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -+++ b/drivers/misc/vc04_services/interface/vchiq_arm/vchiq_shim.c -@@ -405,6 +405,7 @@ int32_t vchi_held_msg_release(VCHI_HELD_MSG_T *message) - - return 0; - } -+EXPORT_SYMBOL(vchi_held_msg_release); - - /*********************************************************** - * Name: vchi_msg_hold -@@ -450,6 +451,7 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, - - return 0; - } -+EXPORT_SYMBOL(vchi_msg_hold); - - /*********************************************************** - * Name: vchi_initialise --- -1.8.5.5 - - -From 4772295c67c6d5d85adb08d0185ad29eb1a4f1e3 Mon Sep 17 00:00:00 2001 +From bfb8817dcfaf51eb4c1ad66bc61a44011f2de160 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 30 Jan 2013 12:45:18 +0000 -Subject: [PATCH 066/118] bcm2835: add v4l2 camera device +Subject: [PATCH 55/99] bcm2835: add v4l2 camera device - Supports raw YUV capture, preview, JPEG and H264. - Uses videobuf2 for data transfer, using dma_buf. @@ -97942,10 +97481,10 @@ index 0000000..c585a8f + +$ v4l2-ctl --list-formats diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig -index d7f0249..1b5beaa 100644 +index b2a4403..c1f82ec 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig -@@ -124,6 +124,7 @@ config VIDEO_S3C_CAMIF +@@ -118,6 +118,7 @@ config VIDEO_S3C_CAMIF source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" @@ -97954,10 +97493,10 @@ index d7f0249..1b5beaa 100644 endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile -index 1348ba1..32cc20c 100644 +index e5269da..6e01549 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile -@@ -54,4 +54,6 @@ obj-y += davinci/ +@@ -51,4 +51,6 @@ obj-y += davinci/ obj-$(CONFIG_ARCH_OMAP) += omap/ @@ -103818,10 +103357,10 @@ index 0000000..9d1d11e 1.8.5.5 -From 7a96548599c1ee1bc3f22eafb182d4e09cf7ce27 Mon Sep 17 00:00:00 2001 +From f4db14f09a0f18e1928e001d15eb464afb86d65a Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 10:58:01 +0000 -Subject: [PATCH 067/118] V4L2: Fix EV values. Add manual shutter speed control +Subject: [PATCH 56/99] V4L2: Fix EV values. Add manual shutter speed control V4L2 EV values should be in units of 1/1000. Corrected. Add support for V4L2_CID_EXPOSURE_ABSOLUTE which should @@ -104014,10 +103553,10 @@ index c611b58..d8aace5 100644 1.8.5.5 -From 8685612473d99215c05e210c874e3a4ac7c4fc5c Mon Sep 17 00:00:00 2001 +From 66ec3c1715c848316f716c7f62f82b86e9d2a3a9 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 11:01:53 +0000 -Subject: [PATCH 068/118] V4L2: Correct JPEG Q-factor range +Subject: [PATCH 57/99] V4L2: Correct JPEG Q-factor range Should be 1-100, not 0-100 @@ -104055,10 +103594,10 @@ index 481d1f6..c2e4c64 100644 1.8.5.5 -From c9e2f7677cfb88843486e8094c47637c04fc7e3a Mon Sep 17 00:00:00 2001 +From 3cea6db49e58e3db348f668c52df0470d8e4bd1e Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 11:05:24 +0000 -Subject: [PATCH 069/118] V4L2: Fix issue of driver jamming if STREAMON failed. +Subject: [PATCH 58/99] V4L2: Fix issue of driver jamming if STREAMON failed. Fix issue where the driver was left in a partially enabled state if STREAMON failed, and would then reject many IOCTLs @@ -104094,10 +103633,10 @@ index 47fe45d..2743074 100644 1.8.5.5 -From 97566a4a5b2c17854307e0b3072192377c56e35a Mon Sep 17 00:00:00 2001 +From cd6acf6546bc8bc163e7d7a1b351d9766b5b28d5 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 15:30:48 +0000 -Subject: [PATCH 070/118] V4L2: Fix ISO controls. +Subject: [PATCH 59/99] V4L2: Fix ISO controls. Driver was passing the index to the GPU, and not the desired ISO value. @@ -104150,10 +103689,10 @@ index c2e4c64..92863f7 100644 1.8.5.5 -From aba70d881dcd2d57a2d8f3aa773b1e06f8ecc67b Mon Sep 17 00:00:00 2001 +From f24dcf1ecb8c1955f121e4a5e1f72011f9c99dcc Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 16:40:24 +0000 -Subject: [PATCH 071/118] V4L2: Add flicker avoidance controls +Subject: [PATCH 60/99] V4L2: Add flicker avoidance controls Add support for V4L2_CID_POWER_LINE_FREQUENCY to set flicker avoidance frequencies. @@ -104268,10 +103807,10 @@ index d8aace5..b3d2c39 100644 1.8.5.5 -From 53f023560be354a1cd705c0285ebbd30d2c99c68 Mon Sep 17 00:00:00 2001 +From 3eaa5a99d484b34e0b732f3a9310ab36e32c77c2 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 13 Dec 2013 15:54:13 +0000 -Subject: [PATCH 072/118] V4L2: Add support for frame rate control. +Subject: [PATCH 61/99] V4L2: Add support for frame rate control. Add support for frame rate (or time per frame as V4L2 inverts it) control via s_parm. @@ -104510,10 +104049,10 @@ index b3d2c39..0f2bd50 100644 1.8.5.5 -From 9acbcbb3ce1b58f979d886f8aa4e42d0f944c917 Mon Sep 17 00:00:00 2001 +From a7e0b024773713e40af1c11b6779f0dde0eeac12 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 17:30:09 +0000 -Subject: [PATCH 073/118] V4L2: Improve G_FBUF handling so we pass conformance +Subject: [PATCH 62/99] V4L2: Improve G_FBUF handling so we pass conformance Return some sane numbers for get framebuffer so that we pass conformance. @@ -104553,10 +104092,10 @@ index 8c38d03..c8d8742 100644 1.8.5.5 -From 01136b3aab4652571e7a42dbb7ef8b6798130888 Mon Sep 17 00:00:00 2001 +From 733f611f4a8040b4dede7676339ff6cb59758a45 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 17:29:39 +0000 -Subject: [PATCH 074/118] V4L2: Fix information advertised through g_vidfmt +Subject: [PATCH 63/99] V4L2: Fix information advertised through g_vidfmt Width and height were being stored based on incorrect values. @@ -104596,10 +104135,10 @@ index c8d8742..4766a9c 100644 1.8.5.5 -From ef74a3536e8cf93a9c630a70ff5502fe25db428e Mon Sep 17 00:00:00 2001 +From 1ef32d6f55e5d53ab3e8ebf442ea43d176c34206 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 11:03:54 +0000 -Subject: [PATCH 075/118] V4L2: Add support for inline H264 headers +Subject: [PATCH 64/99] V4L2: Add support for inline H264 headers Add support for V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER to control H264 inline headers. @@ -104904,10 +104443,10 @@ index 0f2bd50..b08a4b0 100644 1.8.5.5 -From 503a4ab2ba3cf2cf3db98db159b8ba5632d86a56 Mon Sep 17 00:00:00 2001 +From 0b2e0899df49b039e2ffe74e74dde071794f0a30 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 19 Dec 2013 17:33:02 +0000 -Subject: [PATCH 076/118] V4L2: Fix JPEG timestamp issue +Subject: [PATCH 65/99] V4L2: Fix JPEG timestamp issue JPEG images were coming through from the GPU with timestamp of 0. Detect this and give current system time instead @@ -104945,10 +104484,10 @@ index 4766a9c..9fc90a2 100644 1.8.5.5 -From 9cd88da96f8767bb4c63c57c0abca5ec1dfd52d5 Mon Sep 17 00:00:00 2001 +From b46a6974a6ea0cc6173dd4104966e9168ecad874 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 9 Dec 2013 11:24:55 +0000 -Subject: [PATCH 077/118] V4L2: Fix issue when switching down JPEG resolution. +Subject: [PATCH 66/99] V4L2: Fix issue when switching down JPEG resolution. JPEG buffer size calculation is based on input resolution. Input resolution was being configured after output port @@ -105110,4515 +104649,10 @@ index 9fc90a2..4780107 100644 1.8.5.5 -From 598426f6c1e6f178430514a052b351746d344aba Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 2 Dec 2013 16:57:44 +0000 -Subject: [PATCH 078/118] config: Enable V4L / MMAL driver - ---- - arch/arm/configs/bcmrpi_defconfig | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig -index 88f930c..7d9cbd5 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -686,6 +686,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m - CONFIG_VIDEO_EM28XX=m - CONFIG_VIDEO_EM28XX_ALSA=m - CONFIG_VIDEO_EM28XX_DVB=m -+CONFIG_V4L_PLATFORM_DRIVERS=y -+CONFIG_VIDEO_BCM2835=y -+CONFIG_VIDEO_BCM2835_MMAL=m - CONFIG_RADIO_SI470X=y - CONFIG_USB_SI470X=m - CONFIG_I2C_SI470X=m --- -1.8.5.5 - - -From 015eb6a4407c1c2aa103590c7624d1a15e80eca3 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Thu, 9 Jan 2014 16:05:20 +0000 -Subject: [PATCH 079/118] gpio: support low and high level interrupts - ---- - arch/arm/mach-bcm2708/bcm2708_gpio.c | 52 +++++++++++++++++++++++++----------- - 1 file changed, 37 insertions(+), 15 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708_gpio.c b/arch/arm/mach-bcm2708/bcm2708_gpio.c -index d0339eb..bab8a49 100644 ---- a/arch/arm/mach-bcm2708/bcm2708_gpio.c -+++ b/arch/arm/mach-bcm2708/bcm2708_gpio.c -@@ -58,6 +58,8 @@ struct bcm2708_gpio { - struct gpio_chip gc; - unsigned long rising; - unsigned long falling; -+ unsigned long high; -+ unsigned long low; - }; - - static int bcm2708_set_function(struct gpio_chip *gc, unsigned offset, -@@ -145,20 +147,22 @@ static int bcm2708_gpio_irq_set_type(struct irq_data *d, unsigned type) - unsigned irq = d->irq; - struct bcm2708_gpio *gpio = irq_get_chip_data(irq); - -- if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) -+ gpio->rising &= ~(1 << irq_to_gpio(irq)); -+ gpio->falling &= ~(1 << irq_to_gpio(irq)); -+ gpio->high &= ~(1 << irq_to_gpio(irq)); -+ gpio->low &= ~(1 << irq_to_gpio(irq)); -+ -+ if (type & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING | IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - return -EINVAL; - -- if (type & IRQ_TYPE_EDGE_RISING) { -+ if (type & IRQ_TYPE_EDGE_RISING) - gpio->rising |= (1 << irq_to_gpio(irq)); -- } else { -- gpio->rising &= ~(1 << irq_to_gpio(irq)); -- } -- -- if (type & IRQ_TYPE_EDGE_FALLING) { -+ if (type & IRQ_TYPE_EDGE_FALLING) - gpio->falling |= (1 << irq_to_gpio(irq)); -- } else { -- gpio->falling &= ~(1 << irq_to_gpio(irq)); -- } -+ if (type & IRQ_TYPE_LEVEL_HIGH) -+ gpio->high |= (1 << irq_to_gpio(irq)); -+ if (type & IRQ_TYPE_LEVEL_LOW) -+ gpio->low |= (1 << irq_to_gpio(irq)); - return 0; - } - -@@ -168,13 +172,17 @@ static void bcm2708_gpio_irq_mask(struct irq_data *d) - struct bcm2708_gpio *gpio = irq_get_chip_data(irq); - unsigned gn = irq_to_gpio(irq); - unsigned gb = gn / 32; -- unsigned long rising = readl(gpio->base + GPIOREN(gb)); -+ unsigned long rising = readl(gpio->base + GPIOREN(gb)); - unsigned long falling = readl(gpio->base + GPIOFEN(gb)); -+ unsigned long high = readl(gpio->base + GPIOHEN(gb)); -+ unsigned long low = readl(gpio->base + GPIOLEN(gb)); - - gn = gn % 32; - -- writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); -+ writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); - writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); -+ writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); -+ writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); - } - - static void bcm2708_gpio_irq_unmask(struct irq_data *d) -@@ -183,24 +191,38 @@ static void bcm2708_gpio_irq_unmask(struct irq_data *d) - struct bcm2708_gpio *gpio = irq_get_chip_data(irq); - unsigned gn = irq_to_gpio(irq); - unsigned gb = gn / 32; -- unsigned long rising = readl(gpio->base + GPIOREN(gb)); -+ unsigned long rising = readl(gpio->base + GPIOREN(gb)); - unsigned long falling = readl(gpio->base + GPIOFEN(gb)); -+ unsigned long high = readl(gpio->base + GPIOHEN(gb)); -+ unsigned long low = readl(gpio->base + GPIOLEN(gb)); - - gn = gn % 32; - - writel(1 << gn, gpio->base + GPIOEDS(gb)); - - if (gpio->rising & (1 << gn)) { -- writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); -+ writel(rising | (1 << gn), gpio->base + GPIOREN(gb)); - } else { - writel(rising & ~(1 << gn), gpio->base + GPIOREN(gb)); - } - - if (gpio->falling & (1 << gn)) { -- writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); -+ writel(falling | (1 << gn), gpio->base + GPIOFEN(gb)); - } else { - writel(falling & ~(1 << gn), gpio->base + GPIOFEN(gb)); - } -+ -+ if (gpio->high & (1 << gn)) { -+ writel(high | (1 << gn), gpio->base + GPIOHEN(gb)); -+ } else { -+ writel(high & ~(1 << gn), gpio->base + GPIOHEN(gb)); -+ } -+ -+ if (gpio->low & (1 << gn)) { -+ writel(low | (1 << gn), gpio->base + GPIOLEN(gb)); -+ } else { -+ writel(low & ~(1 << gn), gpio->base + GPIOLEN(gb)); -+ } - } - - static struct irq_chip bcm2708_irqchip = { --- -1.8.5.5 - - -From 52b470e0263186c7711d29eb390da3a9e0b66820 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 18 Dec 2013 22:16:19 +0000 -Subject: [PATCH 080/118] 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 7d9cbd5..a6ef4ca 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 271acd8..8a48169 100644 ---- a/kernel/cgroup.c -+++ b/kernel/cgroup.c -@@ -5485,6 +5485,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 f506001..b6999fe 100644 ---- a/mm/memcontrol.c -+++ b/mm/memcontrol.c -@@ -7043,6 +7043,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.8.5.5 - - -From eff8448bb6be88b1ce948241626005b18d5831df Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Mon, 27 Jan 2014 21:00:56 +0000 -Subject: [PATCH 081/118] config: enable RT2800USB_RT3573 and RT2800USB_RT55XX - wifi drivers - ---- - 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 a6ef4ca..6c569a5 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -486,7 +486,9 @@ CONFIG_RT2X00=m - CONFIG_RT2500USB=m - CONFIG_RT73USB=m - CONFIG_RT2800USB=m -+CONFIG_RT2800USB_RT3573=y - CONFIG_RT2800USB_RT53XX=y -+CONFIG_RT2800USB_RT55XX=y - CONFIG_RT2800USB_UNKNOWN=y - CONFIG_RTL8192CU=m - CONFIG_ZD1211RW=m --- -1.8.5.5 - - -From da3a640ef64337fe6fedd857b9bb9c46313c8957 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Wed, 29 Jan 2014 21:37:00 +0000 -Subject: [PATCH 082/118] video: relax the dimensions check for rotated - displays - ---- - drivers/video/bcm2708_fb.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c -index 5758146..935288d 100644 ---- a/drivers/video/bcm2708_fb.c -+++ b/drivers/video/bcm2708_fb.c -@@ -255,8 +255,8 @@ static int bcm2708_fb_check_var(struct fb_var_screeninfo *var, - else if (var->vmode & FB_VMODE_INTERLACED) - yres = (yres + 1) / 2; - -- if (yres > 1200) { -- pr_err("bcm2708_fb_check_var: ERROR: VerticalTotal >= 1200; " -+ if (var->xres * yres > 1920 * 1200) { -+ pr_err("bcm2708_fb_check_var: ERROR: Pixel size >= 1920x1200; " - "special treatment required! (TODO)\n"); - return -EINVAL; - } -@@ -415,7 +415,7 @@ static void bcm2708_fb_copyarea(struct fb_info *info, - - /* Fallback to cfb_copyarea() if we don't like something */ - if (bytes_per_pixel > 4 || -- info->var.xres > 1920 || info->var.yres > 1200 || -+ 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 || --- -1.8.5.5 - - -From b47ea754bd270b76ae3d6480d1d2b3450a5f7b61 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 14:22:53 +0100 -Subject: [PATCH 083/118] 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 ---- - 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 c823daa..69e12b7 100644 ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -312,6 +312,12 @@ config TI_CPPI41 - The Communications Port Programming Interface (CPPI) 4.1 DMA engine - is currently used by the USB driver on AM335x platforms. - -+config DMA_BCM2708 -+ tristate "BCM2708 DMA engine support" -+ depends on MACH_BCM2708 -+ select DMA_ENGINE -+ select DMA_VIRTUAL_CHANNELS -+ - config MMP_PDMA - bool "MMP PDMA support" - depends on (ARCH_MMP || ARCH_PXA) -diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile -index 0ce2da9..7045649 100644 ---- a/drivers/dma/Makefile -+++ b/drivers/dma/Makefile -@@ -38,6 +38,7 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o - obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o - obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o - obj-$(CONFIG_DMA_OMAP) += omap-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..7d5ed19 ---- /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 -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "virt-dma.h" -+ -+#include -+#include -+ -+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_SUCCESS || !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 "); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From 6e47b8d4794411a06d4a9661d5eacd137833119c Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 14:33:38 +0100 -Subject: [PATCH 084/118] ASoC: Add support for BCM2708 - -This driver adds support for digital audio (I2S) -for the BCM2708 SoC that is used by the -Raspberry Pi. External audio codecs can be -connected to the Raspberry Pi via P5 header. - -It relies on cyclic DMA engine support for BCM2708. - -Signed-off-by: Florian Meier ---- - sound/soc/Kconfig | 1 + - sound/soc/Makefile | 1 + - sound/soc/bcm/Kconfig | 10 + - sound/soc/bcm/Makefile | 4 + - sound/soc/bcm/bcm2708-i2s.c | 940 ++++++++++++++++++++++++++++++++++++++++++++ - 5 files changed, 956 insertions(+) - create mode 100644 sound/soc/bcm/Kconfig - create mode 100644 sound/soc/bcm/Makefile - create mode 100644 sound/soc/bcm/bcm2708-i2s.c - -diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig -index 5138b84..a5e3a70 100644 ---- a/sound/soc/Kconfig -+++ b/sound/soc/Kconfig -@@ -33,6 +33,7 @@ config SND_SOC_GENERIC_DMAENGINE_PCM - # All the supported SoCs - source "sound/soc/atmel/Kconfig" - source "sound/soc/au1x/Kconfig" -+source "sound/soc/bcm/Kconfig" - source "sound/soc/blackfin/Kconfig" - source "sound/soc/cirrus/Kconfig" - source "sound/soc/davinci/Kconfig" -diff --git a/sound/soc/Makefile b/sound/soc/Makefile -index 8b9e701..b52d4aa 100644 ---- a/sound/soc/Makefile -+++ b/sound/soc/Makefile -@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC) += codecs/ - obj-$(CONFIG_SND_SOC) += generic/ - obj-$(CONFIG_SND_SOC) += atmel/ - obj-$(CONFIG_SND_SOC) += au1x/ -+obj-$(CONFIG_SND_SOC) += bcm/ - obj-$(CONFIG_SND_SOC) += blackfin/ - obj-$(CONFIG_SND_SOC) += cirrus/ - obj-$(CONFIG_SND_SOC) += davinci/ -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -new file mode 100644 -index 0000000..37c8f8c ---- /dev/null -+++ b/sound/soc/bcm/Kconfig -@@ -0,0 +1,10 @@ -+config SND_BCM2708_SOC_I2S -+ tristate "SoC Audio support for the Broadcom BCM2708 I2S module" -+ depends on MACH_BCM2708 -+ select REGMAP_MMIO -+ select SND_SOC_DMAENGINE_PCM -+ select SND_SOC_GENERIC_DMAENGINE_PCM -+ help -+ 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. -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -new file mode 100644 -index 0000000..486ea09 ---- /dev/null -+++ b/sound/soc/bcm/Makefile -@@ -0,0 +1,4 @@ -+# BCM2708 Platform Support -+snd-soc-bcm2708-i2s-objs := bcm2708-i2s.o -+ -+obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o -diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c -new file mode 100644 -index 0000000..ebaf3d6 ---- /dev/null -+++ b/sound/soc/bcm/bcm2708-i2s.c -@@ -0,0 +1,940 @@ -+/* -+ * ALSA SoC I2S Audio Layer for Broadcom BCM2708 SoC -+ * -+ * Author: Florian Meier -+ * Copyright 2013 -+ * -+ * Based on -+ * Raspberry Pi PCM I2S ALSA Driver -+ * Copyright (c) by Phil Poole 2013 -+ * -+ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor -+ * Vladimir Barinov, -+ * Copyright (C) 2007 MontaVista Software, Inc., -+ * -+ * OMAP ALSA SoC DAI driver using McBSP port -+ * Copyright (C) 2008 Nokia Corporation -+ * Contact: Jarkko Nikula -+ * Peter Ujfalusi -+ * -+ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver -+ * Author: Timur Tabi -+ * Copyright 2007-2010 Freescale Semiconductor, Inc. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Clock registers */ -+#define BCM2708_CLK_PCMCTL_REG 0x00 -+#define BCM2708_CLK_PCMDIV_REG 0x04 -+ -+/* Clock register settings */ -+#define BCM2708_CLK_PASSWD (0x5a000000) -+#define BCM2708_CLK_PASSWD_MASK (0xff000000) -+#define BCM2708_CLK_MASH(v) ((v) << 9) -+#define BCM2708_CLK_FLIP BIT(8) -+#define BCM2708_CLK_BUSY BIT(7) -+#define BCM2708_CLK_KILL BIT(5) -+#define BCM2708_CLK_ENAB BIT(4) -+#define BCM2708_CLK_SRC(v) (v) -+ -+#define BCM2708_CLK_SHIFT (12) -+#define BCM2708_CLK_DIVI(v) ((v) << BCM2708_CLK_SHIFT) -+#define BCM2708_CLK_DIVF(v) (v) -+#define BCM2708_CLK_DIVF_MASK (0xFFF) -+ -+enum { -+ BCM2708_CLK_MASH_0 = 0, -+ BCM2708_CLK_MASH_1, -+ BCM2708_CLK_MASH_2, -+ BCM2708_CLK_MASH_3, -+}; -+ -+enum { -+ BCM2708_CLK_SRC_GND = 0, -+ BCM2708_CLK_SRC_OSC, -+ BCM2708_CLK_SRC_DBG0, -+ BCM2708_CLK_SRC_DBG1, -+ BCM2708_CLK_SRC_PLLA, -+ BCM2708_CLK_SRC_PLLC, -+ BCM2708_CLK_SRC_PLLD, -+ BCM2708_CLK_SRC_HDMI, -+}; -+ -+/* Most clocks are not useable (freq = 0) */ -+static const unsigned int bcm2708_clk_freq[BCM2708_CLK_SRC_HDMI+1] = { -+ [BCM2708_CLK_SRC_GND] = 0, -+ [BCM2708_CLK_SRC_OSC] = 19200000, -+ [BCM2708_CLK_SRC_DBG0] = 0, -+ [BCM2708_CLK_SRC_DBG1] = 0, -+ [BCM2708_CLK_SRC_PLLA] = 0, -+ [BCM2708_CLK_SRC_PLLC] = 0, -+ [BCM2708_CLK_SRC_PLLD] = 500000000, -+ [BCM2708_CLK_SRC_HDMI] = 0, -+}; -+ -+/* I2S registers */ -+#define BCM2708_I2S_CS_A_REG 0x00 -+#define BCM2708_I2S_FIFO_A_REG 0x04 -+#define BCM2708_I2S_MODE_A_REG 0x08 -+#define BCM2708_I2S_RXC_A_REG 0x0c -+#define BCM2708_I2S_TXC_A_REG 0x10 -+#define BCM2708_I2S_DREQ_A_REG 0x14 -+#define BCM2708_I2S_INTEN_A_REG 0x18 -+#define BCM2708_I2S_INTSTC_A_REG 0x1c -+#define BCM2708_I2S_GRAY_REG 0x20 -+ -+/* I2S register settings */ -+#define BCM2708_I2S_STBY BIT(25) -+#define BCM2708_I2S_SYNC BIT(24) -+#define BCM2708_I2S_RXSEX BIT(23) -+#define BCM2708_I2S_RXF BIT(22) -+#define BCM2708_I2S_TXE BIT(21) -+#define BCM2708_I2S_RXD BIT(20) -+#define BCM2708_I2S_TXD BIT(19) -+#define BCM2708_I2S_RXR BIT(18) -+#define BCM2708_I2S_TXW BIT(17) -+#define BCM2708_I2S_CS_RXERR BIT(16) -+#define BCM2708_I2S_CS_TXERR BIT(15) -+#define BCM2708_I2S_RXSYNC BIT(14) -+#define BCM2708_I2S_TXSYNC BIT(13) -+#define BCM2708_I2S_DMAEN BIT(9) -+#define BCM2708_I2S_RXTHR(v) ((v) << 7) -+#define BCM2708_I2S_TXTHR(v) ((v) << 5) -+#define BCM2708_I2S_RXCLR BIT(4) -+#define BCM2708_I2S_TXCLR BIT(3) -+#define BCM2708_I2S_TXON BIT(2) -+#define BCM2708_I2S_RXON BIT(1) -+#define BCM2708_I2S_EN (1) -+ -+#define BCM2708_I2S_CLKDIS BIT(28) -+#define BCM2708_I2S_PDMN BIT(27) -+#define BCM2708_I2S_PDME BIT(26) -+#define BCM2708_I2S_FRXP BIT(25) -+#define BCM2708_I2S_FTXP BIT(24) -+#define BCM2708_I2S_CLKM BIT(23) -+#define BCM2708_I2S_CLKI BIT(22) -+#define BCM2708_I2S_FSM BIT(21) -+#define BCM2708_I2S_FSI BIT(20) -+#define BCM2708_I2S_FLEN(v) ((v) << 10) -+#define BCM2708_I2S_FSLEN(v) (v) -+ -+#define BCM2708_I2S_CHWEX BIT(15) -+#define BCM2708_I2S_CHEN BIT(14) -+#define BCM2708_I2S_CHPOS(v) ((v) << 4) -+#define BCM2708_I2S_CHWID(v) (v) -+#define BCM2708_I2S_CH1(v) ((v) << 16) -+#define BCM2708_I2S_CH2(v) (v) -+ -+#define BCM2708_I2S_TX_PANIC(v) ((v) << 24) -+#define BCM2708_I2S_RX_PANIC(v) ((v) << 16) -+#define BCM2708_I2S_TX(v) ((v) << 8) -+#define BCM2708_I2S_RX(v) (v) -+ -+#define BCM2708_I2S_INT_RXERR BIT(3) -+#define BCM2708_I2S_INT_TXERR BIT(2) -+#define BCM2708_I2S_INT_RXR BIT(1) -+#define BCM2708_I2S_INT_TXW BIT(0) -+ -+/* I2S DMA interface */ -+#define BCM2708_I2S_FIFO_PHYSICAL_ADDR 0x7E203004 -+#define BCM2708_DMA_DREQ_PCM_TX 2 -+#define BCM2708_DMA_DREQ_PCM_RX 3 -+ -+/* General device struct */ -+struct bcm2708_i2s_dev { -+ struct device *dev; -+ struct snd_dmaengine_dai_dma_data dma_data[2]; -+ unsigned int fmt; -+ unsigned int bclk_ratio; -+ -+ struct regmap *i2s_regmap; -+ struct regmap *clk_regmap; -+}; -+ -+static void bcm2708_i2s_start_clock(struct bcm2708_i2s_dev *dev) -+{ -+ /* Start the clock if in master mode */ -+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; -+ -+ switch (master) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ case SND_SOC_DAIFMT_CBS_CFM: -+ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, -+ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, -+ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void bcm2708_i2s_stop_clock(struct bcm2708_i2s_dev *dev) -+{ -+ uint32_t clkreg; -+ int timeout = 1000; -+ -+ /* Stop clock */ -+ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, -+ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, -+ BCM2708_CLK_PASSWD); -+ -+ /* Wait for the BUSY flag going down */ -+ while (--timeout) { -+ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); -+ if (!(clkreg & BCM2708_CLK_BUSY)) -+ break; -+ } -+ -+ if (!timeout) { -+ /* KILL the clock */ -+ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); -+ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, -+ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD_MASK, -+ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD); -+ } -+} -+ -+static void bcm2708_i2s_clear_fifos(struct bcm2708_i2s_dev *dev, -+ bool tx, bool rx) -+{ -+ int timeout = 1000; -+ uint32_t syncval; -+ uint32_t csreg; -+ uint32_t i2s_active_state; -+ uint32_t clkreg; -+ uint32_t clk_active_state; -+ uint32_t off; -+ uint32_t clr; -+ -+ off = tx ? BCM2708_I2S_TXON : 0; -+ off |= rx ? BCM2708_I2S_RXON : 0; -+ -+ clr = tx ? BCM2708_I2S_TXCLR : 0; -+ clr |= rx ? BCM2708_I2S_RXCLR : 0; -+ -+ /* Backup the current state */ -+ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); -+ i2s_active_state = csreg & (BCM2708_I2S_RXON | BCM2708_I2S_TXON); -+ -+ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); -+ clk_active_state = clkreg & BCM2708_CLK_ENAB; -+ -+ /* Start clock if not running */ -+ if (!clk_active_state) { -+ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, -+ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, -+ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); -+ } -+ -+ /* Stop I2S module */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, off, 0); -+ -+ /* -+ * Clear the FIFOs -+ * Requires at least 2 PCM clock cycles to take effect -+ */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, clr, clr); -+ -+ /* Wait for 2 PCM clock cycles */ -+ -+ /* -+ * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back -+ * FIXME: This does not seem to work for slave mode! -+ */ -+ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &syncval); -+ syncval &= BCM2708_I2S_SYNC; -+ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_SYNC, ~syncval); -+ -+ /* Wait for the SYNC flag changing it's state */ -+ while (--timeout) { -+ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); -+ if ((csreg & BCM2708_I2S_SYNC) != syncval) -+ break; -+ } -+ -+ if (!timeout) -+ dev_err(dev->dev, "I2S SYNC error!\n"); -+ -+ /* Stop clock if it was not running before */ -+ if (!clk_active_state) -+ bcm2708_i2s_stop_clock(dev); -+ -+ /* Restore I2S state */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_RXON | BCM2708_I2S_TXON, i2s_active_state); -+} -+ -+static int bcm2708_i2s_set_dai_fmt(struct snd_soc_dai *dai, -+ unsigned int fmt) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ dev->fmt = fmt; -+ return 0; -+} -+ -+static int bcm2708_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, -+ unsigned int ratio) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ dev->bclk_ratio = ratio; -+ return 0; -+} -+ -+static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params, -+ struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ -+ unsigned int sampling_rate = params_rate(params); -+ unsigned int data_length, data_delay, bclk_ratio; -+ unsigned int ch1pos, ch2pos, mode, format; -+ unsigned int mash = BCM2708_CLK_MASH_1; -+ unsigned int divi, divf, target_frequency; -+ int clk_src = -1; -+ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; -+ bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS -+ || master == SND_SOC_DAIFMT_CBS_CFM); -+ -+ bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS -+ || master == SND_SOC_DAIFMT_CBM_CFS); -+ uint32_t csreg; -+ -+ /* -+ * If a stream is already enabled, -+ * the registers are already set properly. -+ */ -+ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); -+ -+ if (csreg & (BCM2708_I2S_TXON | BCM2708_I2S_RXON)) -+ return 0; -+ -+ /* -+ * Adjust the data length according to the format. -+ * We prefill the half frame length with an integer -+ * divider of 2400 as explained at the clock settings. -+ * Maybe it is overwritten there, if the Integer mode -+ * does not apply. -+ */ -+ switch (params_format(params)) { -+ case SNDRV_PCM_FORMAT_S16_LE: -+ data_length = 16; -+ bclk_ratio = 40; -+ break; -+ case SNDRV_PCM_FORMAT_S32_LE: -+ data_length = 32; -+ bclk_ratio = 80; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* If bclk_ratio already set, use that one. */ -+ if (dev->bclk_ratio) -+ bclk_ratio = dev->bclk_ratio; -+ -+ /* -+ * Clock Settings -+ * -+ * The target frequency of the bit clock is -+ * sampling rate * frame length -+ * -+ * Integer mode: -+ * Sampling rates that are multiples of 8000 kHz -+ * can be driven by the oscillator of 19.2 MHz -+ * with an integer divider as long as the frame length -+ * is an integer divider of 19200000/8000=2400 as set up above. -+ * This is no longer possible if the sampling rate -+ * is too high (e.g. 192 kHz), because the oscillator is too slow. -+ * -+ * MASH mode: -+ * For all other sampling rates, it is not possible to -+ * have an integer divider. Approximate the clock -+ * with the MASH module that induces a slight frequency -+ * variance. To minimize that it is best to have the fastest -+ * clock here. That is PLLD with 500 MHz. -+ */ -+ target_frequency = sampling_rate * bclk_ratio; -+ clk_src = BCM2708_CLK_SRC_OSC; -+ mash = BCM2708_CLK_MASH_0; -+ -+ if (bcm2708_clk_freq[clk_src] % target_frequency == 0 -+ && bit_master && frame_master) { -+ divi = bcm2708_clk_freq[clk_src] / target_frequency; -+ divf = 0; -+ } else { -+ uint64_t dividend; -+ -+ if (!dev->bclk_ratio) { -+ /* -+ * Overwrite bclk_ratio, because the -+ * above trick is not needed or can -+ * not be used. -+ */ -+ bclk_ratio = 2 * data_length; -+ } -+ -+ target_frequency = sampling_rate * bclk_ratio; -+ -+ clk_src = BCM2708_CLK_SRC_PLLD; -+ mash = BCM2708_CLK_MASH_1; -+ -+ dividend = bcm2708_clk_freq[clk_src]; -+ dividend <<= BCM2708_CLK_SHIFT; -+ do_div(dividend, target_frequency); -+ divi = dividend >> BCM2708_CLK_SHIFT; -+ divf = dividend & BCM2708_CLK_DIVF_MASK; -+ } -+ -+ /* Set clock divider */ -+ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMDIV_REG, BCM2708_CLK_PASSWD -+ | BCM2708_CLK_DIVI(divi) -+ | BCM2708_CLK_DIVF(divf)); -+ -+ /* Setup clock, but don't start it yet */ -+ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD -+ | BCM2708_CLK_MASH(mash) -+ | BCM2708_CLK_SRC(clk_src)); -+ -+ /* Setup the frame format */ -+ format = BCM2708_I2S_CHEN; -+ -+ if (data_length > 24) -+ format |= BCM2708_I2S_CHWEX; -+ -+ format |= BCM2708_I2S_CHWID((data_length-8)&0xf); -+ -+ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { -+ case SND_SOC_DAIFMT_I2S: -+ data_delay = 1; -+ break; -+ default: -+ /* -+ * TODO -+ * Others are possible but are not implemented at the moment. -+ */ -+ dev_err(dev->dev, "%s:bad format\n", __func__); -+ return -EINVAL; -+ } -+ -+ ch1pos = data_delay; -+ ch2pos = bclk_ratio / 2 + data_delay; -+ -+ switch (params_channels(params)) { -+ case 2: -+ format = BCM2708_I2S_CH1(format) | BCM2708_I2S_CH2(format); -+ format |= BCM2708_I2S_CH1(BCM2708_I2S_CHPOS(ch1pos)); -+ format |= BCM2708_I2S_CH2(BCM2708_I2S_CHPOS(ch2pos)); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ /* -+ * Set format for both streams. -+ * We cannot set another frame length -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ regmap_write(dev->i2s_regmap, BCM2708_I2S_RXC_A_REG, format); -+ regmap_write(dev->i2s_regmap, BCM2708_I2S_TXC_A_REG, format); -+ -+ /* Setup the I2S mode */ -+ mode = 0; -+ -+ if (data_length <= 16) { -+ /* -+ * Use frame packed mode (2 channels per 32 bit word) -+ * We cannot set another frame length in the second stream -+ * (and therefore word length) anyway, -+ * so the format will be the same. -+ */ -+ mode |= BCM2708_I2S_FTXP | BCM2708_I2S_FRXP; -+ } -+ -+ mode |= BCM2708_I2S_FLEN(bclk_ratio - 1); -+ mode |= BCM2708_I2S_FSLEN(bclk_ratio / 2); -+ -+ /* Master or slave? */ -+ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { -+ case SND_SOC_DAIFMT_CBS_CFS: -+ /* CPU is master */ -+ break; -+ case SND_SOC_DAIFMT_CBM_CFS: -+ /* -+ * CODEC is bit clock master -+ * CPU is frame master -+ */ -+ mode |= BCM2708_I2S_CLKM; -+ break; -+ case SND_SOC_DAIFMT_CBS_CFM: -+ /* -+ * CODEC is frame master -+ * CPU is bit clock master -+ */ -+ mode |= BCM2708_I2S_FSM; -+ break; -+ case SND_SOC_DAIFMT_CBM_CFM: -+ /* CODEC is master */ -+ mode |= BCM2708_I2S_CLKM; -+ mode |= BCM2708_I2S_FSM; -+ break; -+ default: -+ dev_err(dev->dev, "%s:bad master\n", __func__); -+ return -EINVAL; -+ } -+ -+ /* -+ * Invert clocks? -+ * -+ * The BCM approach seems to be inverted to the classical I2S approach. -+ */ -+ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { -+ case SND_SOC_DAIFMT_NB_NF: -+ /* None. Therefore, both for BCM */ -+ mode |= BCM2708_I2S_CLKI; -+ mode |= BCM2708_I2S_FSI; -+ break; -+ case SND_SOC_DAIFMT_IB_IF: -+ /* Both. Therefore, none for BCM */ -+ break; -+ case SND_SOC_DAIFMT_NB_IF: -+ /* -+ * Invert only frame sync. Therefore, -+ * invert only bit clock for BCM -+ */ -+ mode |= BCM2708_I2S_CLKI; -+ break; -+ case SND_SOC_DAIFMT_IB_NF: -+ /* -+ * Invert only bit clock. Therefore, -+ * invert only frame sync for BCM -+ */ -+ mode |= BCM2708_I2S_FSI; -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ regmap_write(dev->i2s_regmap, BCM2708_I2S_MODE_A_REG, mode); -+ -+ /* Setup the DMA parameters */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_RXTHR(1) -+ | BCM2708_I2S_TXTHR(1) -+ | BCM2708_I2S_DMAEN, 0xffffffff); -+ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_DREQ_A_REG, -+ BCM2708_I2S_TX_PANIC(0x10) -+ | BCM2708_I2S_RX_PANIC(0x30) -+ | BCM2708_I2S_TX(0x30) -+ | BCM2708_I2S_RX(0x20), 0xffffffff); -+ -+ /* Clear FIFOs */ -+ bcm2708_i2s_clear_fifos(dev, true, true); -+ -+ return 0; -+} -+ -+static int bcm2708_i2s_prepare(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ uint32_t cs_reg; -+ -+ bcm2708_i2s_start_clock(dev); -+ -+ /* -+ * Clear both FIFOs if the one that should be started -+ * is not empty at the moment. This should only happen -+ * after overrun. Otherwise, hw_params would have cleared -+ * the FIFO. -+ */ -+ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &cs_reg); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK -+ && !(cs_reg & BCM2708_I2S_TXE)) -+ bcm2708_i2s_clear_fifos(dev, true, false); -+ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE -+ && (cs_reg & BCM2708_I2S_RXD)) -+ bcm2708_i2s_clear_fifos(dev, false, true); -+ -+ return 0; -+} -+ -+static void bcm2708_i2s_stop(struct bcm2708_i2s_dev *dev, -+ struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ uint32_t mask; -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ mask = BCM2708_I2S_RXON; -+ else -+ mask = BCM2708_I2S_TXON; -+ -+ regmap_update_bits(dev->i2s_regmap, -+ BCM2708_I2S_CS_A_REG, mask, 0); -+ -+ /* Stop also the clock when not SND_SOC_DAIFMT_CONT */ -+ if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT)) -+ bcm2708_i2s_stop_clock(dev); -+} -+ -+static int bcm2708_i2s_trigger(struct snd_pcm_substream *substream, int cmd, -+ struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ uint32_t mask; -+ -+ switch (cmd) { -+ case SNDRV_PCM_TRIGGER_START: -+ case SNDRV_PCM_TRIGGER_RESUME: -+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: -+ bcm2708_i2s_start_clock(dev); -+ -+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) -+ mask = BCM2708_I2S_RXON; -+ else -+ mask = BCM2708_I2S_TXON; -+ -+ regmap_update_bits(dev->i2s_regmap, -+ BCM2708_I2S_CS_A_REG, mask, mask); -+ break; -+ -+ case SNDRV_PCM_TRIGGER_STOP: -+ case SNDRV_PCM_TRIGGER_SUSPEND: -+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: -+ bcm2708_i2s_stop(dev, substream, dai); -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+static int bcm2708_i2s_startup(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ -+ if (dai->active) -+ return 0; -+ -+ /* Should this still be running stop it */ -+ bcm2708_i2s_stop_clock(dev); -+ -+ /* Enable PCM block */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_EN, BCM2708_I2S_EN); -+ -+ /* -+ * Disable STBY. -+ * Requires at least 4 PCM clock cycles to take effect. -+ */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_STBY, BCM2708_I2S_STBY); -+ -+ return 0; -+} -+ -+static void bcm2708_i2s_shutdown(struct snd_pcm_substream *substream, -+ struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ -+ bcm2708_i2s_stop(dev, substream, dai); -+ -+ /* If both streams are stopped, disable module and clock */ -+ if (dai->active) -+ return; -+ -+ /* Disable the module */ -+ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, -+ BCM2708_I2S_EN, 0); -+ -+ /* -+ * Stopping clock is necessary, because stop does -+ * not stop the clock when SND_SOC_DAIFMT_CONT -+ */ -+ bcm2708_i2s_stop_clock(dev); -+} -+ -+static const struct snd_soc_dai_ops bcm2708_i2s_dai_ops = { -+ .startup = bcm2708_i2s_startup, -+ .shutdown = bcm2708_i2s_shutdown, -+ .prepare = bcm2708_i2s_prepare, -+ .trigger = bcm2708_i2s_trigger, -+ .hw_params = bcm2708_i2s_hw_params, -+ .set_fmt = bcm2708_i2s_set_dai_fmt, -+ .set_bclk_ratio = bcm2708_i2s_set_dai_bclk_ratio -+}; -+ -+static int bcm2708_i2s_dai_probe(struct snd_soc_dai *dai) -+{ -+ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); -+ -+ dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; -+ dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; -+ -+ return 0; -+} -+ -+static struct snd_soc_dai_driver bcm2708_i2s_dai = { -+ .name = "bcm2708-i2s", -+ .probe = bcm2708_i2s_dai_probe, -+ .playback = { -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE -+ | SNDRV_PCM_FMTBIT_S32_LE -+ }, -+ .capture = { -+ .channels_min = 2, -+ .channels_max = 2, -+ .rates = SNDRV_PCM_RATE_8000_192000, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE -+ | SNDRV_PCM_FMTBIT_S32_LE -+ }, -+ .ops = &bcm2708_i2s_dai_ops, -+ .symmetric_rates = 1 -+}; -+ -+static bool bcm2708_i2s_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case BCM2708_I2S_CS_A_REG: -+ case BCM2708_I2S_FIFO_A_REG: -+ case BCM2708_I2S_INTSTC_A_REG: -+ case BCM2708_I2S_GRAY_REG: -+ return true; -+ default: -+ return false; -+ }; -+} -+ -+static bool bcm2708_i2s_precious_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case BCM2708_I2S_FIFO_A_REG: -+ return true; -+ default: -+ return false; -+ }; -+} -+ -+static bool bcm2708_clk_volatile_reg(struct device *dev, unsigned int reg) -+{ -+ switch (reg) { -+ case BCM2708_CLK_PCMCTL_REG: -+ return true; -+ default: -+ return false; -+ }; -+} -+ -+static const struct regmap_config bcm2708_regmap_config[] = { -+ { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = BCM2708_I2S_GRAY_REG, -+ .precious_reg = bcm2708_i2s_precious_reg, -+ .volatile_reg = bcm2708_i2s_volatile_reg, -+ .cache_type = REGCACHE_RBTREE, -+ }, -+ { -+ .reg_bits = 32, -+ .reg_stride = 4, -+ .val_bits = 32, -+ .max_register = BCM2708_CLK_PCMDIV_REG, -+ .volatile_reg = bcm2708_clk_volatile_reg, -+ .cache_type = REGCACHE_RBTREE, -+ }, -+}; -+ -+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_MMAP | -+ SNDRV_PCM_INFO_MMAP_VALID | -+ SNDRV_PCM_INFO_INTERLEAVED | -+ SNDRV_PCM_INFO_JOINT_DUPLEX, -+ .formats = SNDRV_PCM_FMTBIT_S16_LE | -+ SNDRV_PCM_FMTBIT_S32_LE, -+ .period_bytes_min = 32, -+ .period_bytes_max = 64 * PAGE_SIZE, -+ .periods_min = 2, -+ .periods_max = 255, -+ .buffer_bytes_max = 128 * PAGE_SIZE, -+}; -+ -+static const struct snd_dmaengine_pcm_config bcm2708_dmaengine_pcm_config = { -+ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, -+ .pcm_hardware = &bcm2708_pcm_hardware, -+ .prealloc_buffer_size = 256 * PAGE_SIZE, -+}; -+ -+ -+static int bcm2708_i2s_probe(struct platform_device *pdev) -+{ -+ struct bcm2708_i2s_dev *dev; -+ int i; -+ int ret; -+ struct regmap *regmap[2]; -+ struct resource *mem[2]; -+ -+ /* Request both ioareas */ -+ for (i = 0; i <= 1; i++) { -+ void __iomem *base; -+ -+ mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); -+ base = devm_ioremap_resource(&pdev->dev, mem[i]); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ regmap[i] = devm_regmap_init_mmio(&pdev->dev, base, -+ &bcm2708_regmap_config[i]); -+ if (IS_ERR(regmap[i])) { -+ dev_err(&pdev->dev, "I2S probe: regmap init failed\n"); -+ return PTR_ERR(regmap[i]); -+ } -+ } -+ -+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), -+ GFP_KERNEL); -+ if (IS_ERR(dev)) -+ return PTR_ERR(dev); -+ -+ bcm2708_i2s_setup_gpio(); -+ -+ dev->i2s_regmap = regmap[0]; -+ dev->clk_regmap = regmap[1]; -+ -+ /* Set the DMA address */ -+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = -+ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; -+ -+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = -+ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; -+ -+ /* Set the DREQ */ -+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].slave_id = -+ BCM2708_DMA_DREQ_PCM_TX; -+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].slave_id = -+ BCM2708_DMA_DREQ_PCM_RX; -+ -+ /* Set the bus width */ -+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = -+ DMA_SLAVE_BUSWIDTH_4_BYTES; -+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width = -+ DMA_SLAVE_BUSWIDTH_4_BYTES; -+ -+ /* Set burst */ -+ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; -+ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; -+ -+ /* BCLK ratio - use default */ -+ dev->bclk_ratio = 0; -+ -+ /* Store the pdev */ -+ dev->dev = &pdev->dev; -+ dev_set_drvdata(&pdev->dev, dev); -+ -+ ret = snd_soc_register_component(&pdev->dev, -+ &bcm2708_i2s_component, &bcm2708_i2s_dai, 1); -+ -+ if (ret) { -+ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); -+ ret = -ENOMEM; -+ return ret; -+ } -+ -+ ret = snd_dmaengine_pcm_register(&pdev->dev, -+ &bcm2708_dmaengine_pcm_config, -+ SND_DMAENGINE_PCM_FLAG_COMPAT); -+ if (ret) { -+ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); -+ snd_soc_unregister_component(&pdev->dev); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int bcm2708_i2s_remove(struct platform_device *pdev) -+{ -+ snd_dmaengine_pcm_unregister(&pdev->dev); -+ snd_soc_unregister_component(&pdev->dev); -+ return 0; -+} -+ -+static struct platform_driver bcm2708_i2s_driver = { -+ .probe = bcm2708_i2s_probe, -+ .remove = bcm2708_i2s_remove, -+ .driver = { -+ .name = "bcm2708-i2s", -+ .owner = THIS_MODULE, -+ }, -+}; -+ -+module_platform_driver(bcm2708_i2s_driver); -+ -+MODULE_ALIAS("platform:bcm2708-i2s"); -+MODULE_DESCRIPTION("BCM2708 I2S interface"); -+MODULE_AUTHOR("Florian Meier "); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From d6ab5d254e8c05c73eaf96342504b179481ad813 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 14:37:51 +0100 -Subject: [PATCH 085/118] BCM2708: Extend mach header - -Extend the headers of the mach-bcm2708 -in order to support I2S and DMA engine. - -Signed-off-by: Florian Meier ---- - 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.8.5.5 - - -From 9a2b4ce45feb0b3a8e4a7b10bdfba2464528c560 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 14:59:51 +0100 -Subject: [PATCH 086/118] ASoC: Add support for PCM5102A codec - -Some definitions to support the PCM5102A codec -by Texas Instruments. - -Signed-off-by: Florian Meier ---- - 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 b33b45d..34d4d55 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 -@@ -311,6 +312,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 -+ * 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 -+#include -+#include -+ -+#include -+ -+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 "); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From c84d3211dd00ae7a40d7abe80649bb93fe75047a Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 19:04:54 +0100 -Subject: [PATCH 087/118] 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 ---- - 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 b4d94bf..d44d70e 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -617,6 +617,28 @@ struct platform_device bcm2708_powerman_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; -@@ -743,6 +765,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.8.5.5 - - -From 2d4ea7586cf8de235a68ae1626da183d6c04b3b8 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 19:19:08 +0100 -Subject: [PATCH 088/118] 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 ---- - 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 37c8f8c..8b14e37 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -8,3 +8,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 486ea09..6834b4d 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -2,3 +2,8 @@ - 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 -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From fe785657d150c83c52026963af404a2e533bf235 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 22 Nov 2013 19:21:34 +0100 -Subject: [PATCH 089/118] 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 ---- - 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 d44d70e..cfb1634 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -639,6 +639,20 @@ struct platform_device bcm2708_powerman_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; -@@ -769,6 +783,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.8.5.5 - - -From 441dac65e46c7db130a27f4865378b69138fd75a Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 6 Dec 2013 18:55:53 +0100 -Subject: [PATCH 090/118] 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 ---- - 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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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.8.5.5 - - -From 59dbe81c022438c4b339181b239c8e176f5a52e7 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Mon, 2 Dec 2013 20:28:22 +0100 -Subject: [PATCH 091/118] 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 ---- - 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 6c569a5..a66aecf 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -734,6 +734,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 -@@ -921,6 +928,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.8.5.5 - - -From 112473e6810e9387a3172c5414cf07be470ea760 Mon Sep 17 00:00:00 2001 -From: Florian Meier -Date: Fri, 6 Dec 2013 20:50:28 +0100 -Subject: [PATCH 092/118] ASoC: BCM2708: Add support for RPi-DAC - -This adds a machine driver for the RPi-DAC. - -Signed-off-by: Florian Meier ---- - 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 a66aecf..6a2c0f4 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -739,8 +739,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 cfb1634..0847c54 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -653,6 +653,20 @@ struct platform_device bcm2708_powerman_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; -@@ -788,6 +802,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 8b14e37..1c1f5cf 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -15,3 +15,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. -\ No newline at end of file -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 6834b4d..95a9d44 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -5,5 +5,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 -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+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 "); -+MODULE_DESCRIPTION("ASoC Driver for RPi-DAC"); -+MODULE_LICENSE("GPL v2"); -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 34d4d55..4a1dd7e 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 -@@ -312,6 +313,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 -+ * 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 -+#include -+#include -+ -+#include -+ -+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 "); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From da3fd7111995b39843e9233b8aad0c40250d6617 Mon Sep 17 00:00:00 2001 -From: Peter Budd -Date: Thu, 2 Jan 2014 23:34:21 +0000 -Subject: [PATCH 093/118] Added support for Proto i2s DAC - ---- - arch/arm/mach-bcm2708/bcm2708.c | 19 ++++++ - sound/soc/bcm/rpi-proto.c | 130 ++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 149 insertions(+) - create mode 100644 sound/soc/bcm/rpi-proto.c - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 0847c54..ee6364b 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -667,6 +667,19 @@ struct platform_device bcm2708_powerman_device = { - }; - #endif - -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_PROTO_MODULE -+static struct platform_device snd_rpi_proto_device = { -+ .name = "snd-rpi-proto", -+ .id = 0, -+ .num_resources = 0, -+}; -+static struct i2c_board_info __initdata snd_rpi_proto_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("wm8731", 0x1a) -+ }, -+}; -+#endif -+ - int __init bcm_register_device(struct platform_device *pdev) - { - int ret; -@@ -807,6 +820,12 @@ void __init bcm2708_init(void) - bcm_register_device(&snd_pcm1794a_codec_device); - #endif - -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_PROTO_MODULE -+ bcm_register_device(&snd_rpi_proto_device); -+ i2c_register_board_info(1, snd_rpi_proto_i2c_devices, -+ ARRAY_SIZE(snd_rpi_proto_i2c_devices)); -+#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/rpi-proto.c b/sound/soc/bcm/rpi-proto.c -new file mode 100644 -index 0000000..4dc8705 ---- /dev/null -+++ b/sound/soc/bcm/rpi-proto.c -@@ -0,0 +1,130 @@ -+/* -+ * ASoC driver for PROTO AudioCODEC (with a WM8731) -+ * connected to a Raspberry Pi -+ * -+ * Author: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "../codecs/wm8731.h" -+ -+static const unsigned int wm8731_rates_12288000[] = { -+ 8000, 32000, 48000, 96000, -+}; -+ -+static struct snd_pcm_hw_constraint_list wm8731_constraints_12288000 = { -+ .list = wm8731_rates_12288000, -+ .count = ARRAY_SIZE(wm8731_rates_12288000), -+}; -+ -+static int snd_rpi_proto_startup(struct snd_pcm_substream *substream) -+{ -+ /* Setup constraints, because there is a 12.288 MHz XTAL on the board */ -+ snd_pcm_hw_constraint_list(substream->runtime, 0, -+ SNDRV_PCM_HW_PARAM_RATE, -+ &wm8731_constraints_12288000); -+ return 0; -+} -+ -+static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ struct snd_soc_pcm_runtime *rtd = substream->private_data; -+ struct snd_soc_dai *codec_dai = rtd->codec_dai; -+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ -+ /* Set proto bclk */ -+ int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2); -+ if (ret < 0){ -+ dev_err(substream->pcm->dev, -+ "Failed to set BCLK ratio %d\n", ret); -+ return ret; -+ } -+ int sysclk = 12288000; /* This is fixed on this board */ -+ -+ /* Set proto sysclk */ -+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, -+ sysclk, SND_SOC_CLOCK_IN); -+ if (ret < 0) { -+ dev_err(substream->pcm->dev, -+ "Failed to set WM8731 SYSCLK: %d\n", ret); -+ return ret; -+ } -+ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_proto_ops = { -+ .startup = snd_rpi_proto_startup, -+ .hw_params = snd_rpi_proto_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_proto_dai[] = { -+{ -+ .name = "WM8731", -+ .stream_name = "WM8731 HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "wm8731-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "wm8731.1-001a", -+ .dai_fmt = SND_SOC_DAIFMT_I2S -+ | SND_SOC_DAIFMT_NB_NF -+ | SND_SOC_DAIFMT_CBM_CFM, -+ .ops = &snd_rpi_proto_ops, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_proto = { -+ .name = "snd_rpi_proto", -+ .dai_link = snd_rpi_proto_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_proto_dai), -+}; -+ -+static int snd_rpi_proto_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_proto.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_proto); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_proto_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_proto); -+} -+ -+static struct platform_driver snd_rpi_proto_driver = { -+ .driver = { -+ .name = "snd-rpi-proto", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_proto_probe, -+ .remove = snd_rpi_proto_remove, -+}; -+ -+module_platform_driver(snd_rpi_proto_driver); -+ -+MODULE_AUTHOR("Florian Meier"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to PROTO board (WM8731)"); -+MODULE_LICENSE("GPL"); --- -1.8.5.5 - - -From 736f0e62e9eb02d02f17fe2b9ca8932e830a76a9 Mon Sep 17 00:00:00 2001 -From: Peter Budd -Date: Fri, 3 Jan 2014 05:50:49 +0000 -Subject: [PATCH 094/118] Add support for additional ASoC i2s drivers - ---- - sound/soc/bcm/rpi-cs534x.c | 105 +++++++++++++++++++++++++++++++++++++++++++ - sound/soc/bcm/rpi-ess9018.c | 92 +++++++++++++++++++++++++++++++++++++ - sound/soc/bcm/rpi-mbed.c | 103 ++++++++++++++++++++++++++++++++++++++++++ - sound/soc/bcm/rpi-pcm5102a.c | 93 ++++++++++++++++++++++++++++++++++++++ - sound/soc/bcm/rpi-proto.c | 3 +- - sound/soc/bcm/rpi-tda1541a.c | 92 +++++++++++++++++++++++++++++++++++++ - 6 files changed, 487 insertions(+), 1 deletion(-) - create mode 100644 sound/soc/bcm/rpi-cs534x.c - create mode 100644 sound/soc/bcm/rpi-ess9018.c - create mode 100644 sound/soc/bcm/rpi-mbed.c - create mode 100644 sound/soc/bcm/rpi-pcm5102a.c - create mode 100644 sound/soc/bcm/rpi-tda1541a.c - -diff --git a/sound/soc/bcm/rpi-cs534x.c b/sound/soc/bcm/rpi-cs534x.c -new file mode 100644 -index 0000000..d2a2ad2 ---- /dev/null -+++ b/sound/soc/bcm/rpi-cs534x.c -@@ -0,0 +1,105 @@ -+/* -+ * ASoC driver for CS5343/CS5344 ADC -+ * connected to a Raspberry Pi -+ * -+ * Author: Wojciech M. Zabolotny -+ * Based on rpi-ess9018.c by: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_cs534x_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ return 0; -+} -+ -+static int snd_rpi_cs534x_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_cs534x_ops = { -+ .hw_params = snd_rpi_cs534x_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_cs534x_dai[] = { -+{ -+ .name = "cs5343", -+ .stream_name = "cs5343 HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "cs534x-hifi", -+ .platform_name = "bcm2708-pcm-audio.0", -+ .codec_name = "cs534x-codec", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBM_CFM, -+ .ops = &snd_rpi_cs534x_ops, -+ .init = snd_rpi_cs534x_init, -+}, -+{ -+ .name = "cs5344", -+ .stream_name = "cs5344 HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "cs534x-hifi", -+ .platform_name = "bcm2708-pcm-audio.0", -+ .codec_name = "cs534x-codec", -+ .dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBM_CFM, -+ .ops = &snd_rpi_cs534x_ops, -+ .init = snd_rpi_cs534x_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_cs534x = { -+ .name = "snd_rpi_cs534x", -+ .dai_link = snd_rpi_cs534x_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_cs534x_dai), -+}; -+ -+static int snd_rpi_cs534x_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_cs534x.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_cs534x); -+ if (ret) -+ { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_cs534x_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_cs534x); -+} -+ -+static struct platform_driver snd_rpi_cs534x_driver = { -+ .driver = { -+ .name = "snd-rpi-cs534x", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_cs534x_probe, -+ .remove = snd_rpi_cs534x_remove, -+}; -+ -+module_platform_driver(snd_rpi_cs534x_driver); -+ -+MODULE_AUTHOR("Wojciech M. Zabolotny"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to a cs534x"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/bcm/rpi-ess9018.c b/sound/soc/bcm/rpi-ess9018.c -new file mode 100644 -index 0000000..1d709f5 ---- /dev/null -+++ b/sound/soc/bcm/rpi-ess9018.c -@@ -0,0 +1,92 @@ -+/* -+ * ASoC driver for ESS9018 codec -+ * connected to a Raspberry Pi -+ * -+ * Author: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_ess9018_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ return 0; -+} -+ -+static int snd_rpi_ess9018_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_ess9018_ops = { -+ .hw_params = snd_rpi_ess9018_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_ess9018_dai[] = { -+{ -+ .name = "ESS9018", -+ .stream_name = "ESS9018 HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "ess9018-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "ess9018-codec", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_ess9018_ops, -+ .init = snd_rpi_ess9018_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_ess9018 = { -+ .name = "snd_rpi_ess9018", -+ .dai_link = snd_rpi_ess9018_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_ess9018_dai), -+}; -+ -+static int snd_rpi_ess9018_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_ess9018.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_ess9018); -+ if (ret) -+ { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_ess9018_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_ess9018); -+} -+ -+static struct platform_driver snd_rpi_ess9018_driver = { -+ .driver = { -+ .name = "snd-rpi-ess9018", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_ess9018_probe, -+ .remove = snd_rpi_ess9018_remove, -+}; -+ -+module_platform_driver(snd_rpi_ess9018_driver); -+ -+MODULE_AUTHOR("Florian Meier"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to a ESS9018"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/bcm/rpi-mbed.c b/sound/soc/bcm/rpi-mbed.c -new file mode 100644 -index 0000000..a14f50c ---- /dev/null -+++ b/sound/soc/bcm/rpi-mbed.c -@@ -0,0 +1,103 @@ -+/* -+ * ASoC driver for mbed AudioCODEC (with a TLV320AIC23b) -+ * connected to a Raspberry Pi -+ * -+ * Author: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include "../codecs/tlv320aic23.h" -+ -+static int snd_rpi_mbed_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ return 0; -+} -+ -+static int snd_rpi_mbed_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; -+ int sysclk; -+ -+ sysclk = 12000000; /* this is fixed on this board */ -+ -+ /* set tlv320aic23 sysclk */ -+ snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, 0); -+ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_mbed_ops = { -+ .hw_params = snd_rpi_mbed_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_mbed_dai[] = { -+{ -+ .name = "TLV320AIC23", -+ .stream_name = "TLV320AIC23 HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "tlv320aic23-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "tlv320aic23-codec.1-001b", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_mbed_ops, -+ .init = snd_rpi_mbed_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_mbed = { -+ .name = "snd_rpi_mbed", -+ .dai_link = snd_rpi_mbed_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_mbed_dai), -+}; -+ -+static int snd_rpi_mbed_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_mbed.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_mbed); -+ if (ret) { -+ dev_err(&pdev->dev, -+ "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_mbed_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_mbed); -+} -+ -+static struct platform_driver snd_rpi_mbed_driver = { -+ .driver = { -+ .name = "snd-rpi-mbed", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_mbed_probe, -+ .remove = snd_rpi_mbed_remove, -+}; -+ -+module_platform_driver(snd_rpi_mbed_driver); -+ -+MODULE_AUTHOR("Florian Meier"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to mbed AudioCODEC"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/bcm/rpi-pcm5102a.c b/sound/soc/bcm/rpi-pcm5102a.c -new file mode 100644 -index 0000000..1006364 ---- /dev/null -+++ b/sound/soc/bcm/rpi-pcm5102a.c -@@ -0,0 +1,93 @@ -+/* -+ * ASoC driver for PCM5102A codec -+ * connected to a Raspberry Pi -+ * -+ * Author: Francesco Valla, -+ * Based on rpi-ess9018.c by: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_pcm5102a_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ return 0; -+} -+ -+static int snd_rpi_pcm5102a_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_pcm5102a_ops = { -+ .hw_params = snd_rpi_pcm5102a_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_pcm5102a_dai[] = { -+{ -+ .name = "PCM5102A", -+ .stream_name = "PCM5102A HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "pcm5102a-hifi", -+ .platform_name = "bcm2708-pcm-audio.0", -+ .codec_name = "pcm5102a-codec", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_pcm5102a_ops, -+ .init = snd_rpi_pcm5102a_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_pcm5102a = { -+ .name = "snd_rpi_pcm5102a", -+ .dai_link = snd_rpi_pcm5102a_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_pcm5102a_dai), -+}; -+ -+static int snd_rpi_pcm5102a_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_pcm5102a.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_pcm5102a); -+ if (ret) -+ { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_pcm5102a_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_pcm5102a); -+} -+ -+static struct platform_driver snd_rpi_pcm5102a_driver = { -+ .driver = { -+ .name = "snd-rpi-pcm5102a", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_pcm5102a_probe, -+ .remove = snd_rpi_pcm5102a_remove, -+}; -+ -+module_platform_driver(snd_rpi_pcm5102a_driver); -+ -+MODULE_AUTHOR("Francesco Valla"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to a PCM5102A"); -+MODULE_LICENSE("GPL"); -diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c -index 4dc8705..5752af2 100644 ---- a/sound/soc/bcm/rpi-proto.c -+++ b/sound/soc/bcm/rpi-proto.c -@@ -49,9 +49,10 @@ static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream, - int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2); - if (ret < 0){ - dev_err(substream->pcm->dev, -- "Failed to set BCLK ratio %d\n", ret); -+ "Failed to set WM8731 BCLK ratio %d\n", ret); - return ret; - } -+ - int sysclk = 12288000; /* This is fixed on this board */ - - /* Set proto sysclk */ -diff --git a/sound/soc/bcm/rpi-tda1541a.c b/sound/soc/bcm/rpi-tda1541a.c -new file mode 100644 -index 0000000..6115033 ---- /dev/null -+++ b/sound/soc/bcm/rpi-tda1541a.c -@@ -0,0 +1,92 @@ -+/* -+ * ASoC driver for TDA1541A codec -+ * connected to a Raspberry Pi -+ * -+ * Author: Florian Meier, -+ * Copyright 2013 -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+static int snd_rpi_tda1541a_init(struct snd_soc_pcm_runtime *rtd) -+{ -+ return 0; -+} -+ -+static int snd_rpi_tda1541a_hw_params(struct snd_pcm_substream *substream, -+ struct snd_pcm_hw_params *params) -+{ -+ return 0; -+} -+ -+/* machine stream operations */ -+static struct snd_soc_ops snd_rpi_tda1541a_ops = { -+ .hw_params = snd_rpi_tda1541a_hw_params, -+}; -+ -+static struct snd_soc_dai_link snd_rpi_tda1541a_dai[] = { -+{ -+ .name = "TDA1541A", -+ .stream_name = "TDA1541A HiFi", -+ .cpu_dai_name = "bcm2708-i2s.0", -+ .codec_dai_name = "tda1541a-hifi", -+ .platform_name = "bcm2708-i2s.0", -+ .codec_name = "tda1541a-codec", -+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | -+ SND_SOC_DAIFMT_CBS_CFS, -+ .ops = &snd_rpi_tda1541a_ops, -+ .init = snd_rpi_tda1541a_init, -+}, -+}; -+ -+/* audio machine driver */ -+static struct snd_soc_card snd_rpi_tda1541a = { -+ .name = "snd_rpi_tda1541a", -+ .dai_link = snd_rpi_tda1541a_dai, -+ .num_links = ARRAY_SIZE(snd_rpi_tda1541a_dai), -+}; -+ -+static int snd_rpi_tda1541a_probe(struct platform_device *pdev) -+{ -+ int ret = 0; -+ -+ snd_rpi_tda1541a.dev = &pdev->dev; -+ ret = snd_soc_register_card(&snd_rpi_tda1541a); -+ if (ret) -+ { -+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret); -+ } -+ -+ return ret; -+} -+ -+ -+static int snd_rpi_tda1541a_remove(struct platform_device *pdev) -+{ -+ return snd_soc_unregister_card(&snd_rpi_tda1541a); -+} -+ -+static struct platform_driver snd_rpi_tda1541a_driver = { -+ .driver = { -+ .name = "snd-rpi-tda1541a", -+ .owner = THIS_MODULE, -+ }, -+ .probe = snd_rpi_tda1541a_probe, -+ .remove = snd_rpi_tda1541a_remove, -+}; -+ -+module_platform_driver(snd_rpi_tda1541a_driver); -+ -+MODULE_AUTHOR("Florian Meier"); -+MODULE_DESCRIPTION("ASoC Driver for Raspberry Pi connected to a TDA1541A"); -+MODULE_LICENSE("GPL"); --- -1.8.5.5 - - -From 46c857e8d5a7c6516178f4600355173788cd5726 Mon Sep 17 00:00:00 2001 -From: Peter Budd -Date: Fri, 3 Jan 2014 05:51:53 +0000 -Subject: [PATCH 095/118] Add support for additional ASoC i2s drivers - ---- - arch/arm/mach-bcm2708/bcm2708.c | 135 ++++++++++++++++++++++++++++++++++------ - sound/soc/bcm/Kconfig | 55 +++++++++++++++- - sound/soc/bcm/Makefile | 10 +++ - 3 files changed, 181 insertions(+), 19 deletions(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index ee6364b..dfc2a8c 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -641,29 +641,59 @@ struct platform_device bcm2708_powerman_device = { - - #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, -+ .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, -+ .name = "pcm5102a-codec", -+ .id = -1, -+ .num_resources = 0, - }; - #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, -+ .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, -+ .name = "pcm1794a-codec", -+ .id = -1, -+ .num_resources = 0, -+}; -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_MBED_MODULE -+static struct platform_device snd_rpi_mbed_device = { -+ .name = "snd-rpi-mbed", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+ -+static struct i2c_board_info __initdata snd_rpi_mbed_i2c_devices[] = { -+ { -+ I2C_BOARD_INFO("tlv320aic23", 0x1b) -+ }, -+}; -+#endif -+ -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_TDA1541A_MODULE -+static struct platform_device snd_rpi_tda1541a_device = { -+ .name = "snd-rpi-tda1541a", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+static struct platform_device snd_rpi_tda1541a_codec_device = { -+ .name = "tda1541a-codec", -+ .id = -1, -+ .num_resources = 0, - }; - #endif - -@@ -673,6 +703,7 @@ struct platform_device bcm2708_powerman_device = { - .id = 0, - .num_resources = 0, - }; -+ - static struct i2c_board_info __initdata snd_rpi_proto_i2c_devices[] = { - { - I2C_BOARD_INFO("wm8731", 0x1a) -@@ -680,6 +711,49 @@ struct platform_device bcm2708_powerman_device = { - }; - #endif - -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_CS534X_MODULE -+static struct platform_device snd_rpi_cs534x_device = { -+ .name = "snd-rpi-cs534x", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+static struct platform_device snd_rpi_cs534x_codec_device = { -+ .name = "cs534x-codec", -+ .id = -1, -+ .num_resources = 0, -+}; -+ -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_ESS9018_MODULE -+static struct platform_device snd_rpi_ess9018_device = { -+ .name = "snd-rpi-ess9018", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+static struct platform_device snd_rpi_ess9018_codec_device = { -+ .name = "ess9018-codec", -+ .id = -1, -+ .num_resources = 0, -+}; -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_PCM5102A_MODULE -+static struct platform_device snd_rpi_pcm5102a_device = { -+ .name = "snd-rpi-pcm5102a", -+ .id = 0, -+ .num_resources = 0, -+}; -+ -+static struct platform_device snd_rpi_pcm5102a_codec_device = { -+ .name = "pcm5102a-codec", -+ .id = -1, -+ .num_resources = 0, -+}; -+#endif -+ - int __init bcm_register_device(struct platform_device *pdev) - { - int ret; -@@ -811,19 +885,44 @@ void __init bcm2708_init(void) - #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); -+ bcm_register_device(&snd_hifiberry_dac_device); -+ 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); -+ bcm_register_device(&snd_rpi_dac_device); -+ bcm_register_device(&snd_pcm1794a_codec_device); -+#endif -+ -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_MBED_MODULE -+ bcm_register_device(&snd_rpi_mbed_device); -+ i2c_register_board_info(1, snd_rpi_mbed_i2c_devices, ARRAY_SIZE(snd_rpi_mbed_i2c_devices)); -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_CS534X_MODULE -+ bcm_register_device(&snd_rpi_cs534x_device); -+ bcm_register_device(&snd_rpi_cs534x_codec_device); -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_TDA1541A_MODULE -+ bcm_register_device(&snd_rpi_tda1541a_device); -+ bcm_register_device(&snd_rpi_tda1541a_codec_device); - #endif - - #ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_PROTO_MODULE - bcm_register_device(&snd_rpi_proto_device); -- i2c_register_board_info(1, snd_rpi_proto_i2c_devices, -- ARRAY_SIZE(snd_rpi_proto_i2c_devices)); -+ i2c_register_board_info(1, snd_rpi_proto_i2c_devices, ARRAY_SIZE(snd_rpi_proto_i2c_devices)); -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_ESS9018_MODULE -+ bcm_register_device(&snd_rpi_ess9018_device); -+ bcm_register_device(&snd_rpi_ess9018_codec_device); -+#endif -+ -+#ifdef CONFIG_SND_BCM2708_SOC_RPI_CODEC_PCM5102A_MODULE -+ bcm_register_device(&snd_rpi_pcm5102a_device); -+ bcm_register_device(&snd_rpi_pcm5102a_codec_device); - #endif - - for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { -diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig -index 1c1f5cf..60fe399 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -21,4 +21,57 @@ config SND_BCM2708_SOC_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. -\ No newline at end of file -+ Say Y or M if you want to add support for RPi-DAC. -+ -+config SND_BCM2708_SOC_I2S -+ tristate "SoC Audio support for the Broadcom BCM2708 I2S module" -+ depends on MACH_BCM2708 -+ select REGMAP_MMIO -+ select SND_SOC_DMAENGINE_PCM -+ select SND_SOC_GENERIC_DMAENGINE_PCM -+ help -+ 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_MINI -+ tristate "Support for HifiBerry Mini" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_PCM5102A -+ help -+ Say Y or M if you want to add support for HifiBerry Mini. -+ -+config SND_BCM2708_SOC_RPI_CODEC_MBED -+ tristate "Support for AudioCODEC for mbed (TLV320AIC32B)" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_TLV320AIC3X -+ help -+ Say Y if you want to add support for AudioCODEC for mbed (TLV320AIC32B) -+ -+config SND_BCM2708_SOC_RPI_CODEC_TDA1541A -+ tristate "Support for TDA1541A" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_TDA1541A -+ help -+ Say Y if you want to add support for TDA1541A -+ -+config SND_BCM2708_SOC_RPI_CODEC_PROTO -+ tristate "Support for Audio Codec Board - PROTO (WM8731)" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_WM8731 -+ help -+ Say Y if you want to add support for Audio Codec Board - PROTO (WM8731) -+ -+config SND_BCM2708_SOC_RPI_CODEC_ESS9018 -+ tristate "Support for ESS9018" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_ESS9018 -+ help -+ Say Y if you want to add support for ESS9018 -+ -+config SND_BCM2708_SOC_RPI_CODEC_PCM5102A -+ tristate "Support for PCM5102A" -+ depends on SND_BCM2708_SOC_I2S -+ select SND_SOC_PCM5102A -+ help -+ Say Y if you want to add support for PCM5102A -diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile -index 95a9d44..eb869fa 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -6,6 +6,16 @@ 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 -+snd-soc-rpi-mbed-objs := rpi-mbed.o -+snd-soc-rpi-tda1541a-objs := rpi-tda1541a.o -+snd-soc-rpi-proto-objs := rpi-proto.o -+snd-soc-rpi-ess9018-objs := rpi-ess9018.o -+snd-soc-rpi-pcm5102a-objs := rpi-pcm5102a.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 -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_MBED) += snd-soc-rpi-mbed.o -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_TDA1541A) += snd-soc-rpi-tda1541a.o -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_PROTO) += snd-soc-rpi-proto.o -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_ESS9018) += snd-soc-rpi-ess9018.o -+obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_PCM5102A) += snd-soc-rpi-pcm5102a.o --- -1.8.5.5 - - -From 7c4bef81864b806bc2193e0fd1e29b53551bb2ed Mon Sep 17 00:00:00 2001 -From: Peter Budd -Date: Sat, 4 Jan 2014 18:27:33 +0000 -Subject: [PATCH 096/118] Remove compile warning - ---- - sound/soc/bcm/rpi-proto.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/sound/soc/bcm/rpi-proto.c b/sound/soc/bcm/rpi-proto.c -index 5752af2..c1532d4 100644 ---- a/sound/soc/bcm/rpi-proto.c -+++ b/sound/soc/bcm/rpi-proto.c -@@ -44,6 +44,7 @@ static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream, - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -+ int sysclk = 12288000; /* This is fixed on this board */ - - /* Set proto bclk */ - int ret = snd_soc_dai_set_bclk_ratio(cpu_dai,32*2); -@@ -53,8 +54,6 @@ static int snd_rpi_proto_hw_params(struct snd_pcm_substream *substream, - return ret; - } - -- int sysclk = 12288000; /* This is fixed on this board */ -- - /* Set proto sysclk */ - ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, - sysclk, SND_SOC_CLOCK_IN); --- -1.8.5.5 - - -From 09398420cb6fa78174e81768b81d2a7b9ccdad9c Mon Sep 17 00:00:00 2001 -From: Daniel Matuschek -Date: Wed, 15 Jan 2014 21:41:23 +0100 -Subject: [PATCH 097/118] 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 ---- - 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 1704b1e..7ec8381 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 @@ struct pll_div { - - #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 int wm8804_probe(struct snd_soc_codec *codec) - }; - - #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.8.5.5 - - -From 867102cd84ebf239271c84f63ec906d19ed226f7 Mon Sep 17 00:00:00 2001 -From: Daniel Matuschek -Date: Wed, 15 Jan 2014 21:42:08 +0100 -Subject: [PATCH 098/118] ASoC: BCM:Add support for HiFiBerry Digi. Driver is - based on the patched WM8804 driver. - -Signed-off-by: Daniel Matuschek ---- - 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 60fe399..fa82682 100644 ---- a/sound/soc/bcm/Kconfig -+++ b/sound/soc/bcm/Kconfig -@@ -16,6 +16,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 eb869fa..b9845a5 100644 ---- a/sound/soc/bcm/Makefile -+++ b/sound/soc/bcm/Makefile -@@ -5,6 +5,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-hifiberry-digi-objs := hifiberry_digi.o - snd-soc-rpi-dac-objs := rpi-dac.o - snd-soc-rpi-mbed-objs := rpi-mbed.o - snd-soc-rpi-tda1541a-objs := rpi-tda1541a.o -@@ -13,6 +14,7 @@ snd-soc-rpi-ess9018-objs := rpi-ess9018.o - snd-soc-rpi-pcm5102a-objs := rpi-pcm5102a.o - - obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o -+obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_MBED) += snd-soc-rpi-mbed.o - obj-$(CONFIG_SND_BCM2708_SOC_RPI_CODEC_TDA1541A) += snd-soc-rpi-tda1541a.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 -+ * based on the HifiBerry DAC driver by Florian Meier -+ * 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 -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#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 "); -+MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); -+MODULE_LICENSE("GPL v2"); --- -1.8.5.5 - - -From ddbc200cf0c7c1c39e34478dc4db1433b802ed3b Mon Sep 17 00:00:00 2001 -From: Daniel Matuschek -Date: Thu, 16 Jan 2014 07:26:08 +0100 -Subject: [PATCH 099/118] BCM2708: Added support for HiFiBerry Digi board Board - initalization by I2C - -Signed-off-by: Daniel Matuschek ---- - 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 dfc2a8c..1cba3d7 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -653,6 +653,21 @@ struct platform_device bcm2708_powerman_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", -@@ -889,6 +904,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.8.5.5 - - -From b269f59f898dff5e16485664e4089253d0ac34ff Mon Sep 17 00:00:00 2001 -From: Daniel Matuschek -Date: Thu, 16 Jan 2014 07:27:28 +0100 -Subject: [PATCH 100/118] 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 ---- - 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 6a2c0f4..ca2a265 100644 ---- a/arch/arm/configs/bcmrpi_defconfig -+++ b/arch/arm/configs/bcmrpi_defconfig -@@ -737,8 +737,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.8.5.5 - - -From c7851896f0666b20f000f85417ce7b06555a77bc Mon Sep 17 00:00:00 2001 -From: Daniel Matuschek -Date: Thu, 16 Jan 2014 07:36:35 +0100 -Subject: [PATCH 101/118] ASoC: wm8804: Set idle_bias_off to false Idle bias - has been change to remove warning on driver startup - -Signed-off-by: Daniel Matuschek ---- - 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 7ec8381..50d0f0c 100644 ---- a/sound/soc/codecs/wm8804.c -+++ b/sound/soc/codecs/wm8804.c -@@ -685,7 +685,7 @@ static int wm8804_probe(struct snd_soc_codec *codec) - .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.8.5.5 - - -From db0f3eb89dbcc2e8c6cd9a48da2a6592e63bdc3b Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 11 Feb 2014 16:34:37 +0000 -Subject: [PATCH 102/118] dma_engine: Replace DMA_SUCCESS with DMA_COMPLETE - ---- - drivers/dma/bcm2708-dmaengine.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/dma/bcm2708-dmaengine.c b/drivers/dma/bcm2708-dmaengine.c -index 7d5ed19..b244293 100644 ---- a/drivers/dma/bcm2708-dmaengine.c -+++ b/drivers/dma/bcm2708-dmaengine.c -@@ -212,7 +212,7 @@ static enum dma_status bcm2708_dma_tx_status(struct dma_chan *chan, - unsigned long flags; - - ret = dma_cookie_status(chan, cookie, txstate); -- if (ret == DMA_SUCCESS || !txstate) -+ if (ret == DMA_COMPLETE || !txstate) - return ret; - - spin_lock_irqsave(&c->vc.lock, flags); --- -1.8.5.5 - - -From 7731c05f3a3edb3ae7973c4fafdcb1b4a2e7f905 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 11 Feb 2014 17:03:51 +0000 -Subject: [PATCH 103/118] bcm2708: Allow disk activity led gpio to be specified - ---- - arch/arm/mach-bcm2708/bcm2708.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index 1cba3d7..e9f0701 100644 ---- a/arch/arm/mach-bcm2708/bcm2708.c -+++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -83,6 +83,8 @@ - /* 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 void __init bcm2708_init_led(void); -@@ -1081,7 +1083,9 @@ static void __init bcm2708_timer_init(void) - - static void __init bcm2708_init_led(void) - { -- platform_device_register(&bcm2708_led_device); -+ bcm2708_leds[0].gpio = disk_led_gpio; -+ bcm2708_leds[0].active_low = disk_led_active_low; -+ platform_device_register(&bcm2708_led_device); - } - #else - static inline void bcm2708_init_led(void) -@@ -1120,4 +1124,6 @@ static void __init board_reserve(void) - module_param(boardrev, uint, 0644); - module_param(serial, uint, 0644); - 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); --- -1.8.5.5 - - -From c1b49956bc11c822d701d932726592ddeb111145 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Tue, 11 Feb 2014 19:12:47 +0000 -Subject: [PATCH 104/118] bcm2708fb: Allow swapping of red/blue in 24/32 modes - ---- - drivers/video/bcm2708_fb.c | 21 ++++++++++++++------- - 1 file changed, 14 insertions(+), 7 deletions(-) - -diff --git a/drivers/video/bcm2708_fb.c b/drivers/video/bcm2708_fb.c -index 935288d..3f1bc8f 100644 ---- a/drivers/video/bcm2708_fb.c -+++ b/drivers/video/bcm2708_fb.c -@@ -53,6 +53,10 @@ - module_param(dma_busy_wait_threshold, int, 0644); - MODULE_PARM_DESC(dma_busy_wait_threshold, "Busy-wait for DMA completion below this area"); - -+static int fbwidth = 800; /* module parameter */ -+static int fbheight = 480; /* module parameter */ -+static int fbdepth = 16; /* module parameter */ -+static int fbswap = 0; /* module parameter */ - - /* this data structure describes each frame buffer device we find */ - -@@ -185,7 +189,12 @@ static int bcm2708_fb_set_bitfields(struct fb_var_screeninfo *var) - * encoded in the pixel data. Calculate their position from - * the bitfield length defined above. - */ -- if (ret == 0 && var->bits_per_pixel >= 24) { -+ if (ret == 0 && var->bits_per_pixel >= 24 && fbswap) { -+ var->blue.offset = 0; -+ var->green.offset = var->blue.offset + var->blue.length; -+ var->red.offset = var->green.offset + var->green.length; -+ var->transp.offset = var->red.offset + var->red.length; -+ } else if (ret == 0 && var->bits_per_pixel >= 24) { - var->red.offset = 0; - var->green.offset = var->red.offset + var->red.length; - var->blue.offset = var->green.offset + var->green.length; -@@ -557,10 +566,6 @@ static irqreturn_t bcm2708_fb_dma_irq(int irq, void *cxt) - .fb_imageblit = bcm2708_fb_imageblit, - }; - --static int fbwidth = 800; /* module parameter */ --static int fbheight = 480; /* module parameter */ --static int fbdepth = 16; /* module parameter */ -- - static int bcm2708_fb_register(struct bcm2708_fb *fb) - { - int ret; -@@ -618,8 +623,8 @@ static int bcm2708_fb_register(struct bcm2708_fb *fb) - - fb_set_var(&fb->fb, &fb->fb.var); - -- print_debug("BCM2708FB: registering framebuffer (%dx%d@%d)\n", fbwidth, -- fbheight, fbdepth); -+ print_debug("BCM2708FB: registering framebuffer (%dx%d@%d) (%d)\n", fbwidth -+ fbheight, fbdepth, fbswap); - - ret = register_framebuffer(&fb->fb); - print_debug("BCM2708FB: register framebuffer (%d)\n", ret); -@@ -749,6 +754,7 @@ static void __exit bcm2708_fb_exit(void) - module_param(fbwidth, int, 0644); - module_param(fbheight, int, 0644); - module_param(fbdepth, int, 0644); -+module_param(fbswap, int, 0644); - - MODULE_DESCRIPTION("BCM2708 framebuffer driver"); - MODULE_LICENSE("GPL"); -@@ -756,3 +762,4 @@ static void __exit bcm2708_fb_exit(void) - MODULE_PARM_DESC(fbwidth, "Width of ARM Framebuffer"); - MODULE_PARM_DESC(fbheight, "Height of ARM Framebuffer"); - MODULE_PARM_DESC(fbdepth, "Bit depth of ARM Framebuffer"); -+MODULE_PARM_DESC(fbswap, "Swap order of red and blue in 24 and 32 bit modes"); --- -1.8.5.5 - - -From 6f70ac169e9ad2c6a09e47e1271b44dcda9ff0f9 Mon Sep 17 00:00:00 2001 +From 200aef7de99ef577f9d476b24a60a41a2d658828 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Mon, 23 Dec 2013 15:42:21 +0000 -Subject: [PATCH 105/118] V4L2: Enable MJPEG encoding +Subject: [PATCH 67/99] V4L2: Enable MJPEG encoding Requires GPU firmware update to support MJPEG encoder. @@ -109662,10 +104696,10 @@ index 856e80e..764bb12 100644 1.8.5.5 -From a221415cf1eb5746f62ccbea489caeff9dd353ff Mon Sep 17 00:00:00 2001 +From 05df2eb83152a9f7f57210f997286e0a5b09a7b6 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Thu, 2 Jan 2014 15:57:06 +0000 -Subject: [PATCH 106/118] V4L2: Correct flag settings for compressed formats +Subject: [PATCH 68/99] V4L2: Correct flag settings for compressed formats Set flags field correctly on enum_fmt_vid_cap for compressed image formats. @@ -109761,11 +104795,11 @@ index 602b4a7..076f9a8 100644 1.8.5.5 -From 22ce4a833a0957f50d318ecb8ec4824759531aaa Mon Sep 17 00:00:00 2001 +From 3c0b1fcf65ceea6294af1eba1068de830c196629 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 12 Feb 2014 11:18:20 +0000 -Subject: [PATCH 107/118] V4L2: H264 profile & level ctrls, FPS control and - auto exp pri +Subject: [PATCH 69/99] V4L2: H264 profile & level ctrls, FPS control and auto + exp pri Several control handling updates. H264 profile and level controls. @@ -110453,10 +105487,10 @@ index b08a4b0..ae8fef9 100644 1.8.5.5 -From d5e0d271054b8bbe313c270523108b1739e5463d Mon Sep 17 00:00:00 2001 +From 90de1796e8a3779fc00ee50e8b292e212c12d8d5 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 12 Feb 2014 11:39:20 +0000 -Subject: [PATCH 108/118] V4L2: Correct BGR24 to RGB24 in format table +Subject: [PATCH 70/99] V4L2: Correct BGR24 to RGB24 in format table Signed-off-by: Dave Stevenson --- @@ -110482,11 +105516,10 @@ index 6d0d77a..8285e6a 100644 1.8.5.5 -From 7bb34b506337c9704d7ad0d163db0004fc4a0604 Mon Sep 17 00:00:00 2001 +From 366ce2a3ef487101224d507fe0439e54018af5f9 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Wed, 12 Feb 2014 15:35:41 +0000 -Subject: [PATCH 109/118] V4L2: Add additional pixel formats. Correct - colourspace +Subject: [PATCH 71/99] V4L2: Add additional pixel formats. Correct colourspace Adds the other flavours of YUYV, and NV12. Corrects the overlay advertised colourspace. @@ -110554,10 +105587,10 @@ index 8285e6a..3dea993 100644 1.8.5.5 -From 5d5ac158e26cf80d4158d1061353b77da49931b5 Mon Sep 17 00:00:00 2001 +From cd8f58dffc2d8efcfa9445e59899c82740f2280b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 14 Feb 2014 17:08:18 +0000 -Subject: [PATCH 110/118] V4L2: Drop logging msg from info to debug +Subject: [PATCH 72/99] V4L2: Drop logging msg from info to debug Signed-off-by: Dave Stevenson --- @@ -110581,10 +105614,10 @@ index a06fb44..82752e6 100644 1.8.5.5 -From 112cf0378d89551bb1a638e6f847c92b9bc55482 Mon Sep 17 00:00:00 2001 +From 709e0286bd1444fba0fecb2cddc1a86f379ef202 Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Fri, 14 Feb 2014 17:12:08 +0000 -Subject: [PATCH 111/118] V4L2: Initial pass at scene modes. +Subject: [PATCH 73/99] V4L2: Initial pass at scene modes. Only supports exposure mode and metering modes. @@ -110949,66 +105982,10 @@ index 45cf790..b7a7e883 100644 1.8.5.5 -From f59363b414b39263197a68327fdef85fd98decc4 Mon Sep 17 00:00:00 2001 -From: popcornmix -Date: Fri, 21 Feb 2014 17:15:59 +0000 -Subject: [PATCH 112/118] alsa: Make alsa work queue high priority. Fixes - underrun issues when using negitive nice priority - ---- - sound/arm/bcm2835-vchiq.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/arm/bcm2835-vchiq.c b/sound/arm/bcm2835-vchiq.c -index 4013d83..ee09b13 100755 ---- a/sound/arm/bcm2835-vchiq.c -+++ b/sound/arm/bcm2835-vchiq.c -@@ -178,7 +178,7 @@ int bcm2835_audio_write(bcm2835_alsa_stream_t *alsa_stream, - - void my_workqueue_init(bcm2835_alsa_stream_t * alsa_stream) - { -- alsa_stream->my_wq = create_workqueue("my_queue"); -+ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1); - return; - } - --- -1.8.5.5 - - -From fe4d19dc46ba7cc68175820788e7aa710e39b95d Mon Sep 17 00:00:00 2001 -From: Matt Whitlock -Date: Tue, 25 Mar 2014 03:45:21 -0400 -Subject: [PATCH 113/118] fix sign in sdhci_bcm2708_raw_writel wait calculation - -The ns_wait variable is intended to hold a lower bound on the number of nanoseconds that have elapsed since the last sdhci register write. However, the actual calculation of it was incorrect, as the subtraction was inverted. This commit fixes the calculation. - -Note that this correction has no bearing when running with the default cycle_delay of 2 and the default clock rate of 50 MHz, under which conditions ns_2clk is 40 nanoseconds and ns_wait, regardless of whether the subtraction is done correctly or incorrectly, cannot possibly be less than 40 except for during the one-microsecond period just before the tick counter wraps around to meet last_write_hpt (i.e., approximately 4295 seconds after the preceding sdhci register write). The correction in this commit only comes into play if ns_2clk > 1000, which requires a cycle_delay of 51 or greater when using the default clock rate. Under those conditions, sdhci_bcm2708_raw_writel will not wait for the full cycle_delay count if at least 1000 nanoseconds have elapsed since the last register write. ---- - drivers/mmc/host/sdhci-bcm2708.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c -index 1ebbe2d..3173c18 100644 ---- a/drivers/mmc/host/sdhci-bcm2708.c -+++ b/drivers/mmc/host/sdhci-bcm2708.c -@@ -263,7 +263,7 @@ static void sdhci_bcm2708_raw_writel(struct sdhci_host *host, u32 val, int reg) - { - /* we must have waited at least this many ns: */ - unsigned int ns_wait = HPTIME_CLK_NS * -- (last_write_hpt - now - 1); -+ (now - last_write_hpt - 1); - if (ns_wait < ns_2clk) - ndelay(ns_2clk - ns_wait); - } --- -1.8.5.5 - - -From fd054baee964388cc85646c10d8c5492f81b2e7b Mon Sep 17 00:00:00 2001 +From fec046e0d40676e437fc43b08ff3ee80ba3e650b Mon Sep 17 00:00:00 2001 From: Dave Stevenson Date: Tue, 25 Mar 2014 11:48:01 +0000 -Subject: [PATCH 114/118] V4L2: Add manual white balance control. +Subject: [PATCH 74/99] V4L2: Add manual white balance control. Adds support for V4L2_CID_RED_BALANCE and V4L2_CID_BLUE_BALANCE. Only has an effect if @@ -111136,51 +106113,115 @@ index ae8fef9..089f949 100644 1.8.5.5 -From 6fb84d86e3b5dd149574558efd7246bbeddfc4c8 Mon Sep 17 00:00:00 2001 +From b30dbb04d4ab3fcbb62535b6ce44c6e77f296788 Mon Sep 17 00:00:00 2001 From: popcornmix -Date: Wed, 12 Mar 2014 11:46:34 +0000 -Subject: [PATCH 115/118] ASoc: Don't report S24_LE support, it produces white - noise with xbmc +Date: Mon, 2 Dec 2013 16:57:44 +0000 +Subject: [PATCH 75/99] config: Enable V4L / MMAL driver --- - sound/soc/bcm/bcm2708-i2s.c | 2 +- - sound/soc/codecs/pcm5102a.c | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) + arch/arm/configs/bcmrpi_defconfig | 3 +++ + 1 file changed, 3 insertions(+) -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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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 @@ - .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 - }, - }; +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index 88692be..75a262d 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -692,6 +692,9 @@ CONFIG_DVB_B2C2_FLEXCOP_USB=m + CONFIG_VIDEO_EM28XX=m + CONFIG_VIDEO_EM28XX_ALSA=m + CONFIG_VIDEO_EM28XX_DVB=m ++CONFIG_V4L_PLATFORM_DRIVERS=y ++CONFIG_VIDEO_BCM2835=y ++CONFIG_VIDEO_BCM2835_MMAL=m + CONFIG_RADIO_SI470X=y + CONFIG_USB_SI470X=m + CONFIG_I2C_SI470X=m -- 1.8.5.5 -From bdbfd9634053d55a1346026132f8bf3e90b07300 Mon Sep 17 00:00:00 2001 +From 01be7e4fc1410a3dc965d682c705f8365dc707e9 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 18 Dec 2013 22:16:19 +0000 +Subject: [PATCH 76/99] 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 75a262d..1041f5e 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 5b6b003..56de606 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -7285,6 +7285,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.8.5.5 + + +From b5d9d7314ef0337c25180ee505753b46198f5244 Mon Sep 17 00:00:00 2001 From: Julian Scheel Date: Wed, 19 Feb 2014 16:06:59 +0100 -Subject: [PATCH 116/118] snd-bcm2835: Add support for spdif/hdmi passthrough +Subject: [PATCH 77/99] 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 @@ -111341,7 +106382,7 @@ index 8c5334a..aad905f 100755 return 0; } diff --git a/sound/arm/bcm2835-pcm.c b/sound/arm/bcm2835-pcm.c -index 7e8b8d9..1845a77 100755 +index 7f6d75e..fe27a8f 100755 --- a/sound/arm/bcm2835-pcm.c +++ b/sound/arm/bcm2835-pcm.c @@ -15,6 +15,8 @@ @@ -111399,7 +106440,7 @@ index 7e8b8d9..1845a77 100755 if (idx > MAX_SUBSTREAMS) { audio_error ("substream(%d) device doesn't exist max(%d) substreams allowed\n", -@@ -139,7 +164,13 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) +@@ -138,7 +163,13 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) runtime->private_data = alsa_stream; runtime->private_free = snd_bcm2835_playback_free; @@ -111415,8 +106456,8 @@ index 7e8b8d9..1845a77 100755 snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 16); @@ -150,6 +181,7 @@ static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream) - return err; } + chip->alsa_stream[idx] = alsa_stream; + chip->opened |= (1 << idx); alsa_stream->open = 1; @@ -111652,10 +106693,10 @@ index 36afee3..8c2fe26 100755 1.8.5.5 -From 56cc27f5e81c3f29edd488a5a219b647f2f8c64a Mon Sep 17 00:00:00 2001 +From adbf95dfbf47e2e320b1258306d61ae17524b1be Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 12:58:23 +0000 -Subject: [PATCH 117/118] dwc_otg: fiq_fsm: Base commit for driver rewrite +Subject: [PATCH 78/99] dwc_otg: fiq_fsm: Base commit for driver rewrite This commit removes the previous FIQ fixes entirely and adds fiq_fsm. @@ -111694,10 +106735,10 @@ previously implemented FIQ fixes. delete mode 100755 drivers/usb/host/dwc_otg/dwc_otg_mphi_fix.h diff --git a/arch/arm/mach-bcm2708/bcm2708.c b/arch/arm/mach-bcm2708/bcm2708.c -index e9f0701..29f6128 100644 +index 2b11e9d..91c008f 100644 --- a/arch/arm/mach-bcm2708/bcm2708.c +++ b/arch/arm/mach-bcm2708/bcm2708.c -@@ -327,20 +327,6 @@ static void __init bcm2708_clocksource_init(void) +@@ -328,20 +328,6 @@ static void __init bcm2708_clocksource_init(void) }, }; @@ -111718,7 +106759,7 @@ index e9f0701..29f6128 100644 static u64 usb_dmamask = DMA_BIT_MASK(DMA_MASK_BITS_COMMON); -@@ -874,11 +860,6 @@ void __init bcm2708_init(void) +@@ -724,11 +710,6 @@ void __init bcm2708_init(void) #endif bcm_register_device(&bcm2708_systemtimer_device); bcm_register_device(&bcm2708_fb_device); @@ -111731,7 +106772,7 @@ index e9f0701..29f6128 100644 bcm_register_device(&bcm2708_uart1_device); bcm_register_device(&bcm2708_powerman_device); diff --git a/drivers/usb/host/dwc_otg/Makefile b/drivers/usb/host/dwc_otg/Makefile -index 8d177b1..6f9d337 100644 +index a56f193..e7bdd12 100644 --- a/drivers/usb/host/dwc_otg/Makefile +++ b/drivers/usb/host/dwc_otg/Makefile @@ -36,7 +36,8 @@ dwc_otg-objs += dwc_otg_cil.o dwc_otg_cil_intr.o @@ -116281,10 +111322,10 @@ index ca17379..0000000 1.8.5.5 -From 2514e943096ff51dd5a83b28b4b4d45ec2693434 Mon Sep 17 00:00:00 2001 +From fbc1db3f574eceffd75f1e46cbe620f0b423a02d Mon Sep 17 00:00:00 2001 From: P33M Date: Wed, 19 Mar 2014 15:13:53 +0000 -Subject: [PATCH 118/118] Fix ARM architecture issue with local_irq_restore() +Subject: [PATCH 79/99] Fix ARM architecture issue with local_irq_restore() If local_fiq_enable() is called before a local_irq_restore(flags) where the flags variable has the F bit set, the FIQ will be erroneously disabled. @@ -116384,3 +111425,4280 @@ index 0812d3a..6d01261 100644 -- 1.8.5.5 + +From c733f3084b8c69e5dc5f09e338959e125b6db438 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 14:22:53 +0100 +Subject: [PATCH 80/99] 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 +--- + 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 ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "virt-dma.h" ++ ++#include ++#include ++ ++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 "); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From aa2e7c4643daf4bd5e8b5491906e6bf9640ad9ce Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 14:33:38 +0100 +Subject: [PATCH 81/99] ASoC: Add support for BCM2708 + +This driver adds support for digital audio (I2S) +for the BCM2708 SoC that is used by the +Raspberry Pi. External audio codecs can be +connected to the Raspberry Pi via P5 header. + +It relies on cyclic DMA engine support for BCM2708. + +Signed-off-by: Florian Meier +--- + sound/soc/bcm/Kconfig | 11 + + sound/soc/bcm/Makefile | 4 + + sound/soc/bcm/bcm2708-i2s.c | 940 ++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 955 insertions(+) + create mode 100644 sound/soc/bcm/bcm2708-i2s.c + +diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig +index 6a834e1..7e5b945 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -7,3 +7,14 @@ config SND_BCM2835_SOC_I2S + Say Y or M if you want to add support for codecs attached to + the BCM2835 I2S interface. You will also need + to select the audio interfaces to support below. ++ ++config SND_BCM2708_SOC_I2S ++ tristate "SoC Audio support for the Broadcom BCM2708 I2S module" ++ depends on MACH_BCM2708 ++ select REGMAP_MMIO ++ select SND_SOC_DMAENGINE_PCM ++ select SND_SOC_GENERIC_DMAENGINE_PCM ++ help ++ 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. +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index bc816b7..f8bbe1f 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -3,3 +3,7 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o + + obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o + ++# BCM2708 Platform Support ++snd-soc-bcm2708-i2s-objs := bcm2708-i2s.o ++ ++obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o +diff --git a/sound/soc/bcm/bcm2708-i2s.c b/sound/soc/bcm/bcm2708-i2s.c +new file mode 100644 +index 0000000..ebaf3d6 +--- /dev/null ++++ b/sound/soc/bcm/bcm2708-i2s.c +@@ -0,0 +1,940 @@ ++/* ++ * ALSA SoC I2S Audio Layer for Broadcom BCM2708 SoC ++ * ++ * Author: Florian Meier ++ * Copyright 2013 ++ * ++ * Based on ++ * Raspberry Pi PCM I2S ALSA Driver ++ * Copyright (c) by Phil Poole 2013 ++ * ++ * ALSA SoC I2S (McBSP) Audio Layer for TI DAVINCI processor ++ * Vladimir Barinov, ++ * Copyright (C) 2007 MontaVista Software, Inc., ++ * ++ * OMAP ALSA SoC DAI driver using McBSP port ++ * Copyright (C) 2008 Nokia Corporation ++ * Contact: Jarkko Nikula ++ * Peter Ujfalusi ++ * ++ * Freescale SSI ALSA SoC Digital Audio Interface (DAI) driver ++ * Author: Timur Tabi ++ * Copyright 2007-2010 Freescale Semiconductor, Inc. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Clock registers */ ++#define BCM2708_CLK_PCMCTL_REG 0x00 ++#define BCM2708_CLK_PCMDIV_REG 0x04 ++ ++/* Clock register settings */ ++#define BCM2708_CLK_PASSWD (0x5a000000) ++#define BCM2708_CLK_PASSWD_MASK (0xff000000) ++#define BCM2708_CLK_MASH(v) ((v) << 9) ++#define BCM2708_CLK_FLIP BIT(8) ++#define BCM2708_CLK_BUSY BIT(7) ++#define BCM2708_CLK_KILL BIT(5) ++#define BCM2708_CLK_ENAB BIT(4) ++#define BCM2708_CLK_SRC(v) (v) ++ ++#define BCM2708_CLK_SHIFT (12) ++#define BCM2708_CLK_DIVI(v) ((v) << BCM2708_CLK_SHIFT) ++#define BCM2708_CLK_DIVF(v) (v) ++#define BCM2708_CLK_DIVF_MASK (0xFFF) ++ ++enum { ++ BCM2708_CLK_MASH_0 = 0, ++ BCM2708_CLK_MASH_1, ++ BCM2708_CLK_MASH_2, ++ BCM2708_CLK_MASH_3, ++}; ++ ++enum { ++ BCM2708_CLK_SRC_GND = 0, ++ BCM2708_CLK_SRC_OSC, ++ BCM2708_CLK_SRC_DBG0, ++ BCM2708_CLK_SRC_DBG1, ++ BCM2708_CLK_SRC_PLLA, ++ BCM2708_CLK_SRC_PLLC, ++ BCM2708_CLK_SRC_PLLD, ++ BCM2708_CLK_SRC_HDMI, ++}; ++ ++/* Most clocks are not useable (freq = 0) */ ++static const unsigned int bcm2708_clk_freq[BCM2708_CLK_SRC_HDMI+1] = { ++ [BCM2708_CLK_SRC_GND] = 0, ++ [BCM2708_CLK_SRC_OSC] = 19200000, ++ [BCM2708_CLK_SRC_DBG0] = 0, ++ [BCM2708_CLK_SRC_DBG1] = 0, ++ [BCM2708_CLK_SRC_PLLA] = 0, ++ [BCM2708_CLK_SRC_PLLC] = 0, ++ [BCM2708_CLK_SRC_PLLD] = 500000000, ++ [BCM2708_CLK_SRC_HDMI] = 0, ++}; ++ ++/* I2S registers */ ++#define BCM2708_I2S_CS_A_REG 0x00 ++#define BCM2708_I2S_FIFO_A_REG 0x04 ++#define BCM2708_I2S_MODE_A_REG 0x08 ++#define BCM2708_I2S_RXC_A_REG 0x0c ++#define BCM2708_I2S_TXC_A_REG 0x10 ++#define BCM2708_I2S_DREQ_A_REG 0x14 ++#define BCM2708_I2S_INTEN_A_REG 0x18 ++#define BCM2708_I2S_INTSTC_A_REG 0x1c ++#define BCM2708_I2S_GRAY_REG 0x20 ++ ++/* I2S register settings */ ++#define BCM2708_I2S_STBY BIT(25) ++#define BCM2708_I2S_SYNC BIT(24) ++#define BCM2708_I2S_RXSEX BIT(23) ++#define BCM2708_I2S_RXF BIT(22) ++#define BCM2708_I2S_TXE BIT(21) ++#define BCM2708_I2S_RXD BIT(20) ++#define BCM2708_I2S_TXD BIT(19) ++#define BCM2708_I2S_RXR BIT(18) ++#define BCM2708_I2S_TXW BIT(17) ++#define BCM2708_I2S_CS_RXERR BIT(16) ++#define BCM2708_I2S_CS_TXERR BIT(15) ++#define BCM2708_I2S_RXSYNC BIT(14) ++#define BCM2708_I2S_TXSYNC BIT(13) ++#define BCM2708_I2S_DMAEN BIT(9) ++#define BCM2708_I2S_RXTHR(v) ((v) << 7) ++#define BCM2708_I2S_TXTHR(v) ((v) << 5) ++#define BCM2708_I2S_RXCLR BIT(4) ++#define BCM2708_I2S_TXCLR BIT(3) ++#define BCM2708_I2S_TXON BIT(2) ++#define BCM2708_I2S_RXON BIT(1) ++#define BCM2708_I2S_EN (1) ++ ++#define BCM2708_I2S_CLKDIS BIT(28) ++#define BCM2708_I2S_PDMN BIT(27) ++#define BCM2708_I2S_PDME BIT(26) ++#define BCM2708_I2S_FRXP BIT(25) ++#define BCM2708_I2S_FTXP BIT(24) ++#define BCM2708_I2S_CLKM BIT(23) ++#define BCM2708_I2S_CLKI BIT(22) ++#define BCM2708_I2S_FSM BIT(21) ++#define BCM2708_I2S_FSI BIT(20) ++#define BCM2708_I2S_FLEN(v) ((v) << 10) ++#define BCM2708_I2S_FSLEN(v) (v) ++ ++#define BCM2708_I2S_CHWEX BIT(15) ++#define BCM2708_I2S_CHEN BIT(14) ++#define BCM2708_I2S_CHPOS(v) ((v) << 4) ++#define BCM2708_I2S_CHWID(v) (v) ++#define BCM2708_I2S_CH1(v) ((v) << 16) ++#define BCM2708_I2S_CH2(v) (v) ++ ++#define BCM2708_I2S_TX_PANIC(v) ((v) << 24) ++#define BCM2708_I2S_RX_PANIC(v) ((v) << 16) ++#define BCM2708_I2S_TX(v) ((v) << 8) ++#define BCM2708_I2S_RX(v) (v) ++ ++#define BCM2708_I2S_INT_RXERR BIT(3) ++#define BCM2708_I2S_INT_TXERR BIT(2) ++#define BCM2708_I2S_INT_RXR BIT(1) ++#define BCM2708_I2S_INT_TXW BIT(0) ++ ++/* I2S DMA interface */ ++#define BCM2708_I2S_FIFO_PHYSICAL_ADDR 0x7E203004 ++#define BCM2708_DMA_DREQ_PCM_TX 2 ++#define BCM2708_DMA_DREQ_PCM_RX 3 ++ ++/* General device struct */ ++struct bcm2708_i2s_dev { ++ struct device *dev; ++ struct snd_dmaengine_dai_dma_data dma_data[2]; ++ unsigned int fmt; ++ unsigned int bclk_ratio; ++ ++ struct regmap *i2s_regmap; ++ struct regmap *clk_regmap; ++}; ++ ++static void bcm2708_i2s_start_clock(struct bcm2708_i2s_dev *dev) ++{ ++ /* Start the clock if in master mode */ ++ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; ++ ++ switch (master) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ case SND_SOC_DAIFMT_CBS_CFM: ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void bcm2708_i2s_stop_clock(struct bcm2708_i2s_dev *dev) ++{ ++ uint32_t clkreg; ++ int timeout = 1000; ++ ++ /* Stop clock */ ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD); ++ ++ /* Wait for the BUSY flag going down */ ++ while (--timeout) { ++ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); ++ if (!(clkreg & BCM2708_CLK_BUSY)) ++ break; ++ } ++ ++ if (!timeout) { ++ /* KILL the clock */ ++ dev_err(dev->dev, "I2S clock didn't stop. Kill the clock!\n"); ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD_MASK, ++ BCM2708_CLK_KILL | BCM2708_CLK_PASSWD); ++ } ++} ++ ++static void bcm2708_i2s_clear_fifos(struct bcm2708_i2s_dev *dev, ++ bool tx, bool rx) ++{ ++ int timeout = 1000; ++ uint32_t syncval; ++ uint32_t csreg; ++ uint32_t i2s_active_state; ++ uint32_t clkreg; ++ uint32_t clk_active_state; ++ uint32_t off; ++ uint32_t clr; ++ ++ off = tx ? BCM2708_I2S_TXON : 0; ++ off |= rx ? BCM2708_I2S_RXON : 0; ++ ++ clr = tx ? BCM2708_I2S_TXCLR : 0; ++ clr |= rx ? BCM2708_I2S_RXCLR : 0; ++ ++ /* Backup the current state */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ i2s_active_state = csreg & (BCM2708_I2S_RXON | BCM2708_I2S_TXON); ++ ++ regmap_read(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, &clkreg); ++ clk_active_state = clkreg & BCM2708_CLK_ENAB; ++ ++ /* Start clock if not running */ ++ if (!clk_active_state) { ++ regmap_update_bits(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, ++ BCM2708_CLK_PASSWD_MASK | BCM2708_CLK_ENAB, ++ BCM2708_CLK_PASSWD | BCM2708_CLK_ENAB); ++ } ++ ++ /* Stop I2S module */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, off, 0); ++ ++ /* ++ * Clear the FIFOs ++ * Requires at least 2 PCM clock cycles to take effect ++ */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, clr, clr); ++ ++ /* Wait for 2 PCM clock cycles */ ++ ++ /* ++ * Toggle the SYNC flag. After 2 PCM clock cycles it can be read back ++ * FIXME: This does not seem to work for slave mode! ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &syncval); ++ syncval &= BCM2708_I2S_SYNC; ++ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_SYNC, ~syncval); ++ ++ /* Wait for the SYNC flag changing it's state */ ++ while (--timeout) { ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ if ((csreg & BCM2708_I2S_SYNC) != syncval) ++ break; ++ } ++ ++ if (!timeout) ++ dev_err(dev->dev, "I2S SYNC error!\n"); ++ ++ /* Stop clock if it was not running before */ ++ if (!clk_active_state) ++ bcm2708_i2s_stop_clock(dev); ++ ++ /* Restore I2S state */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_RXON | BCM2708_I2S_TXON, i2s_active_state); ++} ++ ++static int bcm2708_i2s_set_dai_fmt(struct snd_soc_dai *dai, ++ unsigned int fmt) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ dev->fmt = fmt; ++ return 0; ++} ++ ++static int bcm2708_i2s_set_dai_bclk_ratio(struct snd_soc_dai *dai, ++ unsigned int ratio) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ dev->bclk_ratio = ratio; ++ return 0; ++} ++ ++static int bcm2708_i2s_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ unsigned int sampling_rate = params_rate(params); ++ unsigned int data_length, data_delay, bclk_ratio; ++ unsigned int ch1pos, ch2pos, mode, format; ++ unsigned int mash = BCM2708_CLK_MASH_1; ++ unsigned int divi, divf, target_frequency; ++ int clk_src = -1; ++ unsigned int master = dev->fmt & SND_SOC_DAIFMT_MASTER_MASK; ++ bool bit_master = (master == SND_SOC_DAIFMT_CBS_CFS ++ || master == SND_SOC_DAIFMT_CBS_CFM); ++ ++ bool frame_master = (master == SND_SOC_DAIFMT_CBS_CFS ++ || master == SND_SOC_DAIFMT_CBM_CFS); ++ uint32_t csreg; ++ ++ /* ++ * If a stream is already enabled, ++ * the registers are already set properly. ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &csreg); ++ ++ if (csreg & (BCM2708_I2S_TXON | BCM2708_I2S_RXON)) ++ return 0; ++ ++ /* ++ * Adjust the data length according to the format. ++ * We prefill the half frame length with an integer ++ * divider of 2400 as explained at the clock settings. ++ * Maybe it is overwritten there, if the Integer mode ++ * does not apply. ++ */ ++ switch (params_format(params)) { ++ case SNDRV_PCM_FORMAT_S16_LE: ++ data_length = 16; ++ bclk_ratio = 40; ++ break; ++ case SNDRV_PCM_FORMAT_S32_LE: ++ data_length = 32; ++ bclk_ratio = 80; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* If bclk_ratio already set, use that one. */ ++ if (dev->bclk_ratio) ++ bclk_ratio = dev->bclk_ratio; ++ ++ /* ++ * Clock Settings ++ * ++ * The target frequency of the bit clock is ++ * sampling rate * frame length ++ * ++ * Integer mode: ++ * Sampling rates that are multiples of 8000 kHz ++ * can be driven by the oscillator of 19.2 MHz ++ * with an integer divider as long as the frame length ++ * is an integer divider of 19200000/8000=2400 as set up above. ++ * This is no longer possible if the sampling rate ++ * is too high (e.g. 192 kHz), because the oscillator is too slow. ++ * ++ * MASH mode: ++ * For all other sampling rates, it is not possible to ++ * have an integer divider. Approximate the clock ++ * with the MASH module that induces a slight frequency ++ * variance. To minimize that it is best to have the fastest ++ * clock here. That is PLLD with 500 MHz. ++ */ ++ target_frequency = sampling_rate * bclk_ratio; ++ clk_src = BCM2708_CLK_SRC_OSC; ++ mash = BCM2708_CLK_MASH_0; ++ ++ if (bcm2708_clk_freq[clk_src] % target_frequency == 0 ++ && bit_master && frame_master) { ++ divi = bcm2708_clk_freq[clk_src] / target_frequency; ++ divf = 0; ++ } else { ++ uint64_t dividend; ++ ++ if (!dev->bclk_ratio) { ++ /* ++ * Overwrite bclk_ratio, because the ++ * above trick is not needed or can ++ * not be used. ++ */ ++ bclk_ratio = 2 * data_length; ++ } ++ ++ target_frequency = sampling_rate * bclk_ratio; ++ ++ clk_src = BCM2708_CLK_SRC_PLLD; ++ mash = BCM2708_CLK_MASH_1; ++ ++ dividend = bcm2708_clk_freq[clk_src]; ++ dividend <<= BCM2708_CLK_SHIFT; ++ do_div(dividend, target_frequency); ++ divi = dividend >> BCM2708_CLK_SHIFT; ++ divf = dividend & BCM2708_CLK_DIVF_MASK; ++ } ++ ++ /* Set clock divider */ ++ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMDIV_REG, BCM2708_CLK_PASSWD ++ | BCM2708_CLK_DIVI(divi) ++ | BCM2708_CLK_DIVF(divf)); ++ ++ /* Setup clock, but don't start it yet */ ++ regmap_write(dev->clk_regmap, BCM2708_CLK_PCMCTL_REG, BCM2708_CLK_PASSWD ++ | BCM2708_CLK_MASH(mash) ++ | BCM2708_CLK_SRC(clk_src)); ++ ++ /* Setup the frame format */ ++ format = BCM2708_I2S_CHEN; ++ ++ if (data_length > 24) ++ format |= BCM2708_I2S_CHWEX; ++ ++ format |= BCM2708_I2S_CHWID((data_length-8)&0xf); ++ ++ switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { ++ case SND_SOC_DAIFMT_I2S: ++ data_delay = 1; ++ break; ++ default: ++ /* ++ * TODO ++ * Others are possible but are not implemented at the moment. ++ */ ++ dev_err(dev->dev, "%s:bad format\n", __func__); ++ return -EINVAL; ++ } ++ ++ ch1pos = data_delay; ++ ch2pos = bclk_ratio / 2 + data_delay; ++ ++ switch (params_channels(params)) { ++ case 2: ++ format = BCM2708_I2S_CH1(format) | BCM2708_I2S_CH2(format); ++ format |= BCM2708_I2S_CH1(BCM2708_I2S_CHPOS(ch1pos)); ++ format |= BCM2708_I2S_CH2(BCM2708_I2S_CHPOS(ch2pos)); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ /* ++ * Set format for both streams. ++ * We cannot set another frame length ++ * (and therefore word length) anyway, ++ * so the format will be the same. ++ */ ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_RXC_A_REG, format); ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_TXC_A_REG, format); ++ ++ /* Setup the I2S mode */ ++ mode = 0; ++ ++ if (data_length <= 16) { ++ /* ++ * Use frame packed mode (2 channels per 32 bit word) ++ * We cannot set another frame length in the second stream ++ * (and therefore word length) anyway, ++ * so the format will be the same. ++ */ ++ mode |= BCM2708_I2S_FTXP | BCM2708_I2S_FRXP; ++ } ++ ++ mode |= BCM2708_I2S_FLEN(bclk_ratio - 1); ++ mode |= BCM2708_I2S_FSLEN(bclk_ratio / 2); ++ ++ /* Master or slave? */ ++ switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { ++ case SND_SOC_DAIFMT_CBS_CFS: ++ /* CPU is master */ ++ break; ++ case SND_SOC_DAIFMT_CBM_CFS: ++ /* ++ * CODEC is bit clock master ++ * CPU is frame master ++ */ ++ mode |= BCM2708_I2S_CLKM; ++ break; ++ case SND_SOC_DAIFMT_CBS_CFM: ++ /* ++ * CODEC is frame master ++ * CPU is bit clock master ++ */ ++ mode |= BCM2708_I2S_FSM; ++ break; ++ case SND_SOC_DAIFMT_CBM_CFM: ++ /* CODEC is master */ ++ mode |= BCM2708_I2S_CLKM; ++ mode |= BCM2708_I2S_FSM; ++ break; ++ default: ++ dev_err(dev->dev, "%s:bad master\n", __func__); ++ return -EINVAL; ++ } ++ ++ /* ++ * Invert clocks? ++ * ++ * The BCM approach seems to be inverted to the classical I2S approach. ++ */ ++ switch (dev->fmt & SND_SOC_DAIFMT_INV_MASK) { ++ case SND_SOC_DAIFMT_NB_NF: ++ /* None. Therefore, both for BCM */ ++ mode |= BCM2708_I2S_CLKI; ++ mode |= BCM2708_I2S_FSI; ++ break; ++ case SND_SOC_DAIFMT_IB_IF: ++ /* Both. Therefore, none for BCM */ ++ break; ++ case SND_SOC_DAIFMT_NB_IF: ++ /* ++ * Invert only frame sync. Therefore, ++ * invert only bit clock for BCM ++ */ ++ mode |= BCM2708_I2S_CLKI; ++ break; ++ case SND_SOC_DAIFMT_IB_NF: ++ /* ++ * Invert only bit clock. Therefore, ++ * invert only frame sync for BCM ++ */ ++ mode |= BCM2708_I2S_FSI; ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ regmap_write(dev->i2s_regmap, BCM2708_I2S_MODE_A_REG, mode); ++ ++ /* Setup the DMA parameters */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_RXTHR(1) ++ | BCM2708_I2S_TXTHR(1) ++ | BCM2708_I2S_DMAEN, 0xffffffff); ++ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_DREQ_A_REG, ++ BCM2708_I2S_TX_PANIC(0x10) ++ | BCM2708_I2S_RX_PANIC(0x30) ++ | BCM2708_I2S_TX(0x30) ++ | BCM2708_I2S_RX(0x20), 0xffffffff); ++ ++ /* Clear FIFOs */ ++ bcm2708_i2s_clear_fifos(dev, true, true); ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_prepare(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ uint32_t cs_reg; ++ ++ bcm2708_i2s_start_clock(dev); ++ ++ /* ++ * Clear both FIFOs if the one that should be started ++ * is not empty at the moment. This should only happen ++ * after overrun. Otherwise, hw_params would have cleared ++ * the FIFO. ++ */ ++ regmap_read(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, &cs_reg); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ++ && !(cs_reg & BCM2708_I2S_TXE)) ++ bcm2708_i2s_clear_fifos(dev, true, false); ++ else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE ++ && (cs_reg & BCM2708_I2S_RXD)) ++ bcm2708_i2s_clear_fifos(dev, false, true); ++ ++ return 0; ++} ++ ++static void bcm2708_i2s_stop(struct bcm2708_i2s_dev *dev, ++ struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ uint32_t mask; ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ mask = BCM2708_I2S_RXON; ++ else ++ mask = BCM2708_I2S_TXON; ++ ++ regmap_update_bits(dev->i2s_regmap, ++ BCM2708_I2S_CS_A_REG, mask, 0); ++ ++ /* Stop also the clock when not SND_SOC_DAIFMT_CONT */ ++ if (!dai->active && !(dev->fmt & SND_SOC_DAIFMT_CONT)) ++ bcm2708_i2s_stop_clock(dev); ++} ++ ++static int bcm2708_i2s_trigger(struct snd_pcm_substream *substream, int cmd, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ uint32_t mask; ++ ++ switch (cmd) { ++ case SNDRV_PCM_TRIGGER_START: ++ case SNDRV_PCM_TRIGGER_RESUME: ++ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: ++ bcm2708_i2s_start_clock(dev); ++ ++ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ++ mask = BCM2708_I2S_RXON; ++ else ++ mask = BCM2708_I2S_TXON; ++ ++ regmap_update_bits(dev->i2s_regmap, ++ BCM2708_I2S_CS_A_REG, mask, mask); ++ break; ++ ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ bcm2708_i2s_stop(dev, substream, dai); ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_startup(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ if (dai->active) ++ return 0; ++ ++ /* Should this still be running stop it */ ++ bcm2708_i2s_stop_clock(dev); ++ ++ /* Enable PCM block */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_EN, BCM2708_I2S_EN); ++ ++ /* ++ * Disable STBY. ++ * Requires at least 4 PCM clock cycles to take effect. ++ */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_STBY, BCM2708_I2S_STBY); ++ ++ return 0; ++} ++ ++static void bcm2708_i2s_shutdown(struct snd_pcm_substream *substream, ++ struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ bcm2708_i2s_stop(dev, substream, dai); ++ ++ /* If both streams are stopped, disable module and clock */ ++ if (dai->active) ++ return; ++ ++ /* Disable the module */ ++ regmap_update_bits(dev->i2s_regmap, BCM2708_I2S_CS_A_REG, ++ BCM2708_I2S_EN, 0); ++ ++ /* ++ * Stopping clock is necessary, because stop does ++ * not stop the clock when SND_SOC_DAIFMT_CONT ++ */ ++ bcm2708_i2s_stop_clock(dev); ++} ++ ++static const struct snd_soc_dai_ops bcm2708_i2s_dai_ops = { ++ .startup = bcm2708_i2s_startup, ++ .shutdown = bcm2708_i2s_shutdown, ++ .prepare = bcm2708_i2s_prepare, ++ .trigger = bcm2708_i2s_trigger, ++ .hw_params = bcm2708_i2s_hw_params, ++ .set_fmt = bcm2708_i2s_set_dai_fmt, ++ .set_bclk_ratio = bcm2708_i2s_set_dai_bclk_ratio ++}; ++ ++static int bcm2708_i2s_dai_probe(struct snd_soc_dai *dai) ++{ ++ struct bcm2708_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); ++ ++ dai->playback_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK]; ++ dai->capture_dma_data = &dev->dma_data[SNDRV_PCM_STREAM_CAPTURE]; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_driver bcm2708_i2s_dai = { ++ .name = "bcm2708-i2s", ++ .probe = bcm2708_i2s_dai_probe, ++ .playback = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE ++ | SNDRV_PCM_FMTBIT_S32_LE ++ }, ++ .capture = { ++ .channels_min = 2, ++ .channels_max = 2, ++ .rates = SNDRV_PCM_RATE_8000_192000, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE ++ | SNDRV_PCM_FMTBIT_S32_LE ++ }, ++ .ops = &bcm2708_i2s_dai_ops, ++ .symmetric_rates = 1 ++}; ++ ++static bool bcm2708_i2s_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_I2S_CS_A_REG: ++ case BCM2708_I2S_FIFO_A_REG: ++ case BCM2708_I2S_INTSTC_A_REG: ++ case BCM2708_I2S_GRAY_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static bool bcm2708_i2s_precious_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_I2S_FIFO_A_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static bool bcm2708_clk_volatile_reg(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case BCM2708_CLK_PCMCTL_REG: ++ return true; ++ default: ++ return false; ++ }; ++} ++ ++static const struct regmap_config bcm2708_regmap_config[] = { ++ { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = BCM2708_I2S_GRAY_REG, ++ .precious_reg = bcm2708_i2s_precious_reg, ++ .volatile_reg = bcm2708_i2s_volatile_reg, ++ .cache_type = REGCACHE_RBTREE, ++ }, ++ { ++ .reg_bits = 32, ++ .reg_stride = 4, ++ .val_bits = 32, ++ .max_register = BCM2708_CLK_PCMDIV_REG, ++ .volatile_reg = bcm2708_clk_volatile_reg, ++ .cache_type = REGCACHE_RBTREE, ++ }, ++}; ++ ++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_MMAP | ++ SNDRV_PCM_INFO_MMAP_VALID | ++ SNDRV_PCM_INFO_INTERLEAVED | ++ SNDRV_PCM_INFO_JOINT_DUPLEX, ++ .formats = SNDRV_PCM_FMTBIT_S16_LE | ++ SNDRV_PCM_FMTBIT_S32_LE, ++ .period_bytes_min = 32, ++ .period_bytes_max = 64 * PAGE_SIZE, ++ .periods_min = 2, ++ .periods_max = 255, ++ .buffer_bytes_max = 128 * PAGE_SIZE, ++}; ++ ++static const struct snd_dmaengine_pcm_config bcm2708_dmaengine_pcm_config = { ++ .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, ++ .pcm_hardware = &bcm2708_pcm_hardware, ++ .prealloc_buffer_size = 256 * PAGE_SIZE, ++}; ++ ++ ++static int bcm2708_i2s_probe(struct platform_device *pdev) ++{ ++ struct bcm2708_i2s_dev *dev; ++ int i; ++ int ret; ++ struct regmap *regmap[2]; ++ struct resource *mem[2]; ++ ++ /* Request both ioareas */ ++ for (i = 0; i <= 1; i++) { ++ void __iomem *base; ++ ++ mem[i] = platform_get_resource(pdev, IORESOURCE_MEM, i); ++ base = devm_ioremap_resource(&pdev->dev, mem[i]); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ regmap[i] = devm_regmap_init_mmio(&pdev->dev, base, ++ &bcm2708_regmap_config[i]); ++ if (IS_ERR(regmap[i])) { ++ dev_err(&pdev->dev, "I2S probe: regmap init failed\n"); ++ return PTR_ERR(regmap[i]); ++ } ++ } ++ ++ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), ++ GFP_KERNEL); ++ if (IS_ERR(dev)) ++ return PTR_ERR(dev); ++ ++ bcm2708_i2s_setup_gpio(); ++ ++ dev->i2s_regmap = regmap[0]; ++ dev->clk_regmap = regmap[1]; ++ ++ /* Set the DMA address */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = ++ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; ++ ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = ++ (dma_addr_t)BCM2708_I2S_FIFO_PHYSICAL_ADDR; ++ ++ /* Set the DREQ */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].slave_id = ++ BCM2708_DMA_DREQ_PCM_TX; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].slave_id = ++ BCM2708_DMA_DREQ_PCM_RX; ++ ++ /* Set the bus width */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width = ++ DMA_SLAVE_BUSWIDTH_4_BYTES; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr_width = ++ DMA_SLAVE_BUSWIDTH_4_BYTES; ++ ++ /* Set burst */ ++ dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].maxburst = 2; ++ dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].maxburst = 2; ++ ++ /* BCLK ratio - use default */ ++ dev->bclk_ratio = 0; ++ ++ /* Store the pdev */ ++ dev->dev = &pdev->dev; ++ dev_set_drvdata(&pdev->dev, dev); ++ ++ ret = snd_soc_register_component(&pdev->dev, ++ &bcm2708_i2s_component, &bcm2708_i2s_dai, 1); ++ ++ if (ret) { ++ dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ++ ret = -ENOMEM; ++ return ret; ++ } ++ ++ ret = snd_dmaengine_pcm_register(&pdev->dev, ++ &bcm2708_dmaengine_pcm_config, ++ SND_DMAENGINE_PCM_FLAG_COMPAT); ++ if (ret) { ++ dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); ++ snd_soc_unregister_component(&pdev->dev); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int bcm2708_i2s_remove(struct platform_device *pdev) ++{ ++ snd_dmaengine_pcm_unregister(&pdev->dev); ++ snd_soc_unregister_component(&pdev->dev); ++ return 0; ++} ++ ++static struct platform_driver bcm2708_i2s_driver = { ++ .probe = bcm2708_i2s_probe, ++ .remove = bcm2708_i2s_remove, ++ .driver = { ++ .name = "bcm2708-i2s", ++ .owner = THIS_MODULE, ++ }, ++}; ++ ++module_platform_driver(bcm2708_i2s_driver); ++ ++MODULE_ALIAS("platform:bcm2708-i2s"); ++MODULE_DESCRIPTION("BCM2708 I2S interface"); ++MODULE_AUTHOR("Florian Meier "); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From ad419b8ec1740e861ed3ef407b73ba1d5f6ecfbf Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 14:37:51 +0100 +Subject: [PATCH 82/99] BCM2708: Extend mach header + +Extend the headers of the mach-bcm2708 +in order to support I2S and DMA engine. + +Signed-off-by: Florian Meier +--- + 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.8.5.5 + + +From dc793b88e6e5c02e8beb481f9d3e2bd6fc5fdcce Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 14:59:51 +0100 +Subject: [PATCH 83/99] ASoC: Add support for PCM5102A codec + +Some definitions to support the PCM5102A codec +by Texas Instruments. + +Signed-off-by: Florian Meier +--- + 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 ++ * 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 ++#include ++#include ++ ++#include ++ ++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 "); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From f68e4706c0e75d01adaab54805f3036b3611d1e9 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 19:04:54 +0100 +Subject: [PATCH 84/99] 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 +--- + 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 91c008f..6117a4b 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -606,6 +606,28 @@ struct platform_device bcm2708_powerman_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; +@@ -728,6 +750,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.8.5.5 + + +From 993c59574b9a17f08d52abfc8783b0011368f9b8 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 19:19:08 +0100 +Subject: [PATCH 85/99] 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 +--- + 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 ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++MODULE_DESCRIPTION("ASoC Driver for HifiBerry DAC"); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From 1df3a9bdd13d77e065a7bfc7bc3b144f8ff0f264 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 22 Nov 2013 19:21:34 +0100 +Subject: [PATCH 86/99] 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 +--- + 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 6117a4b..5056993 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -628,6 +628,20 @@ struct platform_device bcm2708_powerman_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; +@@ -754,6 +768,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.8.5.5 + + +From fc707e469b114d7118e6e7d68c80d8ab1fae2349 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 6 Dec 2013 18:55:53 +0100 +Subject: [PATCH 87/99] 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 +--- + 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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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.8.5.5 + + +From 3f6defbf3bb80fd122390a84c85ec22d667e5ed9 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Mon, 2 Dec 2013 20:28:22 +0100 +Subject: [PATCH 88/99] 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 +--- + 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 1041f5e..0360c86 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -738,6 +738,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 +@@ -925,6 +932,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.8.5.5 + + +From d741f8dc1b2a9360874d006ef2241a835a1ff3b0 Mon Sep 17 00:00:00 2001 +From: Florian Meier +Date: Fri, 6 Dec 2013 20:50:28 +0100 +Subject: [PATCH 89/99] ASoC: BCM2708: Add support for RPi-DAC + +This adds a machine driver for the RPi-DAC. + +Signed-off-by: Florian Meier +--- + 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 0360c86..524ad3e 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -743,8 +743,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 5056993..b6348c9 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -642,6 +642,20 @@ struct platform_device bcm2708_powerman_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; +@@ -773,6 +787,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 ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++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 "); ++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 ++ * 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 ++#include ++#include ++ ++#include ++ ++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 "); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From 846c793898454d0ca138ef430bbbce78ba3a8bea Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Wed, 15 Jan 2014 21:41:23 +0100 +Subject: [PATCH 90/99] 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 +--- + 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 @@ struct pll_div { + + #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 int wm8804_probe(struct snd_soc_codec *codec) + }; + + #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.8.5.5 + + +From e7aa74134a9db80e57c35f7ce9613ebf405ae76e Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Wed, 15 Jan 2014 21:42:08 +0100 +Subject: [PATCH 91/99] ASoC: BCM:Add support for HiFiBerry Digi. Driver is + based on the patched WM8804 driver. + +Signed-off-by: Daniel Matuschek +--- + 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 ++ * based on the HifiBerry DAC driver by Florian Meier ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#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 "); ++MODULE_DESCRIPTION("ASoC Driver for HifiBerry Digi"); ++MODULE_LICENSE("GPL v2"); +-- +1.8.5.5 + + +From 541fe8734b48bc92ec4d6f9b47047a09fd332419 Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Thu, 16 Jan 2014 07:26:08 +0100 +Subject: [PATCH 92/99] BCM2708: Added support for HiFiBerry Digi board Board + initalization by I2C + +Signed-off-by: Daniel Matuschek +--- + 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 b6348c9..b5a41c9 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -642,6 +642,21 @@ struct platform_device bcm2708_powerman_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", +@@ -787,6 +802,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.8.5.5 + + +From 347c1db0f704e29d6e826470e93bb01961245f1b Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Thu, 16 Jan 2014 07:27:28 +0100 +Subject: [PATCH 93/99] 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 +--- + 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 524ad3e..cefbb24 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -741,8 +741,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.8.5.5 + + +From 15fb9ee32a161f7a762b8a03c08c43fc9c053c3c Mon Sep 17 00:00:00 2001 +From: Daniel Matuschek +Date: Thu, 16 Jan 2014 07:36:35 +0100 +Subject: [PATCH 94/99] ASoC: wm8804: Set idle_bias_off to false Idle bias has + been change to remove warning on driver startup + +Signed-off-by: Daniel Matuschek +--- + 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 int wm8804_probe(struct snd_soc_codec *codec) + .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.8.5.5 + + +From 373d6a336f4ef61f9d30c43bfb3829edb0821519 Mon Sep 17 00:00:00 2001 +From: popcornmix +Date: Wed, 12 Mar 2014 11:46:34 +0000 +Subject: [PATCH 95/99] 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 int bcm2708_i2s_dai_probe(struct snd_soc_dai *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 @@ + .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.8.5.5 + + +From 7aa79bd4be182c96a9a099e4d72c75d9664d99be Mon Sep 17 00:00:00 2001 +From: Gordon Garrity +Date: Sat, 8 Mar 2014 16:56:57 +0000 +Subject: [PATCH 96/99] Add IQaudIO Sound Card support for Raspberry Pi + +--- + arch/arm/configs/bcmrpi_defconfig | 1 + + arch/arm/mach-bcm2708/bcm2708.c | 22 ++ + sound/soc/bcm/Kconfig | 7 + + sound/soc/bcm/Makefile | 2 + + sound/soc/bcm/iqaudio-dac.c | 111 +++++++ + sound/soc/codecs/Kconfig | 4 + + sound/soc/codecs/Makefile | 2 + + sound/soc/codecs/pcm512x.c | 677 ++++++++++++++++++++++++++++++++++++++ + sound/soc/codecs/pcm512x.h | 142 ++++++++ + 9 files changed, 968 insertions(+) + create mode 100644 sound/soc/bcm/iqaudio-dac.c + create mode 100644 sound/soc/codecs/pcm512x.c + create mode 100644 sound/soc/codecs/pcm512x.h + +diff --git a/arch/arm/configs/bcmrpi_defconfig b/arch/arm/configs/bcmrpi_defconfig +index cefbb24..4407a5d 100644 +--- a/arch/arm/configs/bcmrpi_defconfig ++++ b/arch/arm/configs/bcmrpi_defconfig +@@ -749,6 +749,7 @@ 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_SND_BCM2708_SOC_IQAUDIO_DAC=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 b5a41c9..887f732 100644 +--- a/arch/arm/mach-bcm2708/bcm2708.c ++++ b/arch/arm/mach-bcm2708/bcm2708.c +@@ -671,6 +671,22 @@ struct platform_device bcm2708_powerman_device = { + }; + #endif + ++ ++#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) ++static struct platform_device snd_rpi_iqaudio_dac_device = { ++ .name = "snd-rpi-iqaudio-dac", ++ .id = 0, ++ .num_resources = 0, ++}; ++ ++// Use the actual device name rather than generic driver name ++static struct i2c_board_info __initdata snd_pcm512x_i2c_devices[] = { ++ { ++ I2C_BOARD_INFO("pcm5122", 0x4c) ++ }, ++}; ++#endif ++ + int __init bcm_register_device(struct platform_device *pdev) + { + int ret; +@@ -812,6 +828,12 @@ void __init bcm2708_init(void) + bcm_register_device(&snd_pcm1794a_codec_device); + #endif + ++#if defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) || defined(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC_MODULE) ++ bcm_register_device(&snd_rpi_iqaudio_dac_device); ++ i2c_register_board_info(1, snd_pcm512x_i2c_devices, ARRAY_SIZE(snd_pcm512x_i2c_devices)); ++#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 e563dbc..84e4f27 100644 +--- a/sound/soc/bcm/Kconfig ++++ b/sound/soc/bcm/Kconfig +@@ -39,3 +39,10 @@ config SND_BCM2708_SOC_RPI_DAC + select SND_SOC_PCM1794A + help + Say Y or M if you want to add support for RPi-DAC. ++ ++config SND_BCM2708_SOC_IQAUDIO_DAC ++ tristate "Support for IQaudIO-DAC" ++ depends on SND_BCM2708_SOC_I2S ++ select SND_SOC_PCM512x ++ help ++ Say Y or M if you want to add support for IQaudIO-DAC. +diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile +index 826df7d..d597fb0 100644 +--- a/sound/soc/bcm/Makefile ++++ b/sound/soc/bcm/Makefile +@@ -12,7 +12,9 @@ obj-$(CONFIG_SND_BCM2708_SOC_I2S) += snd-soc-bcm2708-i2s.o + snd-soc-hifiberry-dac-objs := hifiberry_dac.o + snd-soc-hifiberry-digi-objs := hifiberry_digi.o + snd-soc-rpi-dac-objs := rpi-dac.o ++snd-soc-iqaudio-dac-objs := iqaudio-dac.o + + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DIGI) += snd-soc-hifiberry-digi.o + obj-$(CONFIG_SND_BCM2708_SOC_RPI_DAC) += snd-soc-rpi-dac.o ++obj-$(CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC) += snd-soc-iqaudio-dac.o +diff --git a/sound/soc/bcm/iqaudio-dac.c b/sound/soc/bcm/iqaudio-dac.c +new file mode 100644 +index 0000000..515f044 +--- /dev/null ++++ b/sound/soc/bcm/iqaudio-dac.c +@@ -0,0 +1,111 @@ ++/* ++ * ASoC Driver for IQaudIO DAC ++ * ++ * Author: Florian Meier ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++static int snd_rpi_iqaudio_dac_init(struct snd_soc_pcm_runtime *rtd) ++{ ++// NOT USED struct snd_soc_codec *codec = rtd->codec; ++ ++ return 0; ++} ++ ++static int snd_rpi_iqaudio_dac_hw_params(struct snd_pcm_substream *substream, ++ struct snd_pcm_hw_params *params) ++{ ++ struct snd_soc_pcm_runtime *rtd = substream->private_data; ++// NOT USED struct snd_soc_dai *codec_dai = rtd->codec_dai; ++// NOT USED struct snd_soc_codec *codec = rtd->codec; ++ struct snd_soc_dai *cpu_dai = rtd->cpu_dai; ++ ++ unsigned int sample_bits = ++ snd_pcm_format_physical_width(params_format(params)); ++ ++ return snd_soc_dai_set_bclk_ratio(cpu_dai, sample_bits * 2); ++} ++ ++/* machine stream operations */ ++static struct snd_soc_ops snd_rpi_iqaudio_dac_ops = { ++ .hw_params = snd_rpi_iqaudio_dac_hw_params, ++}; ++ ++static struct snd_soc_dai_link snd_rpi_iqaudio_dac_dai[] = { ++{ ++ .name = "IQaudIO DAC", ++ .stream_name = "IQaudIO DAC HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "pcm512x-hifi", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "pcm512x.1-004c", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBS_CFS, ++ .ops = &snd_rpi_iqaudio_dac_ops, ++ .init = snd_rpi_iqaudio_dac_init, ++}, ++}; ++ ++/* audio machine driver */ ++static struct snd_soc_card snd_rpi_iqaudio_dac = { ++ .name = "snd_rpi_iqaudio_dac", ++ .dai_link = snd_rpi_iqaudio_dac_dai, ++ .num_links = ARRAY_SIZE(snd_rpi_iqaudio_dac_dai), ++}; ++ ++static int snd_rpi_iqaudio_dac_probe(struct platform_device *pdev) ++{ ++ int ret = 0; ++ ++ snd_rpi_iqaudio_dac.dev = &pdev->dev; ++ ret = snd_soc_register_card(&snd_rpi_iqaudio_dac); ++ if (ret) ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ ++ return ret; ++} ++ ++static int snd_rpi_iqaudio_dac_remove(struct platform_device *pdev) ++{ ++ return snd_soc_unregister_card(&snd_rpi_iqaudio_dac); ++} ++ ++static const struct of_device_id iqaudio_of_match[] = { ++ { .compatible = "iqaudio,iqaudio-dac", }, ++ {}, ++}; ++ ++static struct platform_driver snd_rpi_iqaudio_dac_driver = { ++ .driver = { ++ .name = "snd-rpi-iqaudio-dac", ++ .owner = THIS_MODULE, ++ .of_match_table = iqaudio_of_match, ++ }, ++ .probe = snd_rpi_iqaudio_dac_probe, ++ .remove = snd_rpi_iqaudio_dac_remove, ++}; ++ ++module_platform_driver(snd_rpi_iqaudio_dac_driver); ++ ++MODULE_AUTHOR("Florian Meier "); ++MODULE_DESCRIPTION("ASoC Driver for IQAudio DAC"); ++MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig +index 4d2569e..ac28805 100644 +--- a/sound/soc/codecs/Kconfig ++++ b/sound/soc/codecs/Kconfig +@@ -61,6 +61,7 @@ config SND_SOC_ALL_CODECS + select SND_SOC_PCM3008 + select SND_SOC_PCM1794A + select SND_SOC_PCM5102A ++ select SND_SOC_PCM512x if SND_SOC_I2C_AND_SPI + select SND_SOC_RT5631 if I2C + select SND_SOC_RT5640 if I2C + select SND_SOC_SGTL5000 if I2C +@@ -321,6 +322,9 @@ config SND_SOC_PCM1794A + config SND_SOC_PCM5102A + tristate + ++config SND_SOC_PCM512x ++ tristate ++ + config SND_SOC_RT5631 + tristate + +diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile +index 9b806a2..61461c1 100644 +--- a/sound/soc/codecs/Makefile ++++ b/sound/soc/codecs/Makefile +@@ -48,6 +48,7 @@ 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-pcm512x-objs := pcm512x.o + snd-soc-rt5631-objs := rt5631.o + snd-soc-rt5640-objs := rt5640.o + snd-soc-sgtl5000-objs := sgtl5000.o +@@ -183,6 +184,7 @@ 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_PCM512x) += snd-soc-pcm512x.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/pcm512x.c b/sound/soc/codecs/pcm512x.c +new file mode 100644 +index 0000000..55b6200 +--- /dev/null ++++ b/sound/soc/codecs/pcm512x.c +@@ -0,0 +1,677 @@ ++/* ++ * Driver for the PCM512x CODECs ++ * ++ * Author: Mark Brown ++ * Copyright 2014 Linaro Ltd ++ * ++ * 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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "pcm512x.h" ++ ++#define PCM512x_NUM_SUPPLIES 3 ++static const char *pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { ++ "AVDD", ++ "DVDD", ++ "CPVDD", ++}; ++ ++struct pcm512x_priv { ++ struct regmap *regmap; ++ struct clk *sclk; ++ struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; ++ struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; ++}; ++ ++/* ++ * We can't use the same notifier block for more than one supply and ++ * there's no way I can see to get from a callback to the caller ++ * except container_of(). ++ */ ++#define PCM512x_REGULATOR_EVENT(n) \ ++static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ ++ unsigned long event, void *data) \ ++{ \ ++ struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ ++ supply_nb[n]); \ ++ if (event & REGULATOR_EVENT_DISABLE) { \ ++ regcache_mark_dirty(pcm512x->regmap); \ ++ regcache_cache_only(pcm512x->regmap, true); \ ++ } \ ++ return 0; \ ++} ++ ++PCM512x_REGULATOR_EVENT(0) ++PCM512x_REGULATOR_EVENT(1) ++PCM512x_REGULATOR_EVENT(2) ++ ++static const struct reg_default pcm512x_reg_defaults[] = { ++ { PCM512x_RESET, 0x00 }, ++ { PCM512x_POWER, 0x00 }, ++ { PCM512x_MUTE, 0x00 }, ++ { PCM512x_DSP, 0x00 }, ++ { PCM512x_PLL_REF, 0x00 }, ++ { PCM512x_DAC_ROUTING, 0x11 }, ++ { PCM512x_DSP_PROGRAM, 0x01 }, ++ { PCM512x_CLKDET, 0x00 }, ++ { PCM512x_AUTO_MUTE, 0x00 }, ++ { PCM512x_ERROR_DETECT, 0x00 }, ++ { PCM512x_DIGITAL_VOLUME_1, 0x00 }, ++ { PCM512x_DIGITAL_VOLUME_2, 0x30 }, ++ { PCM512x_DIGITAL_VOLUME_3, 0x30 }, ++ { PCM512x_DIGITAL_MUTE_1, 0x22 }, ++ { PCM512x_DIGITAL_MUTE_2, 0x00 }, ++ { PCM512x_DIGITAL_MUTE_3, 0x07 }, ++}; ++ ++static bool pcm512x_readable(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case PCM512x_RESET: ++ case PCM512x_POWER: ++ case PCM512x_MUTE: ++ case PCM512x_PLL_EN: ++ case PCM512x_SPI_MISO_FUNCTION: ++ case PCM512x_DSP: ++ case PCM512x_GPIO_EN: ++ case PCM512x_BCLK_LRCLK_CFG: ++ case PCM512x_DSP_GPIO_INPUT: ++ case PCM512x_MASTER_MODE: ++ case PCM512x_PLL_REF: ++ case PCM512x_PLL_COEFF_0: ++ case PCM512x_PLL_COEFF_1: ++ case PCM512x_PLL_COEFF_2: ++ case PCM512x_PLL_COEFF_3: ++ case PCM512x_PLL_COEFF_4: ++ case PCM512x_DSP_CLKDIV: ++ case PCM512x_DAC_CLKDIV: ++ case PCM512x_NCP_CLKDIV: ++ case PCM512x_OSR_CLKDIV: ++ case PCM512x_MASTER_CLKDIV_1: ++ case PCM512x_MASTER_CLKDIV_2: ++ case PCM512x_FS_SPEED_MODE: ++ case PCM512x_IDAC_1: ++ case PCM512x_IDAC_2: ++ case PCM512x_ERROR_DETECT: ++ case PCM512x_I2S_1: ++ case PCM512x_I2S_2: ++ case PCM512x_DAC_ROUTING: ++ case PCM512x_DSP_PROGRAM: ++ case PCM512x_CLKDET: ++ case PCM512x_AUTO_MUTE: ++ case PCM512x_DIGITAL_VOLUME_1: ++ case PCM512x_DIGITAL_VOLUME_2: ++ case PCM512x_DIGITAL_VOLUME_3: ++ case PCM512x_DIGITAL_MUTE_1: ++ case PCM512x_DIGITAL_MUTE_2: ++ case PCM512x_DIGITAL_MUTE_3: ++ case PCM512x_GPIO_OUTPUT_1: ++ case PCM512x_GPIO_OUTPUT_2: ++ case PCM512x_GPIO_OUTPUT_3: ++ case PCM512x_GPIO_OUTPUT_4: ++ case PCM512x_GPIO_OUTPUT_5: ++ case PCM512x_GPIO_OUTPUT_6: ++ case PCM512x_GPIO_CONTROL_1: ++ case PCM512x_GPIO_CONTROL_2: ++ case PCM512x_OVERFLOW: ++ case PCM512x_RATE_DET_1: ++ case PCM512x_RATE_DET_2: ++ case PCM512x_RATE_DET_3: ++ case PCM512x_RATE_DET_4: ++ case PCM512x_ANALOG_MUTE_DET: ++ case PCM512x_GPIN: ++ case PCM512x_DIGITAL_MUTE_DET: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static bool pcm512x_volatile(struct device *dev, unsigned int reg) ++{ ++ switch (reg) { ++ case PCM512x_PLL_EN: ++ case PCM512x_OVERFLOW: ++ case PCM512x_RATE_DET_1: ++ case PCM512x_RATE_DET_2: ++ case PCM512x_RATE_DET_3: ++ case PCM512x_RATE_DET_4: ++ case PCM512x_ANALOG_MUTE_DET: ++ case PCM512x_GPIN: ++ case PCM512x_DIGITAL_MUTE_DET: ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); ++ ++static const char *pcm512x_dsp_program_texts[] = { ++ "FIR interpolation with de-emphasis", ++ "Low latency IIR with de-emphasis", ++ "High attenuation with de-emphasis", ++ "Ringing-less low latency FIR", ++}; ++ ++static const unsigned int pcm512x_dsp_program_values[] = { ++ 1, ++ 2, ++ 3, ++ 5, ++ 7, ++}; ++ ++static const SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, ++ PCM512x_DSP_PROGRAM, 0, 0x1f, ++ pcm512x_dsp_program_texts, ++ pcm512x_dsp_program_values); ++ ++static const char *pcm512x_clk_missing_text[] = { ++ "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" ++}; ++ ++static const struct soc_enum pcm512x_clk_missing = ++ SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 7, pcm512x_clk_missing_text); ++ ++static const char *pcm512x_autom_text[] = { ++ "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" ++}; ++ ++static const struct soc_enum pcm512x_autom_l = ++ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 7, ++ pcm512x_autom_text); ++ ++static const struct soc_enum pcm512x_autom_r = ++ SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 7, ++ pcm512x_autom_text); ++ ++static const char *pcm512x_ramp_rate_text[] = { ++ "1 sample/update", "2 samples/update", "4 samples/update", ++ "Immediate" ++}; ++ ++static const struct soc_enum pcm512x_vndf = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, ++ pcm512x_ramp_rate_text); ++ ++static const struct soc_enum pcm512x_vnuf = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, ++ pcm512x_ramp_rate_text); ++ ++static const struct soc_enum pcm512x_vedf = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, ++ pcm512x_ramp_rate_text); ++ ++static const char *pcm512x_ramp_step_text[] = { ++ "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" ++}; ++ ++static const struct soc_enum pcm512x_vnds = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, ++ pcm512x_ramp_step_text); ++ ++static const struct soc_enum pcm512x_vnus = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, ++ pcm512x_ramp_step_text); ++ ++static const struct soc_enum pcm512x_veds = ++ SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, ++ 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("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, ++ PCM512x_RQMR_SHIFT, 1, 1), ++ ++SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), ++SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), ++ ++SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), ++SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), ++SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), ++SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, ++ PCM512x_ACTL_SHIFT, 1, 0), ++SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, ++ PCM512x_AMLR_SHIFT, 1, 0), ++ ++SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), ++SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), ++SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), ++SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), ++SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), ++SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), ++}; ++ ++static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { ++SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), ++SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), ++ ++SND_SOC_DAPM_OUTPUT("OUTL"), ++SND_SOC_DAPM_OUTPUT("OUTR"), ++}; ++ ++static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { ++ { "DACL", NULL, "Playback" }, ++ { "DACR", NULL, "Playback" }, ++ ++ { "OUTL", NULL, "DACL" }, ++ { "OUTR", NULL, "DACR" }, ++}; ++ ++static int pcm512x_set_bias_level(struct snd_soc_codec *codec, ++ enum snd_soc_bias_level level) ++{ ++ struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); ++ int ret; ++ ++ switch (level) { ++ case SND_SOC_BIAS_ON: ++ case SND_SOC_BIAS_PREPARE: ++ break; ++ ++ case SND_SOC_BIAS_STANDBY: ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, ++ PCM512x_RQST, 0); ++ if (ret != 0) { ++ dev_err(codec->dev, "Failed to remove standby: %d\n", ++ ret); ++ return ret; ++ } ++ break; ++ ++ case SND_SOC_BIAS_OFF: ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, ++ PCM512x_RQST, PCM512x_RQST); ++ if (ret != 0) { ++ dev_err(codec->dev, "Failed to request standby: %d\n", ++ ret); ++ return ret; ++ } ++ break; ++ } ++ ++ codec->dapm.bias_level = level; ++ ++ return 0; ++} ++ ++static struct snd_soc_dai_driver pcm512x_dai = { ++ .name = "pcm512x-hifi", ++ .playback = { ++ .stream_name = "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 pcm512x_codec_driver = { ++ .set_bias_level = pcm512x_set_bias_level, ++ .idle_bias_off = true, ++ ++ .controls = pcm512x_controls, ++ .num_controls = ARRAY_SIZE(pcm512x_controls), ++ .dapm_widgets = pcm512x_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), ++ .dapm_routes = pcm512x_dapm_routes, ++ .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), ++}; ++ ++static const struct regmap_config pcm512x_regmap = { ++ .reg_bits = 8, ++ .val_bits = 8, ++ ++ .readable_reg = pcm512x_readable, ++ .volatile_reg = pcm512x_volatile, ++ ++ .max_register = PCM512x_MAX_REGISTER, ++ .reg_defaults = pcm512x_reg_defaults, ++ .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), ++ .cache_type = REGCACHE_RBTREE, ++}; ++ ++static const struct of_device_id pcm512x_of_match[] = { ++ { .compatible = "ti,pcm5121", }, ++ { .compatible = "ti,pcm5122", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, pcm512x_of_match); ++ ++static int pcm512x_probe(struct device *dev, struct regmap *regmap) ++{ ++ struct pcm512x_priv *pcm512x; ++ int i, ret; ++ ++ pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); ++ if (!pcm512x) ++ return -ENOMEM; ++ ++ dev_set_drvdata(dev, pcm512x); ++ pcm512x->regmap = regmap; ++ ++ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) ++ pcm512x->supplies[i].supply = pcm512x_supply_names[i]; ++ ++ ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++ if (ret != 0) { ++ dev_err(dev, "Failed to get supplies: %d\n", ret); ++ return ret; ++ } ++ ++ pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; ++ pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; ++ pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; ++ ++ for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { ++ ret = regulator_register_notifier(pcm512x->supplies[i].consumer, ++ &pcm512x->supply_nb[i]); ++ if (ret != 0) { ++ dev_err(dev, ++ "Failed to register regulator notifier: %d\n", ++ ret); ++ } ++ } ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++ if (ret != 0) { ++ dev_err(dev, "Failed to enable supplies: %d\n", ret); ++ return ret; ++ } ++ ++ /* Reset the device, verifying I/O in the process for I2C */ ++ ret = regmap_write(regmap, PCM512x_RESET, ++ PCM512x_RSTM | PCM512x_RSTR); ++ if (ret != 0) { ++ dev_err(dev, "Failed to reset device: %d\n", ret); ++ goto err; ++ } ++ ++ ret = regmap_write(regmap, PCM512x_RESET, 0); ++ if (ret != 0) { ++ dev_err(dev, "Failed to reset device: %d\n", ret); ++ goto err; ++ } ++ ++ pcm512x->sclk = devm_clk_get(dev, NULL); ++ if (IS_ERR(pcm512x->sclk)) { ++ if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ ++ dev_info(dev, "No SCLK, using BCLK: %ld\n", ++ PTR_ERR(pcm512x->sclk)); ++ ++ /* Disable reporting of missing SCLK as an error */ ++ regmap_update_bits(regmap, PCM512x_ERROR_DETECT, ++ PCM512x_IDCH, PCM512x_IDCH); ++ ++ /* Switch PLL input to BCLK */ ++ regmap_update_bits(regmap, PCM512x_PLL_REF, ++ PCM512x_SREF, PCM512x_SREF); ++ } else { ++ ret = clk_prepare_enable(pcm512x->sclk); ++ if (ret != 0) { ++ dev_err(dev, "Failed to enable SCLK: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ /* Default to standby mode */ ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, ++ PCM512x_RQST, PCM512x_RQST); ++ if (ret != 0) { ++ dev_err(dev, "Failed to request standby: %d\n", ++ ret); ++ goto err_clk; ++ } ++ ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ pm_runtime_idle(dev); ++ ++ ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, ++ &pcm512x_dai, 1); ++ if (ret != 0) { ++ dev_err(dev, "Failed to register CODEC: %d\n", ret); ++ goto err_pm; ++ } ++ ++ dev_info(dev, "Completed initialisation - pcm512x_probe"); ++ ++ return 0; ++ ++err_pm: ++ pm_runtime_disable(dev); ++err_clk: ++ if (!IS_ERR(pcm512x->sclk)) ++ clk_disable_unprepare(pcm512x->sclk); ++err: ++ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++ return ret; ++} ++ ++static void pcm512x_remove(struct device *dev) ++{ ++ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); ++ ++ snd_soc_unregister_codec(dev); ++ pm_runtime_disable(dev); ++ if (!IS_ERR(pcm512x->sclk)) ++ clk_disable_unprepare(pcm512x->sclk); ++ regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++} ++ ++/* TODO ++static int pcm512x_suspend(struct device *dev) ++{ ++ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); ++ int ret; ++ ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, ++ PCM512x_RQPD, PCM512x_RQPD); ++ if (ret != 0) { ++ dev_err(dev, "Failed to request power down: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++ if (ret != 0) { ++ dev_err(dev, "Failed to disable supplies: %d\n", ret); ++ return ret; ++ } ++ ++ if (!IS_ERR(pcm512x->sclk)) ++ clk_disable_unprepare(pcm512x->sclk); ++ ++ return 0; ++} ++ ++static int pcm512x_resume(struct device *dev) ++{ ++ struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); ++ int ret; ++ ++ if (!IS_ERR(pcm512x->sclk)) { ++ ret = clk_prepare_enable(pcm512x->sclk); ++ if (ret != 0) { ++ dev_err(dev, "Failed to enable SCLK: %d\n", ret); ++ return ret; ++ } ++ } ++ ++ ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), ++ pcm512x->supplies); ++ if (ret != 0) { ++ dev_err(dev, "Failed to enable supplies: %d\n", ret); ++ return ret; ++ } ++ ++ regcache_cache_only(pcm512x->regmap, false); ++ ret = regcache_sync(pcm512x->regmap); ++ if (ret != 0) { ++ dev_err(dev, "Failed to sync cache: %d\n", ret); ++ return ret; ++ } ++ ++ ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, ++ PCM512x_RQPD, 0); ++ if (ret != 0) { ++ dev_err(dev, "Failed to remove power down: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++// END OF PCM512x_suspend and resume calls TODO ++*/ ++ ++static const struct dev_pm_ops pcm512x_pm_ops = { ++ SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) ++}; ++ ++#if IS_ENABLED(CONFIG_I2C) ++static int pcm512x_i2c_probe(struct i2c_client *i2c, ++ const struct i2c_device_id *id) ++{ ++ struct regmap *regmap; ++ ++ regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); ++ if (IS_ERR(regmap)) ++ return PTR_ERR(regmap); ++ ++ return pcm512x_probe(&i2c->dev, regmap); ++} ++ ++static int pcm512x_i2c_remove(struct i2c_client *i2c) ++{ ++ pcm512x_remove(&i2c->dev); ++ return 0; ++} ++ ++static const struct i2c_device_id pcm512x_i2c_id[] = { ++ { "pcm5121", }, ++ { "pcm5122", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); ++ ++static struct i2c_driver pcm512x_i2c_driver = { ++ .probe = pcm512x_i2c_probe, ++ .remove = pcm512x_i2c_remove, ++ .id_table = pcm512x_i2c_id, ++ .driver = { ++ .name = "pcm512x", ++ .owner = THIS_MODULE, ++ .of_match_table = pcm512x_of_match, ++ .pm = &pcm512x_pm_ops, ++ }, ++}; ++#endif ++ ++#if defined(CONFIG_SPI_MASTER) ++static int pcm512x_spi_probe(struct spi_device *spi) ++{ ++ struct regmap *regmap; ++ int ret; ++ ++ regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); ++ if (IS_ERR(regmap)) { ++ ret = PTR_ERR(regmap); ++ return ret; ++ } ++ ++ return pcm512x_probe(&spi->dev, regmap); ++} ++ ++static int pcm512x_spi_remove(struct spi_device *spi) ++{ ++ pcm512x_remove(&spi->dev); ++ return 0; ++} ++ ++static const struct spi_device_id pcm512x_spi_id[] = { ++ { "pcm5121", }, ++ { "pcm5122", }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); ++ ++static struct spi_driver pcm512x_spi_driver = { ++ .probe = pcm512x_spi_probe, ++ .remove = pcm512x_spi_remove, ++ .id_table = pcm512x_spi_id, ++ .driver = { ++ .name = "pcm512x", ++ .owner = THIS_MODULE, ++ .of_match_table = pcm512x_of_match, ++ .pm = &pcm512x_pm_ops, ++ }, ++}; ++#endif ++ ++static int __init pcm512x_modinit(void) ++{ ++ int ret = 0; ++ ++#if IS_ENABLED(CONFIG_I2C) ++ ret = i2c_add_driver(&pcm512x_i2c_driver); ++ if (ret) { ++ printk(KERN_ERR "Failed to register pcm512x I2C driver: %d\n", ++ ret); ++ } ++#endif ++#if defined(CONFIG_SPI_MASTER) ++ ret = spi_register_driver(&pcm512x_spi_driver); ++ if (ret != 0) { ++ printk(KERN_ERR "Failed to register pcm512x SPI driver: %d\n", ++ ret); ++ } ++#endif ++ return ret; ++} ++module_init(pcm512x_modinit); ++ ++static void __exit pcm512x_exit(void) ++{ ++#if IS_ENABLED(CONFIG_I2C) ++ i2c_del_driver(&pcm512x_i2c_driver); ++#endif ++#if defined(CONFIG_SPI_MASTER) ++ spi_unregister_driver(&pcm512x_spi_driver); ++#endif ++} ++module_exit(pcm512x_exit); ++ ++MODULE_DESCRIPTION("ASoC PCM512x codec driver"); ++MODULE_AUTHOR("Mark Brown "); ++MODULE_LICENSE("GPL v2"); +diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h +new file mode 100644 +index 0000000..b2f518e +--- /dev/null ++++ b/sound/soc/codecs/pcm512x.h +@@ -0,0 +1,142 @@ ++/* ++ * Driver for the PCM512x CODECs ++ * ++ * Author: Mark Brown ++ * Copyright 2014 Linaro Ltd ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++#ifndef _SND_SOC_PCM512X ++#define _SND_SOC_PCM512X ++ ++#define PCM512x_PAGE_0_BASE 0 ++ ++#define PCM512x_PAGE 0 ++ ++#define PCM512x_RESET (PCM512x_PAGE_0_BASE + 1) ++#define PCM512x_POWER (PCM512x_PAGE_0_BASE + 2) ++#define PCM512x_MUTE (PCM512x_PAGE_0_BASE + 3) ++#define PCM512x_PLL_EN (PCM512x_PAGE_0_BASE + 4) ++#define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_0_BASE + 6) ++#define PCM512x_DSP (PCM512x_PAGE_0_BASE + 7) ++#define PCM512x_GPIO_EN (PCM512x_PAGE_0_BASE + 8) ++#define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_0_BASE + 9) ++#define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_0_BASE + 10) ++#define PCM512x_MASTER_MODE (PCM512x_PAGE_0_BASE + 12) ++#define PCM512x_PLL_REF (PCM512x_PAGE_0_BASE + 13) ++#define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_0_BASE + 20) ++#define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_0_BASE + 21) ++#define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_0_BASE + 22) ++#define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_0_BASE + 23) ++#define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_0_BASE + 24) ++#define PCM512x_DSP_CLKDIV (PCM512x_PAGE_0_BASE + 27) ++#define PCM512x_DAC_CLKDIV (PCM512x_PAGE_0_BASE + 28) ++#define PCM512x_NCP_CLKDIV (PCM512x_PAGE_0_BASE + 29) ++#define PCM512x_OSR_CLKDIV (PCM512x_PAGE_0_BASE + 30) ++#define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_0_BASE + 32) ++#define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_0_BASE + 33) ++#define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_0_BASE + 34) ++#define PCM512x_IDAC_1 (PCM512x_PAGE_0_BASE + 35) ++#define PCM512x_IDAC_2 (PCM512x_PAGE_0_BASE + 36) ++#define PCM512x_ERROR_DETECT (PCM512x_PAGE_0_BASE + 37) ++#define PCM512x_I2S_1 (PCM512x_PAGE_0_BASE + 40) ++#define PCM512x_I2S_2 (PCM512x_PAGE_0_BASE + 41) ++#define PCM512x_DAC_ROUTING (PCM512x_PAGE_0_BASE + 42) ++#define PCM512x_DSP_PROGRAM (PCM512x_PAGE_0_BASE + 43) ++#define PCM512x_CLKDET (PCM512x_PAGE_0_BASE + 44) ++#define PCM512x_AUTO_MUTE (PCM512x_PAGE_0_BASE + 59) ++#define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_0_BASE + 60) ++#define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_0_BASE + 61) ++#define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_0_BASE + 62) ++#define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_0_BASE + 63) ++#define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_0_BASE + 64) ++#define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_0_BASE + 65) ++#define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_0_BASE + 80) ++#define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_0_BASE + 81) ++#define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_0_BASE + 82) ++#define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_0_BASE + 83) ++#define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_0_BASE + 84) ++#define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_0_BASE + 85) ++#define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_0_BASE + 86) ++#define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_0_BASE + 87) ++#define PCM512x_OVERFLOW (PCM512x_PAGE_0_BASE + 90) ++#define PCM512x_RATE_DET_1 (PCM512x_PAGE_0_BASE + 91) ++#define PCM512x_RATE_DET_2 (PCM512x_PAGE_0_BASE + 92) ++#define PCM512x_RATE_DET_3 (PCM512x_PAGE_0_BASE + 93) ++#define PCM512x_RATE_DET_4 (PCM512x_PAGE_0_BASE + 94) ++#define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_0_BASE + 108) ++#define PCM512x_GPIN (PCM512x_PAGE_0_BASE + 119) ++#define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_0_BASE + 120) ++ ++#define PCM512x_MAX_REGISTER (PCM512x_PAGE_0_BASE + 120) ++ ++/* Page 0, Register 1 - reset */ ++#define PCM512x_RSTR (1 << 0) ++#define PCM512x_RSTM (1 << 4) ++ ++/* Page 0, Register 2 - power */ ++#define PCM512x_RQPD (1 << 0) ++#define PCM512x_RQPD_SHIFT 0 ++#define PCM512x_RQST (1 << 4) ++#define PCM512x_RQST_SHIFT 4 ++ ++/* Page 0, Register 3 - mute */ ++#define PCM512x_RQMR_SHIFT 0 ++#define PCM512x_RQML_SHIFT 4 ++ ++/* Page 0, Register 4 - PLL */ ++#define PCM512x_PLCE (1 << 0) ++#define PCM512x_RLCE_SHIFT 0 ++#define PCM512x_PLCK (1 << 4) ++#define PCM512x_PLCK_SHIFT 4 ++ ++/* Page 0, Register 7 - DSP */ ++#define PCM512x_SDSL (1 << 0) ++#define PCM512x_SDSL_SHIFT 0 ++#define PCM512x_DEMP (1 << 4) ++#define PCM512x_DEMP_SHIFT 4 ++ ++/* Page 0, Register 13 - PLL reference */ ++#define PCM512x_SREF (1 << 4) ++ ++/* Page 0, Register 37 - Error detection */ ++#define PCM512x_IPLK (1 << 0) ++#define PCM512x_DCAS (1 << 1) ++#define PCM512x_IDCM (1 << 2) ++#define PCM512x_IDCH (1 << 3) ++#define PCM512x_IDSK (1 << 4) ++#define PCM512x_IDBK (1 << 5) ++#define PCM512x_IDFS (1 << 6) ++ ++/* Page 0, Register 42 - DAC routing */ ++#define PCM512x_AUPR_SHIFT 0 ++#define PCM512x_AUPL_SHIFT 4 ++ ++/* Page 0, Register 59 - auto mute */ ++#define PCM512x_ATMR_SHIFT 0 ++#define PCM512x_ATML_SHIFT 4 ++ ++/* Page 0, Register 63 - ramp rates */ ++#define PCM512x_VNDF_SHIFT 6 ++#define PCM512x_VNDS_SHIFT 4 ++#define PCM512x_VNUF_SHIFT 2 ++#define PCM512x_VNUS_SHIFT 0 ++ ++/* Page 0, Register 64 - emergency ramp rates */ ++#define PCM512x_VEDF_SHIFT 6 ++#define PCM512x_VEDS_SHIFT 4 ++ ++/* Page 0, Register 65 - Digital mute enables */ ++#define PCM512x_ACTL_SHIFT 2 ++#define PCM512x_AMLE_SHIFT 1 ++#define PCM512x_AMLR_SHIFT 0 ++ ++#endif +-- +1.8.5.5 + + +From 05a105da2563512639f45dbd8aae4fa87ad5411b Mon Sep 17 00:00:00 2001 +From: Howard Mitchell +Date: Fri, 28 Mar 2014 16:27:57 +0000 +Subject: [PATCH 97/99] 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.8.5.5 + + +From 0d94f1fd12135e5616135829b515ba1f5962740e Mon Sep 17 00:00:00 2001 +From: Howard Mitchell +Date: Fri, 28 Mar 2014 16:40:31 +0000 +Subject: [PATCH 98/99] 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 SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, + 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.8.5.5 + + +From dbddcf763ee7cecef28a677494c4f2c21e1137b7 Mon Sep 17 00:00:00 2001 +From: Gordon Garrity +Date: Sun, 30 Mar 2014 13:52:33 +0100 +Subject: [PATCH 99/99] 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 SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, + 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.8.5.5 +