From c1613bf19b8db580215d1111f48cc8e762be7e05 Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 1/9] bcm2835-bootloader: add support for device specific files --- packages/tools/bcm2835-bootloader/package.mk | 22 +++++++++++++------- packages/tools/bcm2835-bootloader/release | 13 +++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/tools/bcm2835-bootloader/package.mk b/packages/tools/bcm2835-bootloader/package.mk index 091a080cb9..0e626af741 100644 --- a/packages/tools/bcm2835-bootloader/package.mk +++ b/packages/tools/bcm2835-bootloader/package.mk @@ -31,10 +31,7 @@ PKG_IS_ADDON="no" PKG_AUTORECONF="no" make_target() { - if [ -f $DISTRO_DIR/$DISTRO/config/dt-blob.dts ]; then - echo Compiling device tree blob - $(kernel_path)/scripts/dtc/dtc -O dtb -o dt-blob.bin $DISTRO_DIR/$DISTRO/config/dt-blob.dts - fi + : } makeinstall_target() { @@ -43,17 +40,28 @@ makeinstall_target() { cp -PRv bootcode.bin $INSTALL/usr/share/bootloader cp -PRv fixup_x.dat $INSTALL/usr/share/bootloader/fixup.dat cp -PRv start_x.elf $INSTALL/usr/share/bootloader/start.elf - [ -f dt-blob.bin ] && cp -PRv dt-blob.bin $INSTALL/usr/share/bootloader/dt-blob.bin + + if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin ]; then + cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin $INSTALL/usr/share/bootloader + fi cp -PRv $PKG_DIR/scripts/update.sh $INSTALL/usr/share/bootloader - if [ -f $DISTRO_DIR/$DISTRO/config/distroconfig.txt ]; then + if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/distroconfig.txt ]; then + cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/distroconfig.txt $INSTALL/usr/share/bootloader + elif [ -f $PROJECT_DIR/$PROJECT/config/distroconfig.txt ]; then + cp -PRv $PROJECT_DIR/$PROJECT/config/distroconfig.txt $INSTALL/usr/share/bootloader + elif [ -f $DISTRO_DIR/$DISTRO/config/distroconfig.txt ]; then cp -PRv $DISTRO_DIR/$DISTRO/config/distroconfig.txt $INSTALL/usr/share/bootloader else cp -PRv $PKG_DIR/files/3rdparty/bootloader/distroconfig.txt $INSTALL/usr/share/bootloader fi - if [ -f $DISTRO_DIR/$DISTRO/config/config.txt ]; then + if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/config.txt ]; then + cp -PRv $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/config.txt $INSTALL/usr/share/bootloader + elif [ -f $PROJECT_DIR/$PROJECT/config/config.txt ]; then + cp -PRv $PROJECT_DIR/$PROJECT/config/config.txt $INSTALL/usr/share/bootloader + elif [ -f $DISTRO_DIR/$DISTRO/config/config.txt ]; then cp -PRv $DISTRO_DIR/$DISTRO/config/config.txt $INSTALL/usr/share/bootloader else cp -PRv $PKG_DIR/files/3rdparty/bootloader/config.txt $INSTALL/usr/share/bootloader diff --git a/packages/tools/bcm2835-bootloader/release b/packages/tools/bcm2835-bootloader/release index 577d4b473b..5170fa409f 100755 --- a/packages/tools/bcm2835-bootloader/release +++ b/packages/tools/bcm2835-bootloader/release @@ -25,8 +25,15 @@ mkdir -p $RELEASE_DIR/3rdparty/bootloader cp -PR $BUILD/bcm2835-bootloader-*/bootcode.bin $RELEASE_DIR/3rdparty/bootloader/ cp -PR $BUILD/bcm2835-bootloader-*/fixup_x.dat $RELEASE_DIR/3rdparty/bootloader/fixup.dat cp -PR $BUILD/bcm2835-bootloader-*/start_x.elf $RELEASE_DIR/3rdparty/bootloader/start.elf - [ -f $BUILD/bcm2835-bootloader-*/dt-blob.bin ] && cp -PR $BUILD/bcm2835-bootloader-*/dt-blob.bin $RELEASE_DIR/3rdparty/bootloader/ + if [ -f $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin ]; then + cp -PR $PROJECT_DIR/$PROJECT/devices/$DEVICE/config/dt-blob.bin $RELEASE_DIR/3rdparty/bootloader/ + fi cp -PR $INSTALL/usr/share/bootloader/*.dtb $RELEASE_DIR/3rdparty/bootloader/ cp -PR $INSTALL/usr/share/bootloader/overlays $RELEASE_DIR/3rdparty/bootloader/ - cp -PR $INSTALL/usr/share/bootloader/config.txt $RELEASE_DIR/3rdparty/bootloader/ - cp -PR $INSTALL/usr/share/bootloader/distroconfig.txt $RELEASE_DIR/3rdparty/bootloader/ + + if [ -f $INSTALL/usr/share/bootloader/config.txt ]; then + cp -PR $INSTALL/usr/share/bootloader/config.txt $RELEASE_DIR/3rdparty/bootloader/ + fi + if [ -f $INSTALL/usr/share/bootloader/distroconfig.txt ]; then + cp -PR $INSTALL/usr/share/bootloader/distroconfig.txt $RELEASE_DIR/3rdparty/bootloader/ + fi From a34815d1457a01a07a97ea828f797c37d700ab49 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 2/9] led_tools: add package --- .../led_tools/media/ledpatterns/ffwd.png | Bin 0 -> 235 bytes .../led_tools/media/ledpatterns/pause.png | Bin 0 -> 247 bytes .../led_tools/media/ledpatterns/play.png | Bin 0 -> 250 bytes .../led_tools/media/ledpatterns/quit.png | Bin 0 -> 2530 bytes .../tools/led_tools/media/ledpatterns/rew.png | Bin 0 -> 242 bytes .../led_tools/media/ledpatterns/shutdown.png | Bin 0 -> 4338 bytes .../led_tools/media/ledpatterns/skipf.png | Bin 0 -> 229 bytes .../led_tools/media/ledpatterns/skipr.png | Bin 0 -> 228 bytes .../led_tools/media/ledpatterns/sleep.png | Bin 0 -> 2319 bytes .../led_tools/media/ledpatterns/startup.png | Bin 0 -> 22721 bytes .../led_tools/media/ledpatterns/stop.png | Bin 0 -> 1329 bytes .../led_tools/media/ledpatterns/wake.png | Bin 0 -> 2543 bytes packages/tools/led_tools/package.mk | 46 ++++++++++++++++++ 13 files changed, 46 insertions(+) create mode 100644 packages/tools/led_tools/media/ledpatterns/ffwd.png create mode 100644 packages/tools/led_tools/media/ledpatterns/pause.png create mode 100644 packages/tools/led_tools/media/ledpatterns/play.png create mode 100644 packages/tools/led_tools/media/ledpatterns/quit.png create mode 100644 packages/tools/led_tools/media/ledpatterns/rew.png create mode 100644 packages/tools/led_tools/media/ledpatterns/shutdown.png create mode 100644 packages/tools/led_tools/media/ledpatterns/skipf.png create mode 100644 packages/tools/led_tools/media/ledpatterns/skipr.png create mode 100644 packages/tools/led_tools/media/ledpatterns/sleep.png create mode 100644 packages/tools/led_tools/media/ledpatterns/startup.png create mode 100644 packages/tools/led_tools/media/ledpatterns/stop.png create mode 100644 packages/tools/led_tools/media/ledpatterns/wake.png create mode 100644 packages/tools/led_tools/package.mk diff --git a/packages/tools/led_tools/media/ledpatterns/ffwd.png b/packages/tools/led_tools/media/ledpatterns/ffwd.png new file mode 100644 index 0000000000000000000000000000000000000000..5bee66fb5cfc8218fc77a18194cd492b884d4178 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^l0eMQ!3HD+(^8%SDVB6cUq=Rpjs4tz5?O(K&H|6f zVg?4jgCNYfV`BDOprBNVYeY$Kep*R+Vo@qXKw@TIiJqTph(ejMo~fRpfx(xeg+Nv5 zo-U3d7XDj%8Mzn~Iaq3E`G0=COr~5Uw`3+4v*{G)EM=urXS`fYE1t~VG(-RE)4w7| z<~bMUh`1VRY)%fSQ#ra|&W;|(ohlN|MW+*Ugxvr1^v++Dlk_84M8vpX{{E%oZ~Ek) bI^JSfB_?ZD`cbqEXeEQEtDnm{r-UW|3P4S; literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/pause.png b/packages/tools/led_tools/media/ledpatterns/pause.png new file mode 100644 index 0000000000000000000000000000000000000000..60a480f1047a84c6bf5feb263913dc6bae8c33be GIT binary patch literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^l0eMQ!3HD+(^8%SDVB6cUq=Rpjs4tz5?O(K&H|6f zVg?4j10c+pb*+;VC@59p8c`CQpH@;6t+$9cg)rXSZznZD{glC2O4^Z*9)o694sQ?`Jwt?X|&~Vb{L9 sOc%b)6JU6`H|W11mdKI;Vst0ND0eL;wH) literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/quit.png b/packages/tools/led_tools/media/ledpatterns/quit.png new file mode 100644 index 0000000000000000000000000000000000000000..667ada77e62bca01dc3275a4efa48a80a0ae0ca0 GIT binary patch literal 2530 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 guq=t@ne(6j1;Y;4k07*qoM6N<$f>UXGq5uE@ literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/skipf.png b/packages/tools/led_tools/media/ledpatterns/skipf.png new file mode 100644 index 0000000000000000000000000000000000000000..2018e325eb8d9ab8e119776ba7db38e6da5ad2af GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^l0eMI!3HF6S#5U!QY`6?zK#qG8~eHcB(eheoCO|{ z#XvRtL735kHCP2GC{^MbQ4*Y=R#Ki=l*$m0n3-3i=jR%tP-d)Ws%L0m@TF)WP*tL* zi(`m||JL)~d<_Z$EEnyh+#f$%s~51?^~bqIVl9br6LPfEwN+o+94%2?YVfAFC9!47 zw!|%eZX3CIXZt2^S##CE&AaOLu@@gRe0${1h8@kQ*edVlynC17t~+->FJ1A3*-LAG Ve%aQBmq5!HJYD@<);T3K0RWJlPlf;h literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/skipr.png b/packages/tools/led_tools/media/ledpatterns/skipr.png new file mode 100644 index 0000000000000000000000000000000000000000..9292082b82fafe00c00691e39fd387b616217220 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^l0eMI!3HF6S#5U!QY`6?zK#qG8~eHcB(eheoCO|{ z#XvRtK$!8B)5ZfpL8%hgh?3y^w370~qEv=}#LT=BJwMkFg)(D3Q$0figD*u3fvOTb zT^vI!{I_0k_HNvGrg9r0B1PkW@YaraaU&na4uQhFzw`dzbF+J5!i`%RoV3`P6% U+ikvu0PSM%boFyt=akR{03?A<)c^nh literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/sleep.png b/packages/tools/led_tools/media/ledpatterns/sleep.png new file mode 100644 index 0000000000000000000000000000000000000000..3cef539d53e28dd76677230cc83008016695f2f9 GIT binary patch literal 2319 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 M07*qoM6N<$f)!G%?EnA( literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/stop.png b/packages/tools/led_tools/media/ledpatterns/stop.png new file mode 100644 index 0000000000000000000000000000000000000000..e02589b8136cc15de486d0fedd700f36485685d4 GIT binary patch literal 1329 zcmV-11P000pP1^@s6D7ps@00004XF*Lt007wQ z^&Awc0000WV@Og>004&%004{)008-u004yL004V}008TC002L<001Ibb!%Rn000B< zX+uL$Nkc;*P;zf(X>4Tx07%D;Ro!pfR1`mnZ(O7nKcKOW4i$^9Ra0BJ8yc;~21%2p z=|UR0&DbiW$#rfTQ`a`O(`{9s_5yDV_yd5l2Of}kLK+Oj_Ok5(v`JGz71bo9J#^YY zXp{DWs&KBaQ@dTpxRI}aIp=pi@6k0t$5)!;m`NF6-tt{FpOKHBn3g+MAqmexC-gw4 zrh87hTrL7G#)U`L!(So6-Zux@>;H3gR;i~0B%VTSS3P|m@o9jRsXML@Al^p#@G0Lx z-0?i(9WEw_SYddU<1E8793KxjQ|c&UmW!mTC> zk>?{om1c9SUx<6_jj_!T&^M{wWM#>IBbOSf*xP<^F{$ zj$aOQ5Y{cTROCL1M7^NKKL&(yA}mSw#iM0^;IB{ZO5!wl{^Sg-*ysE~&Yz8!E;Qv(A`lu*=Clo*Mp zVGd>OdF6n^am1Jntk;<}MrqIC5$=Q>n{*R}?8oOIDUw5En2dl--Xw34!z7E+5pr-OgyQ-soSab)C%saskMla`aQLVzg0+MZf20tJU&K{hZoBrUc+U4 ze9&3ow|KmGEe4#xz17wBu{f`SS_4i66?j31EjY7n{zGfhONK~c+td!TS#B}J zoR}5UAd7p&5phTyXSkK0xCeD3xaYP^o&J~#Xp9xFb0C;HHml5fA<%h1eR|qw7wxF+ zoNL9T1Aits?sKNIwvGaN)^WO$I z^cUV)HzL_|1K?{9p!>B*)`xfEv!4N6IG{J&h49W#Bz^(#YWw%`e_a{8n{G9m5AeR~ z_yl0%<7V@pN2bPDNB8b~7$DE-^4L^m3s9004zaL_t(IPrZ&o4!|G? z!1lB~Z9jKngy<|$5;BusDpId{$`7E-24yxV7jA&&98gZk!UqV1P#R;P3L_Xo+3*5N zAcV3#)JPRB8rg(UTHqw2A==YHX}>#(=q&B&ploQw3+de^AfPn7P#_?noESqRhXDcQ nf-L+(a}Fr8L75H8M6U7zW8dXMNKhyO00000NkvXXu0mjfq^)Ko literal 0 HcmV?d00001 diff --git a/packages/tools/led_tools/media/ledpatterns/wake.png b/packages/tools/led_tools/media/ledpatterns/wake.png new file mode 100644 index 0000000000000000000000000000000000000000..31944073b0969e3935cfc2dc9bd980f2c9b1e4e4 GIT binary patch literal 2543 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 FV1g8Q(. +################################################################################ + +PKG_NAME="led_tools" +PKG_VERSION="0.1" +PKG_ARCH="any" +PKG_LICENSE="GPL" +PKG_SITE="http://www.fiveninjas.com" +PKG_URL="http://updates.fiveninjas.com/src/$PKG_NAME-$PKG_VERSION.tar.gz" +PKG_DEPENDS_TARGET="toolchain zlib libpng" +PKG_DEPENDS_HOST="toolchain" +PKG_SECTION="tools" +PKG_SHORTDESC="led_tools" +PKG_LONGDESC="LED tools, these are a set of tools to control the LEDs on Slice" + +PKG_IS_ADDON="no" +PKG_AUTORECONF="no" + +make_target() { + make CC="$CC" \ + CFLAGS="$CFLAGS" \ + LDFLAGS="$LDFLAGS" +} + +makeinstall_target() { + mkdir -p $INSTALL/usr/bin + cp led_png $INSTALL/usr/bin + + mkdir -p $INSTALL/usr/share/kodi/ + cp -r $PKG_DIR/media $INSTALL/usr/share/kodi/ +} From 5a43defa8ad9cd94e360d2b11391f9089c610961 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 3/9] kodi: depends on led_tools for slice projects --- packages/mediacenter/kodi/package.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/mediacenter/kodi/package.mk b/packages/mediacenter/kodi/package.mk index 49aa9cbb61..51ac987201 100644 --- a/packages/mediacenter/kodi/package.mk +++ b/packages/mediacenter/kodi/package.mk @@ -186,6 +186,10 @@ else KODI_ARCH="-DWITH_ARCH=$TARGET_ARCH" fi +if [ "$DEVICE" = "Slice" -o "$DEVICE" = "Slice3" ]; then + PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET led_tools" +fi + if [ ! "$KODIPLAYER_DRIVER" = default ]; then PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $KODIPLAYER_DRIVER" if [ "$KODIPLAYER_DRIVER" = bcm2835-driver ]; then From f9f8d5c67e18cd164ead4343afa650248752373e Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 4/9] linux: install device specific dts files --- packages/linux/package.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/linux/package.mk b/packages/linux/package.mk index 4cb15c585c..98c1cfcee0 100644 --- a/packages/linux/package.mk +++ b/packages/linux/package.mk @@ -139,6 +139,10 @@ post_patch() { sed -i -e "s|CONFIG_MXC_HDMI_CEC_SR=y||" $PKG_BUILD/.config fi fi + + # install extra dts files + cp -v projects/$PROJECT/devices/$DEVICE/config/*-overlay.dts $PKG_BUILD/arch/$TARGET_KERNEL_ARCH/boot/dts/overlays/ || : + cp -v projects/$PROJECT/devices/$DEVICE/config/dt-blob.dts $PKG_BUILD/arch/$TARGET_KERNEL_ARCH/boot/dts/ || : } makeinstall_host() { From c7b19e897cd0aa1524509b457ad6f9793177f25d Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 5/9] config/functions: just check if the linux.*.conf exists --- config/functions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/functions b/config/functions index e0263de80c..371755f2f0 100644 --- a/config/functions +++ b/config/functions @@ -329,7 +329,7 @@ dashes="===========================" linux_config_dir="$PROJECT_DIR/$PROJECT/linux" fi - if [ ! -f $linux_config_dir/linux.$TARGET_ARCH.conf ] && + if [ ! -e $linux_config_dir/linux.$TARGET_ARCH.conf ] && ! ls $linux_config_dir/*/linux.$TARGET_ARCH.conf &>/dev/null; then check_arch="$check_arch\n $dashes$dashes$dashes" check_arch="$check_arch\n ERROR: Architecture not found, use a valid Architecture" From e63937bab1d1f22e92c83b32f2b945c8a7d40895 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 6/9] RPi: add device Slice --- projects/RPi/devices/RPi/linux/linux.arm.conf | 4 +- .../RPi/devices/Slice/config/distroconfig.txt | 23 + projects/RPi/devices/Slice/config/dt-blob.bin | Bin 0 -> 4171 bytes projects/RPi/devices/Slice/config/dt-blob.dts | 92 +++ .../devices/Slice/config/slice-overlay.dts | 172 +++++ .../devices/Slice/config/ws2812-overlay.dts | 33 + .../Slice/filesystem/usr/config/autostart.sh | 2 + .../Slice/filesystem/usr/config/shutdown.sh | 23 + .../usr/share/alsa/cards/snd_slice.conf | 25 + .../RPi/devices/Slice/linux/linux.arm.conf | 1 + projects/RPi/devices/Slice/options | 2 + .../patches/kodi/kodi-002-slice-led.patch | 677 ++++++++++++++++++ .../patches/kodi/kodi-003-slice-audio.patch | 18 + .../patches/kodi/kodi-004-keyboard.patch | 22 + .../Slice/patches/kodi/kodi-005-cmake.patch | 31 + 15 files changed, 1124 insertions(+), 1 deletion(-) create mode 100644 projects/RPi/devices/Slice/config/distroconfig.txt create mode 100644 projects/RPi/devices/Slice/config/dt-blob.bin create mode 100644 projects/RPi/devices/Slice/config/dt-blob.dts create mode 100644 projects/RPi/devices/Slice/config/slice-overlay.dts create mode 100644 projects/RPi/devices/Slice/config/ws2812-overlay.dts create mode 100644 projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh create mode 100644 projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh create mode 100644 projects/RPi/devices/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf create mode 120000 projects/RPi/devices/Slice/linux/linux.arm.conf create mode 100644 projects/RPi/devices/Slice/options create mode 100644 projects/RPi/devices/Slice/patches/kodi/kodi-002-slice-led.patch create mode 100644 projects/RPi/devices/Slice/patches/kodi/kodi-003-slice-audio.patch create mode 100644 projects/RPi/devices/Slice/patches/kodi/kodi-004-keyboard.patch create mode 100644 projects/RPi/devices/Slice/patches/kodi/kodi-005-cmake.patch diff --git a/projects/RPi/devices/RPi/linux/linux.arm.conf b/projects/RPi/devices/RPi/linux/linux.arm.conf index b614eb0f7b..0aa3c9001c 100644 --- a/projects/RPi/devices/RPi/linux/linux.arm.conf +++ b/projects/RPi/devices/RPi/linux/linux.arm.conf @@ -1071,6 +1071,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_BCM2835_SMI=m +CONFIG_BCM2835_WS2812=m # CONFIG_AD525X_DPOT is not set # CONFIG_DUMMY_IRQ is not set # CONFIG_ICS932S401 is not set @@ -2802,6 +2803,7 @@ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m CONFIG_SND_BCM2708_SOC_RASPIDAC3=m +CONFIG_SND_BCM2708_SOC_SLICE=m CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m @@ -2855,7 +2857,7 @@ CONFIG_SND_SOC_ADAU7002=m # CONFIG_SND_SOC_CS42L52 is not set # CONFIG_SND_SOC_CS42L56 is not set # CONFIG_SND_SOC_CS42L73 is not set -# CONFIG_SND_SOC_CS4265 is not set +CONFIG_SND_SOC_CS4265=m # CONFIG_SND_SOC_CS4270 is not set # CONFIG_SND_SOC_CS4271_I2C is not set # CONFIG_SND_SOC_CS4271_SPI is not set diff --git a/projects/RPi/devices/Slice/config/distroconfig.txt b/projects/RPi/devices/Slice/config/distroconfig.txt new file mode 100644 index 0000000000..aa3604e820 --- /dev/null +++ b/projects/RPi/devices/Slice/config/distroconfig.txt @@ -0,0 +1,23 @@ +################################################################################ +# This file is part of LibreELEC - http://www.libreelec.tv +# Copyright (C) 2016 Team LibreELEC +# +# LibreELEC 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. +# +# LibreELEC 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 LibreELEC. If not, see . +################################################################################ + +# WARNING: DO NOT EDIT THIS FILE - IT WILL BE OVERWRITTEN WHEN UPGRADING! + +dtoverlay=slice +dtoverlay=ws2812 + diff --git a/projects/RPi/devices/Slice/config/dt-blob.bin b/projects/RPi/devices/Slice/config/dt-blob.bin new file mode 100644 index 0000000000000000000000000000000000000000..f4f373db200b959d241ed383a81d030ce3dd4bd3 GIT binary patch literal 4171 zcmcIn-EPw`6n6P9KVn?$3CaaX2tk@LxIwKt#Mruanu@rzN}6`oQYWO&$}V^oUWNzY zMR)^*IOn8sld4G@2O_z#PyL-^`+T2c|9tT07h^lejIq~@J^T&tCr}_sdU4AYm z=h#I1T`2V+@;pBB=Mt^4y$afJ_e7e!m>aM}978OT z#}G>dGQ<*zG&UNBDwYkc`#o66y7W29QOH=!skI^^23YP# z%|hPg??+9|xiVwSJHMch-P9>1HNHZAZdk`cer~{Oe*TO3ZODP<^#6}#ujpV-XU~K` z`QI&D>tNe4E^}yC(1Km4g>~OOoJ$_hit}J=E!+ej4PiMnX{c|pK3We3*wP%w@!)>+ z3<_#AZ_cS4Xf14;zjZNCGwb#k^toQYc2-BTkuwZO=!M3-y1%T(OpQOQ5o14ln*X#8 z=6w?Zm6ltT}V@Fe-{K>azCl^CsVyT{Ky_OR<#KAtXopda$(c)oMNXReCxqcv)` zPCuQX$7TE@_V_!tmzdW3(@ys|t#8!RQSIB;)}mh$1K;()_lBWRR}7{%g$uP3zGO26 sC;uqm@K!DxM-ndPU>=2dJ)f!2l@oQ&r){RL0+-2X`q>THICQ_Tzj2#tyZ`_I literal 0 HcmV?d00001 diff --git a/projects/RPi/devices/Slice/config/dt-blob.dts b/projects/RPi/devices/Slice/config/dt-blob.dts new file mode 100644 index 0000000000..443b31b7c8 --- /dev/null +++ b/projects/RPi/devices/Slice/config/dt-blob.dts @@ -0,0 +1,92 @@ +/dts-v1/; + +/ { + videocore { + + pins_cm { + + pin_config { + + pin@default { + polarity = "active_high"; + termination = "pull_down"; + startup_state = "inactive"; + function = "input"; + }; // pin + + // BANK 0 // + pin@p0 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p1 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p2 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p3 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p4 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p5 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p6 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p7 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p8 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p9 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p10 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p11 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p12 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p13 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p14 { function = "uart0"; termination = "no_pulling"; }; // UART0_TX + pin@p15 { function = "uart0"; termination = "pull_up"; }; // UART0_RX + pin@p16 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p17 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p18 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p19 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p20 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p21 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p22 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p23 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p24 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p25 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p26 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p27 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + + // BANK 1 // + pin@p28 { function = "pcm"; termination = "no_pulling"; }; // PCM_CLK + pin@p29 { function = "pcm"; termination = "no_pulling"; }; // PCM_FS + pin@p30 { function = "pcm"; termination = "no_pulling"; }; // PCM_DIN + pin@p31 { function = "pcm"; termination = "no_pulling"; }; // PCM_DOUT + pin@p32 { function = "gp_clk"; termination = "no_pulling"; }; // PCM_MCLK (GPCLK0) + pin@p33 { function = "output"; termination = "no_pulling"; polarity = "active_low"; startup_state = "inactive"; }; // AUD_RST_N + pin@p34 { function = "input"; termination = "pull_up"; }; // NOT USED + pin@p35 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "active"; }; // USB_ON + pin@p36 { function = "input"; termination = "no_pulling"; }; // RTC_IRQ + pin@p37 { function = "input"; termination = "no_pulling"; }; // IR_RX + pin@p38 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // STBY_LED + pin@p39 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // DISK_OFF + pin@p40 { function = "pwm"; termination = "no_pulling"; }; // LED_PWM + pin@p41 { function = "output"; termination = "no_pulling"; }; // LAN_RUN + pin@p42 { function = "gp_clk"; termination = "no_pulling"; }; // ETH_CLK (GPCLK1) + pin@p43 { function = "output"; termination = "pull_down"; polarity = "active_high"; startup_state = "inactive"; }; // LEDS_ON + pin@p44 { function = "i2c1"; termination = "no_pulling"; }; // SDA1 + pin@p45 { function = "i2c1"; termination = "no_pulling"; }; // SCL1 + + // BANK 2 // + pin@p46 { function = "input"; termination = "no_pulling"; drive_strength_mA = <8>; polarity = "active_high"; }; // HPD_N + pin@p47 { function = "output"; termination = "no_pulling"; drive_strength_mA = <8>; polarity = "active_low"; startup_state = "active"; }; // EMMC_DISABLE_N CONTROL + pin@p48 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CLK + pin@p49 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CMD + pin@p50 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D0 + pin@p51 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D1 + pin@p52 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D2 + pin@p53 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D3 + + }; // pin_config + + pin_defines { + pin_define@HDMI_CONTROL_ATTACHED { type = "internal"; number = <46>; }; // HPD_N on GPIO46 + pin_define@LAN_RUN { type = "internal"; number = <41>; }; // LAN_RUN + }; // pin_defines + + }; // pins_cm + + clock_setup { + clock@PWM { freq = < 2400000>; }; // LEDS PWM CLOCK + clock@GPCLK1 { freq = <25000000>; }; // ETH_CLK + }; // clock_setup + + }; // videocore +}; diff --git a/projects/RPi/devices/Slice/config/slice-overlay.dts b/projects/RPi/devices/Slice/config/slice-overlay.dts new file mode 100644 index 0000000000..7f0a4d2f3b --- /dev/null +++ b/projects/RPi/devices/Slice/config/slice-overlay.dts @@ -0,0 +1,172 @@ +// Definitions for Slice hardware +/dts-v1/; +/plugin/; + +#include "dt-bindings/clock/bcm2835.h" + +/ { + compatible = "brcm,bcm2708"; + + // + // Set up GPIOs: + // I2C1 on GPIO44,45 + // LIRC input/output on GPIO4 and 37 (NB GPIO4 NC on Slice) + // I2S on GPIO28-31 + // + fragment@0 { + target = <&gpio>; + __overlay__ { + i2c1_pins: i2c1 { + brcm,pins = <44 45>; + brcm,function = <6>; /* alt2 */ + }; + lirc_pins: lirc_pins { + brcm,pins = <4 37>; // + brcm,function = <1 0>; // out in + brcm,pull = <0 1>; // off down + }; + i2s_pins: i2s { + brcm,pins = <28 29 30 31>; + brcm,function = <6>; /* alt2 */ + }; + ws2812_pins: ws2812 { + brcm,pins = <40>; + brcm,function = <4>; /* alt0 */ + }; + }; + }; + + // + // I2C at 100KHz + // + fragment@1 { + target = <&i2c1>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; + }; + }; + + // + // Add devices to I2C1 Bus: + // PCF8523 RTC device + // CS4265 Audio CODEC + // + fragment@2 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + nxp,xtalcap-7pf; /* set crystal load to 7pf */ + status = "okay"; + }; + cs4265@4e { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4265"; + reg = <0x4e>; + cs4265-reset-gpios = <&gpio 33 0>; /* AUD_RST_N on GPIO33 */ + cirrus,no-s16le; /* remove S16LE support to workaround I2S controller issue */ + status = "okay"; + }; + }; + }; + + // + // LIRC + // + fragment@3 { + target-path = "/"; + __overlay__ { + lirc_rpi: lirc_rpi { + compatible = "rpi,lirc-rpi"; + pinctrl-names = "default"; + pinctrl-0 = <&lirc_pins>; + status = "okay"; + + // Override autodetection of IR receiver circuit + // (0 = active high, 1 = active low, -1 = no override ) + rpi,sense = <0xffffffff>; + + // Software carrier + // (0 = off, 1 = on) + rpi,softcarrier = <1>; + + // Invert output + // (0 = off, 1 = on) + rpi,invert = <0>; + + // Enable debugging messages + // (0 = off, 1 = on) + rpi,debug = <0>; + }; + }; + }; + + // + // Audio driver + // + fragment@4 { + #address-cells = <1>; + #size-cells = <1>; + target = <&sound>; + __overlay__ { + compatible = "fiveninjas,slice"; + clocks = <&cprman BCM2835_CLOCK_GP0>; + clock-names = "gp0"; + pinctrl-names = "default"; + i2s-controller = <&i2s>; + status = "okay"; + }; + }; + + // + // Enable I2S + // + fragment@5 { + target = <&i2s>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; + brcm,enable-mmap; + status = "okay"; + }; + }; + + // + // WS2812B LEDs driver + // + fragment@6 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + ws2812: ws2812 { + compatible = "rpi,ws2812"; + pinctrl-names = "default"; + pinctrl-0 = <&ws2812_pins>; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + rpi,invert = <1>; + rpi,num_leds = <25>; + status = "okay"; + }; + }; + }; + + // + // Disable standard audio + // + fragment@7 { + target = <&audio>; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/projects/RPi/devices/Slice/config/ws2812-overlay.dts b/projects/RPi/devices/Slice/config/ws2812-overlay.dts new file mode 100644 index 0000000000..42cde9d73b --- /dev/null +++ b/projects/RPi/devices/Slice/config/ws2812-overlay.dts @@ -0,0 +1,33 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2708"; + + fragment@0 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + ws2812: ws2812 { + compatible = "rpi,ws2812"; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + + rpi,invert = <1>; + rpi,num_leds = <25>; + + status = "okay"; + + }; + }; + }; + + __overrides__ { + invert = <&ws2812>,"rpi,invert:0"; + num_leds = <&ws2812>,"rpi,num_leds:0"; + }; +}; diff --git a/projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh b/projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh new file mode 100644 index 0000000000..0b6166972b --- /dev/null +++ b/projects/RPi/devices/Slice/filesystem/usr/config/autostart.sh @@ -0,0 +1,2 @@ +#!/bin/bash +hdparm -S60 /dev/sda diff --git a/projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh b/projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh new file mode 100644 index 0000000000..ebd32374e6 --- /dev/null +++ b/projects/RPi/devices/Slice/filesystem/usr/config/shutdown.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -f /storage/.kodi/media/ledpatterns/shutdown.png ]; then + LEDDIR=/storage/.kodi +else + LEDDIR=/usr/share/kodi +fi + +case "$1" in + halt) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + poweroff) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + reboot) + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + *) + ;; +esac diff --git a/projects/RPi/devices/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf b/projects/RPi/devices/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf new file mode 100644 index 0000000000..298f43d8e7 --- /dev/null +++ b/projects/RPi/devices/Slice/filesystem/usr/share/alsa/cards/snd_slice.conf @@ -0,0 +1,25 @@ + + +snd_slice.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } +} diff --git a/projects/RPi/devices/Slice/linux/linux.arm.conf b/projects/RPi/devices/Slice/linux/linux.arm.conf new file mode 120000 index 0000000000..15e9a3933d --- /dev/null +++ b/projects/RPi/devices/Slice/linux/linux.arm.conf @@ -0,0 +1 @@ +../../RPi/linux/linux.arm.conf \ No newline at end of file diff --git a/projects/RPi/devices/Slice/options b/projects/RPi/devices/Slice/options new file mode 100644 index 0000000000..a2566ab649 --- /dev/null +++ b/projects/RPi/devices/Slice/options @@ -0,0 +1,2 @@ + # Additional kernel make parameters + KERNEL_MAKE_EXTRACMD+=" dt-blob.dtb overlays/slice.dtbo overlays/ws2812.dtbo" diff --git a/projects/RPi/devices/Slice/patches/kodi/kodi-002-slice-led.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-002-slice-led.patch new file mode 100644 index 0000000000..6ba4cfb403 --- /dev/null +++ b/projects/RPi/devices/Slice/patches/kodi/kodi-002-slice-led.patch @@ -0,0 +1,677 @@ +--- a/xbmc/windows/GUIWindowHome.cpp 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.cpp 2016-10-01 19:22:20.908566550 +0100 +@@ -30,9 +30,245 @@ + #include "guilib/GUIWindowManager.h" + #include "Application.h" + #include "utils/StringUtils.h" ++extern "C" ++{ ++ #include "readpng.h" ++} + + using namespace ANNOUNCEMENT; + ++int g_pattern = 0; ++int g_halt = 0; ++int g_pattern_playing = 0; ++int g_speed = 30000; ++int g_repeat = 0; ++ ++enum pattern_e { ++ PAT_PLAY, PAT_PAUSE, PAT_STOP, PAT_SLEEP, PAT_WAKE, PAT_FFWD, PAT_REW, PAT_SKIPF, PAT_SKIPR, PAT_STARTUP, PAT_QUIT, PAT_NONE ++}; ++#define NUM_PATTERNS 11 ++const char *patterns[NUM_PATTERNS] = { ++ "play" , "pause", "stop", "sleep", "wake", "ffwd", "rew", "skipf", "skipr", "startup", "quit" ++}; ++ ++void on_speed_changed(const char *message, const CVariant &data) ++{ ++ int speed = data["player"]["speed"].asInteger(); ++ ++ CLog::Log(LOGDEBUG, "speed changed %d", speed); ++ ++ switch(abs(speed)) ++ { ++ case 1: g_speed = 60000; break; ++ case 2: g_speed = 40000; break; ++ case 4: g_speed = 35000; break; ++ case 8: g_speed = 30000; break; ++ case 16: g_speed = 25000; break; ++ case 32: g_speed = 15000; break; ++ } ++ ++ if(speed > 0) ++ g_pattern = PAT_FFWD; ++ else ++ g_pattern = PAT_REW; ++ ++ if(speed != 1) ++ g_repeat = 1; ++ else ++ { ++ g_repeat = 0; ++ g_pattern = PAT_NONE; ++ } ++} ++ ++void on_seek(const char *message, const CVariant &data) ++{ ++ int seek_time = data["player"]["seekoffset"]["seconds"].asInteger() + ++ data["player"]["seekoffset"]["minutes"].asInteger() * 60; ++ ++ CLog::Log(LOGDEBUG, "Seek offset = %d", seek_time); ++ if(seek_time > 0) ++ { ++ g_pattern = PAT_SKIPF; ++ } ++ else ++ { ++ g_pattern = PAT_SKIPR; ++ } ++ ++ g_repeat = 0; ++} ++ ++enum action_e { ++ ACTION_DO, ACTION_REPEAT, ACTION_FN ++ }; ++ ++enum led_state_e { ++ LED_STATE_INVALID = 0, ++ LED_STATE_IDLE, ++ LED_STATE_PLAYING, ++ LED_STATE_PAUSED, ++ LED_STATE_SLEEP ++}; ++ ++struct led_action_s { ++ const char * event_name; ++ enum action_e action; ++ enum pattern_e action_data; ++ void (*action_fn)(const char *, const CVariant &); ++ led_state_e action_state; ++} led_actions[] = { ++ { "OnPlay", ACTION_DO, PAT_PLAY, NULL, LED_STATE_PLAYING }, ++ { "OnPause", ACTION_DO, PAT_PAUSE, NULL, LED_STATE_PAUSED }, ++ { "OnStop", ACTION_DO, PAT_STOP, NULL, LED_STATE_IDLE }, ++ { "OnSpeedChanged", ACTION_FN, PAT_NONE, on_speed_changed, LED_STATE_INVALID }, ++ { "OnSeek", ACTION_FN, PAT_NONE, on_seek, LED_STATE_INVALID }, ++ { "OnScreensaverActivated", ACTION_DO, PAT_SLEEP, NULL, LED_STATE_SLEEP }, ++ { "OnScreensaverDeactivated", ACTION_DO, PAT_WAKE, NULL, LED_STATE_IDLE }, ++ { "OnQuit", ACTION_REPEAT, PAT_QUIT, NULL, LED_STATE_IDLE }, ++}; ++ ++int zeroes[25] = { 0,}; ++ ++class CLedPattern : public IRunnable ++{ ++ int m_going; ++ CEvent *m_ev; ++ struct pattern { ++ unsigned long w; ++ unsigned long h; ++ unsigned long rowbytes; ++ unsigned char * img; ++ } m_pattern[NUM_PATTERNS]; ++ ++ void open_patterns() ++ { ++ unsigned int i; ++ for(i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) ++ { ++ FILE * fp; ++ char filename[256]; ++ int channels; ++ ++ m_pattern[i].img = NULL; ++ sprintf(filename, "/storage/.kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename , "rb"); ++ if(fp == NULL) ++ { ++ sprintf(filename, "/usr/share/kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename, "rb"); ++ if(fp == NULL) ++ { ++ CLog::Log(LOGDEBUG, "Unable to open file %s", filename); ++ goto drop_out; ++ } ++ } ++ ++ if(readpng_init(fp, &m_pattern[i].w, &m_pattern[i].h) != 0) ++ { ++ CLog::Log(LOGERROR, "Unable to parse png files %s", filename); ++ goto drop_out; ++ } ++ ++ m_pattern[i].img = readpng_get_image(1.0, &channels, &m_pattern[i].rowbytes); ++ if(m_pattern[i].img == NULL || channels != 4) ++ { ++ CLog::Log(LOGERROR, "Invalid png %s, width = %lu, height = %lu, channels = %d, rowbytes = %lu", ++ filename, m_pattern[i].w, m_pattern[i].h, channels, m_pattern[i].rowbytes); ++ goto drop_out; ++ } ++ ++ CLog::Log(LOGDEBUG, "Opened %s: (%lu x %lu)", filename, m_pattern[i].w, m_pattern[i].h); ++ ++drop_out: ++ if(fp) ++ fclose(fp); ++ ++ } ++ } ++ ++ void play_pattern(int pat) ++ { ++ int fd = open("/dev/ws2812", O_WRONLY, 0); ++ if(fd < 0) ++ { ++ CLog::Log(LOGERROR, "Unable to open /dev/ws2812"); ++ } ++ else ++ { ++ if(pat < PAT_NONE && m_pattern[pat].img != NULL) ++ { ++ CLog::Log(LOGDEBUG, "playing pattern"); ++ g_pattern_playing = 1; ++ do ++ { ++ unsigned char * p_line = m_pattern[pat].img; ++ unsigned int i; ++ ++ for(i = 0; i < m_pattern[pat].h; i++) ++ { ++ write(fd, p_line, m_pattern[pat].w * 4); ++ if(m_pattern[pat].w == 26) ++ { ++ int *p = (int *) (p_line + (25 * 4)); ++ usleep(*p); ++ } ++ else ++ { ++ usleep(g_speed); ++ } ++ p_line += m_pattern[pat].rowbytes; ++ // If we get the g_halt signal then stop repeating ++ // the pattern ++ if(g_halt) ++ { ++ g_halt = 0; ++ g_repeat = 0; ++ break; ++ } ++ } ++ p_line += m_pattern[pat].rowbytes; ++ } ++ while(g_repeat); ++ g_pattern_playing = 0; ++ ++ if(pat != PAT_QUIT) ++ write(fd, zeroes, sizeof(zeroes)); ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG, "No img for LED pattern %d", pat); ++ } ++ close(fd); ++ } ++ } ++ ++public: ++ CLedPattern(CEvent *ev) ++ { ++ CLog::Log(LOGDEBUG, "Initialising CLedPattern"); ++ open_patterns(); ++ m_ev = ev; ++ } ++ ++ void Run() ++ { ++ m_going = 1; ++ while(m_going) ++ { ++ m_ev->Wait(); ++ CLog::Log(LOGDEBUG, "Led Pattern %d triggered", g_pattern); ++ play_pattern(g_pattern); ++ } ++ } ++ ++ void Stop() ++ { ++ m_going = 0; ++ m_ev->Set(); ++ } ++}; ++ + CGUIWindowHome::CGUIWindowHome(void) : CGUIWindow(WINDOW_HOME, "Home.xml"), + m_recentlyAddedRunning(false), + m_cumulativeUpdateFlag(0) +@@ -40,6 +276,14 @@ CGUIWindowHome::CGUIWindowHome(void) : C + m_updateRA = (Audio | Video | Totals); + m_loadType = KEEP_IN_MEMORY; + ++ m_ledevent = new CEvent(); ++ m_ledthread = new CThread(new CLedPattern(m_ledevent), "LedThread"); ++ m_ledthread->Create(); ++ g_pattern = PAT_STARTUP; ++ g_speed = 30000; ++ g_repeat = 0; ++ m_ledevent->Set(); ++ + CAnnouncementManager::GetInstance().AddAnnouncer(this); + } + +@@ -75,10 +319,49 @@ void CGUIWindowHome::OnInitWindow() + + void CGUIWindowHome::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) + { ++ unsigned int i; + int ra_flag = 0; + + CLog::Log(LOGDEBUG, "GOT ANNOUNCEMENT, type: %i, from %s, message %s",(int)flag, sender, message); + ++ for(i = 0; i < sizeof(led_actions)/sizeof(led_actions[0]); i++) ++ { ++ if(strcmp(message, led_actions[i].event_name) == 0) ++ { ++ switch(led_actions[i].action) { ++ case ACTION_DO: ++ case ACTION_REPEAT: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = (led_actions[i].action == ACTION_DO) ? 0 : 1; ++ g_speed = 30000; ++ g_pattern = (int) led_actions[i].action_data; ++ m_ledevent->Set(); ++ break; ++ } ++ case ACTION_FN: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = 0; ++ g_speed = 30000; ++ led_actions[i].action_fn(message, data); ++ m_ledevent->Set(); ++ break; ++ } ++ default: ++ { ++ CLog::Log(LOGERROR, "Failed to execute LED action %d for event %s\n", i, led_actions[i].event_name); ++ } ++ } ++ } ++ } ++ + // we are only interested in library changes + if ((flag & (VideoLibrary | AudioLibrary)) == 0) + return; +--- a/xbmc/windows/GUIWindowHome.h 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.h 2016-10-01 19:34:18.585113811 +0100 +@@ -23,6 +23,8 @@ + #include "guilib/GUIWindow.h" + #include "interfaces/IAnnouncer.h" + #include "utils/Job.h" ++#include "threads/Thread.h" ++#include "threads/Event.h" + + class CVariant; + +@@ -47,4 +49,7 @@ + + bool m_recentlyAddedRunning; + int m_cumulativeUpdateFlag; ++ ++ CThread *m_ledthread; ++ CEvent *m_ledevent; + }; +--- a/xbmc/windows/readpng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.c 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,274 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.c ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#include ++#include ++ ++#include "png.h" /* libpng header; includes zlib.h */ ++#include "readpng.h" /* typedefs, common macros, public prototypes */ ++ ++ ++static png_structp png_ptr = NULL; ++static png_infop info_ptr = NULL; ++ ++png_uint_32 width, height; ++int bit_depth, color_type; ++uch *image_data = NULL; ++ ++ ++void readpng_version_info(void) ++{ ++ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", ++ PNG_LIBPNG_VER_STRING, png_libpng_ver); ++} ++ ++ ++/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) ++{ ++ uch sig[8]; ++ ++ ++ /* first do a quick check that the file really is a PNG image; could ++ * have used slightly more general png_sig_cmp() function instead */ ++ ++ fread(sig, 1, 8, infile); ++ if(png_sig_cmp(sig, 0, 8)) ++ return 1; /* bad signature */ ++ ++ ++ /* could pass pointers to user-defined error handlers instead of NULLs: */ ++ ++ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ++ if (!png_ptr) ++ return 4; /* out of memory */ ++ ++ info_ptr = png_create_info_struct(png_ptr); ++ if (!info_ptr) { ++ png_destroy_read_struct(&png_ptr, NULL, NULL); ++ return 4; /* out of memory */ ++ } ++ ++ ++ /* we could create a second info struct here (end_info), but it's only ++ * useful if we want to keep pre- and post-IDAT chunk info separated ++ * (mainly for PNG-aware image editors and converters) */ ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ png_init_io(png_ptr, infile); ++ png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ ++ ++ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ ++ ++ ++ /* alternatively, could make separate calls to png_get_image_width(), ++ * etc., but want bit_depth and color_type for later [don't care about ++ * compression_type and filter_type => NULLs] */ ++ ++ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, ++ NULL, NULL, NULL); ++ *pWidth = width; ++ *pHeight = height; ++ ++ ++ /* OK, that's all we need for now; return happy */ ++ ++ return 0; ++} ++ ++ ++ ++ ++/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; ++ * scales values to 8-bit if necessary */ ++ ++int readpng_get_bgcolor(uch *red, uch *green, uch *blue) ++{ ++ png_color_16p pBackground; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) ++ return 1; ++ ++ /* it is not obvious from the libpng documentation, but this function ++ * takes a pointer to a pointer, and it always returns valid red, green ++ * and blue values, regardless of color_type: */ ++ ++ png_get_bKGD(png_ptr, info_ptr, &pBackground); ++ ++ ++ /* however, it always returns the raw bKGD data, regardless of any ++ * bit-depth transformations, so check depth and adjust if necessary */ ++ ++ if (bit_depth == 16) { ++ *red = pBackground->red >> 8; ++ *green = pBackground->green >> 8; ++ *blue = pBackground->blue >> 8; ++ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { ++ if (bit_depth == 1) ++ *red = *green = *blue = pBackground->gray? 255 : 0; ++ else if (bit_depth == 2) ++ *red = *green = *blue = (255/3) * pBackground->gray; ++ else /* bit_depth == 4 */ ++ *red = *green = *blue = (255/15) * pBackground->gray; ++ } else { ++ *red = (uch)pBackground->red; ++ *green = (uch)pBackground->green; ++ *blue = (uch)pBackground->blue; ++ } ++ ++ return 0; ++} ++ ++ ++ ++ ++/* display_exponent == LUT_exponent * CRT_exponent */ ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) ++{ ++ double gamma; ++ png_uint_32 i, rowbytes; ++ png_bytepp row_pointers = NULL; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ ++ ++ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, ++ * transparency chunks to full alpha channel; strip 16-bit-per-sample ++ * images to 8 bits per sample; and convert grayscale to RGB[A] */ ++ ++ if (color_type == PNG_COLOR_TYPE_PALETTE) ++ png_set_expand(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) ++ png_set_expand(png_ptr); ++ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) ++ png_set_expand(png_ptr); ++ if (bit_depth == 16) ++ png_set_strip_16(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY || ++ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ++ png_set_gray_to_rgb(png_ptr); ++ ++ ++ /* unlike the example in the libpng documentation, we have *no* idea where ++ * this file may have come from--so if it doesn't have a file gamma, don't ++ * do any correction ("do no harm") */ ++ ++ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) ++ png_set_gamma(png_ptr, display_exponent, gamma); ++ ++ ++ /* all transformations have been registered; now update info_ptr data, ++ * get rowbytes and channels, and allocate image memory */ ++ ++ png_read_update_info(png_ptr, info_ptr); ++ ++ *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); ++ *pChannels = (int)png_get_channels(png_ptr, info_ptr); ++ ++ if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ free(image_data); ++ image_data = NULL; ++ return NULL; ++ } ++ ++ Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height)); ++ ++ ++ /* set the individual row_pointers to point at the correct offsets */ ++ ++ for (i = 0; i < height; ++i) ++ row_pointers[i] = image_data + i*rowbytes; ++ ++ ++ /* now we can go ahead and just read the whole image */ ++ ++ png_read_image(png_ptr, row_pointers); ++ ++ ++ /* and we're done! (png_read_end() can be omitted if no processing of ++ * post-IDAT text/time/etc. is desired) */ ++ ++ free(row_pointers); ++ row_pointers = NULL; ++ ++ png_read_end(png_ptr, NULL); ++ ++ return image_data; ++} ++ ++ ++void readpng_cleanup(int free_image_data) ++{ ++ if (free_image_data && image_data) { ++ free(image_data); ++ image_data = NULL; ++ } ++ ++ if (png_ptr && info_ptr) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ png_ptr = NULL; ++ info_ptr = NULL; ++ } ++} ++ +--- a/xbmc/windows/readpng.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.h 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,65 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.h ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#ifndef TRUE ++# define TRUE 1 ++# define FALSE 0 ++#endif ++ ++#ifndef MAX ++# define MAX(a,b) ((a) > (b)? (a) : (b)) ++# define MIN(a,b) ((a) < (b)? (a) : (b)) ++#endif ++ ++#ifdef DEBUG ++# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} ++#else ++# define Trace(x) ; ++#endif ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++ ++/* prototypes for public functions in readpng.c */ ++ ++void readpng_version_info(void); ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); ++ ++int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ++ ulg *pRowbytes); ++ ++void readpng_cleanup(int free_image_data); ++ diff --git a/projects/RPi/devices/Slice/patches/kodi/kodi-003-slice-audio.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-003-slice-audio.patch new file mode 100644 index 0000000000..839cdaeee1 --- /dev/null +++ b/projects/RPi/devices/Slice/patches/kodi/kodi-003-slice-audio.patch @@ -0,0 +1,18 @@ +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-09-17 16:35:20.000000000 +0100 ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-10-01 19:26:40.470553260 +0100 +@@ -527,6 +527,7 @@ + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); + ++#if 0 + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); + m_info.m_streamTypes.clear(); +@@ -548,6 +549,7 @@ + + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); ++#endif + + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); diff --git a/projects/RPi/devices/Slice/patches/kodi/kodi-004-keyboard.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-004-keyboard.patch new file mode 100644 index 0000000000..05158c998a --- /dev/null +++ b/projects/RPi/devices/Slice/patches/kodi/kodi-004-keyboard.patch @@ -0,0 +1,22 @@ +--- a/system/keymaps/keyboard.xml 2016-09-17 16:35:20.000000000 +0100 ++++ b/system/keymaps/keyboard.xml 2016-10-01 19:31:07.928719606 +0100 +@@ -56,7 +56,7 @@ +

Menu + ContextMenu + Menu +- Pause ++ PlayPause + Stop + SkipNext + SkipPrevious +@@ -321,8 +321,8 @@ + NextSubtitle + StepBack + StepForward +- ChapterOrBigStepForward +- ChapterOrBigStepBack ++ VolumeUp ++ VolumeDown + AudioNextLanguage + NextSubtitle + AudioDelay diff --git a/projects/RPi/devices/Slice/patches/kodi/kodi-005-cmake.patch b/projects/RPi/devices/Slice/patches/kodi/kodi-005-cmake.patch new file mode 100644 index 0000000000..81e238bd44 --- /dev/null +++ b/projects/RPi/devices/Slice/patches/kodi/kodi-005-cmake.patch @@ -0,0 +1,31 @@ +diff --git a/xbmc/windows/CMakeLists.txt b/xbmc/windows/CMakeLists.txt +index 3700602..c75f78f 100644 +--- a/xbmc/windows/CMakeLists.txt ++++ b/xbmc/windows/CMakeLists.txt +@@ -1,3 +1,5 @@ ++find_package(PNG REQUIRED) ++ + set(SOURCES GUIMediaWindow.cpp + GUIWindowDebugInfo.cpp + GUIWindowFileManager.cpp +@@ -9,7 +11,8 @@ set(SOURCES GUIMediaWindow.cpp + GUIWindowSplash.cpp + GUIWindowStartup.cpp + GUIWindowSystemInfo.cpp +- GUIWindowWeather.cpp) ++ GUIWindowWeather.cpp ++ readpng.c) + + set(HEADERS GUIMediaWindow.h + GUIWindowDebugInfo.h +@@ -22,6 +25,9 @@ set(HEADERS GUIMediaWindow.h + GUIWindowSplash.h + GUIWindowStartup.h + GUIWindowSystemInfo.h +- GUIWindowWeather.h) ++ GUIWindowWeather.h ++ readpng.h) + + core_add_library(windows) ++ ++target_link_libraries(windows PRIVATE ${PNG_LIBRARIES}) From b61dbfd9bc8534a9540af07c662dfebcae897115 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:20 -0700 Subject: [PATCH 7/9] RPi: add device Slice3 --- .../RPi/devices/RPi2/linux/linux.arm.conf | 4 +- .../devices/Slice3/config/distroconfig.txt | 23 + .../RPi/devices/Slice3/config/dt-blob.bin | Bin 0 -> 4451 bytes .../RPi/devices/Slice3/config/dt-blob.dts | 98 +++ .../devices/Slice3/config/slice-overlay.dts | 172 +++++ .../devices/Slice3/config/ws2812-overlay.dts | 33 + .../Slice3/filesystem/usr/config/autostart.sh | 2 + .../Slice3/filesystem/usr/config/shutdown.sh | 23 + .../usr/share/alsa/cards/snd_slice.conf | 25 + .../RPi/devices/Slice3/linux/linux.arm.conf | 1 + projects/RPi/devices/Slice3/options | 2 + .../patches/kodi/kodi-002-slice-led.patch | 677 ++++++++++++++++++ .../patches/kodi/kodi-003-slice-audio.patch | 18 + .../patches/kodi/kodi-004-keyboard.patch | 22 + .../Slice3/patches/kodi/kodi-005-cmake.patch | 31 + 15 files changed, 1130 insertions(+), 1 deletion(-) create mode 100644 projects/RPi/devices/Slice3/config/distroconfig.txt create mode 100644 projects/RPi/devices/Slice3/config/dt-blob.bin create mode 100644 projects/RPi/devices/Slice3/config/dt-blob.dts create mode 100644 projects/RPi/devices/Slice3/config/slice-overlay.dts create mode 100644 projects/RPi/devices/Slice3/config/ws2812-overlay.dts create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh create mode 100644 projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf create mode 120000 projects/RPi/devices/Slice3/linux/linux.arm.conf create mode 100644 projects/RPi/devices/Slice3/options create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch create mode 100644 projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch diff --git a/projects/RPi/devices/RPi2/linux/linux.arm.conf b/projects/RPi/devices/RPi2/linux/linux.arm.conf index b8558ec8f7..fd7c596edf 100644 --- a/projects/RPi/devices/RPi2/linux/linux.arm.conf +++ b/projects/RPi/devices/RPi2/linux/linux.arm.conf @@ -1158,6 +1158,7 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 # # CONFIG_SENSORS_LIS3LV02D is not set CONFIG_BCM2835_SMI=m +CONFIG_BCM2835_WS2812=m # CONFIG_AD525X_DPOT is not set # CONFIG_DUMMY_IRQ is not set # CONFIG_ICS932S401 is not set @@ -2893,6 +2894,7 @@ CONFIG_SND_BCM2708_SOC_JUSTBOOM_DIGI=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DAC=m CONFIG_SND_BCM2708_SOC_IQAUDIO_DIGI=m CONFIG_SND_BCM2708_SOC_RASPIDAC3=m +CONFIG_SND_BCM2708_SOC_SLICE=m CONFIG_SND_BCM2708_SOC_ADAU1977_ADC=m CONFIG_SND_AUDIOINJECTOR_PI_SOUNDCARD=m CONFIG_SND_AUDIOINJECTOR_OCTO_SOUNDCARD=m @@ -2946,7 +2948,7 @@ CONFIG_SND_SOC_ADAU7002=m # CONFIG_SND_SOC_CS42L52 is not set # CONFIG_SND_SOC_CS42L56 is not set # CONFIG_SND_SOC_CS42L73 is not set -# CONFIG_SND_SOC_CS4265 is not set +CONFIG_SND_SOC_CS4265=m # CONFIG_SND_SOC_CS4270 is not set # CONFIG_SND_SOC_CS4271_I2C is not set # CONFIG_SND_SOC_CS4271_SPI is not set diff --git a/projects/RPi/devices/Slice3/config/distroconfig.txt b/projects/RPi/devices/Slice3/config/distroconfig.txt new file mode 100644 index 0000000000..6473369b91 --- /dev/null +++ b/projects/RPi/devices/Slice3/config/distroconfig.txt @@ -0,0 +1,23 @@ +################################################################################ +# This file is part of LibreELEC - http://www.libreelec.tv +# Copyright (C) 2016 Team LibreELEC +# +# LibreELEC 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. +# +# LibreELEC 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 LibreELEC. If not, see . +################################################################################ + +# WARNING: DO NOT EDIT THIS FILE - IT WILL BE OVERWRITTEN WHEN UPGRADING! + +dtoverlay=slice +dtoverlay=ws2812 +dtoverlay=mmc diff --git a/projects/RPi/devices/Slice3/config/dt-blob.bin b/projects/RPi/devices/Slice3/config/dt-blob.bin new file mode 100644 index 0000000000000000000000000000000000000000..6958aae3943678be8f617a845b6a62ebfee6bac0 GIT binary patch literal 4451 zcmcJT>u%F96vtie$b6|+EPyESn85dE8kAnvc4Tl-78DoYfBx_30L`Xd27@y<0~`w3YwxiS7;SD zmRbdmrB(rCsZ|hZZ9Ir%5;khw@4-mcML;nexkzF;GgbbLo-*VjYZ!t=wmbUm6B>TpbHH!N(SNJk@EqPvfh2Uw3spSZIxm7ssG$ zQ4DYJ`v!hHU=lg)JIcip%)`AvOOIJa`arr=tgD`(~A-fr(BZ6EYc zjt;uCb#l^b?{#+ZCAiQp#^*bBDOn^2J{sXdJM!1Y0$dAqG`p=nJ^I{N&$JIN3Vl3X z;-k~+wP~l{df)Bj{TSMU=laFA9QO{7>G5t0ovhQA=Y>An-F1DunEAlAsP=e%;GNMa zlgSyqrpnF3FFo`)AJ2XA_y?Bfn&yYYcK1_u&BJluuYJF4&fZJwz`Py?{vhJ=ioj4$ z;7A(xDdVgY|vfO#0bkZX7Dr7{&ldmiyqlkSYe*vdF Bm>B>7 literal 0 HcmV?d00001 diff --git a/projects/RPi/devices/Slice3/config/dt-blob.dts b/projects/RPi/devices/Slice3/config/dt-blob.dts new file mode 100644 index 0000000000..938b72fa2c --- /dev/null +++ b/projects/RPi/devices/Slice3/config/dt-blob.dts @@ -0,0 +1,98 @@ +/dts-v1/; + +/ { + videocore { + + pins_cm3 { + + pin_config { + + pin@default { + polarity = "active_high"; + termination = "pull_down"; + startup_state = "inactive"; + function = "input"; + }; // pin + + // BANK 0 // + pin@p0 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p1 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p2 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p3 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p4 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p5 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p6 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p7 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p8 { function = "input"; termination = "pull_up"; }; // NOT USED (DEFAULT STATE) + pin@p9 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p10 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p11 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p12 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p13 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p14 { function = "uart0"; termination = "no_pulling"; }; // UART0_TX + pin@p15 { function = "uart0"; termination = "pull_up"; }; // UART0_RX + pin@p16 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p17 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p18 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p19 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p20 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p21 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p22 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p23 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p24 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p25 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p26 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + pin@p27 { function = "input"; termination = "pull_down"; }; // NOT USED (DEFAULT STATE) + + // BANK 1 // + pin@p28 { function = "pcm"; termination = "no_pulling"; }; // PCM_CLK + pin@p29 { function = "pcm"; termination = "no_pulling"; }; // PCM_FS + pin@p30 { function = "pcm"; termination = "no_pulling"; }; // PCM_DIN + pin@p31 { function = "pcm"; termination = "no_pulling"; }; // PCM_DOUT + pin@p32 { function = "gp_clk"; termination = "no_pulling"; }; // PCM_MCLK (GPCLK0) + pin@p33 { function = "output"; termination = "no_pulling"; polarity = "active_low"; startup_state = "inactive"; }; // AUD_RST_N + pin@p34 { function = "input"; termination = "pull_up"; }; // NOT USED + pin@p35 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "active"; }; // USB_ON + pin@p36 { function = "input"; termination = "no_pulling"; }; // RTC_IRQ + pin@p37 { function = "input"; termination = "no_pulling"; }; // IR_RX + pin@p38 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // STBY_LED + pin@p39 { function = "output"; termination = "no_pulling"; polarity = "active_high"; startup_state = "inactive"; }; // DISK_OFF + pin@p40 { function = "pwm"; termination = "no_pulling"; }; // LED_PWM + pin@p41 { function = "output"; termination = "no_pulling"; }; // LAN_RUN + pin@p42 { function = "gp_clk"; termination = "no_pulling"; }; // ETH_CLK (GPCLK1) + pin@p43 { function = "output"; termination = "pull_down"; polarity = "active_high"; startup_state = "inactive"; }; // LEDS_ON + pin@p44 { function = "i2c1"; termination = "no_pulling"; }; // SDA1 + pin@p45 { function = "i2c1"; termination = "no_pulling"; }; // SCL1 + + // BANK 2 // + pin@p46 { function = "input"; termination = "pull_up"; }; // SMPS_SCL + pin@p47 { function = "input"; termination = "pull_up"; }; // SMPS_SDA + pin@p48 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CLK + pin@p49 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD CMD + pin@p50 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D0 + pin@p51 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D1 + pin@p52 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D2 + pin@p53 { function = "sdcard"; termination = "pull_up"; drive_strength_mA = <8>; }; // SD D3 + pin@p128 { function = "input"; termination = "no_pulling"; polarity = "active_low"; }; // Hotplug + pin@p129 { function = "output"; termination = "no_pulling"; polarity = "active_low"; }; // EMMC_ENABLE_N + + + }; // pin_config + + pin_defines { + pin_define@HDMI_CONTROL_ATTACHED { type = "external"; number = <0>; }; // HPD_N on external gpio + pin_define@LAN_RUN { type = "internal"; number = <41>; }; // LAN_RUN + pin_define@EMMC_ENABLE { type = "external"; number = <1>; }; + pin_define@SMPS_SDA { type = "internal"; number = <46>; }; + pin_define@SMPS_SCL { type = "internal"; number = <47>; }; + }; // pin_defines + + }; // pins_cm + + clock_setup { + clock@PWM { freq = < 2400000>; }; // LEDS PWM CLOCK + clock@GPCLK1 { freq = <25000000>; }; // ETH_CLK + }; // clock_setup + + }; // videocore +}; diff --git a/projects/RPi/devices/Slice3/config/slice-overlay.dts b/projects/RPi/devices/Slice3/config/slice-overlay.dts new file mode 100644 index 0000000000..7f0a4d2f3b --- /dev/null +++ b/projects/RPi/devices/Slice3/config/slice-overlay.dts @@ -0,0 +1,172 @@ +// Definitions for Slice hardware +/dts-v1/; +/plugin/; + +#include "dt-bindings/clock/bcm2835.h" + +/ { + compatible = "brcm,bcm2708"; + + // + // Set up GPIOs: + // I2C1 on GPIO44,45 + // LIRC input/output on GPIO4 and 37 (NB GPIO4 NC on Slice) + // I2S on GPIO28-31 + // + fragment@0 { + target = <&gpio>; + __overlay__ { + i2c1_pins: i2c1 { + brcm,pins = <44 45>; + brcm,function = <6>; /* alt2 */ + }; + lirc_pins: lirc_pins { + brcm,pins = <4 37>; // + brcm,function = <1 0>; // out in + brcm,pull = <0 1>; // off down + }; + i2s_pins: i2s { + brcm,pins = <28 29 30 31>; + brcm,function = <6>; /* alt2 */ + }; + ws2812_pins: ws2812 { + brcm,pins = <40>; + brcm,function = <4>; /* alt0 */ + }; + }; + }; + + // + // I2C at 100KHz + // + fragment@1 { + target = <&i2c1>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; + clock-frequency = <100000>; + }; + }; + + // + // Add devices to I2C1 Bus: + // PCF8523 RTC device + // CS4265 Audio CODEC + // + fragment@2 { + target = <&i2c1>; + __overlay__ { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + pcf8523@68 { + compatible = "nxp,pcf8523"; + reg = <0x68>; + nxp,xtalcap-7pf; /* set crystal load to 7pf */ + status = "okay"; + }; + cs4265@4e { + #sound-dai-cells = <0>; + compatible = "cirrus,cs4265"; + reg = <0x4e>; + cs4265-reset-gpios = <&gpio 33 0>; /* AUD_RST_N on GPIO33 */ + cirrus,no-s16le; /* remove S16LE support to workaround I2S controller issue */ + status = "okay"; + }; + }; + }; + + // + // LIRC + // + fragment@3 { + target-path = "/"; + __overlay__ { + lirc_rpi: lirc_rpi { + compatible = "rpi,lirc-rpi"; + pinctrl-names = "default"; + pinctrl-0 = <&lirc_pins>; + status = "okay"; + + // Override autodetection of IR receiver circuit + // (0 = active high, 1 = active low, -1 = no override ) + rpi,sense = <0xffffffff>; + + // Software carrier + // (0 = off, 1 = on) + rpi,softcarrier = <1>; + + // Invert output + // (0 = off, 1 = on) + rpi,invert = <0>; + + // Enable debugging messages + // (0 = off, 1 = on) + rpi,debug = <0>; + }; + }; + }; + + // + // Audio driver + // + fragment@4 { + #address-cells = <1>; + #size-cells = <1>; + target = <&sound>; + __overlay__ { + compatible = "fiveninjas,slice"; + clocks = <&cprman BCM2835_CLOCK_GP0>; + clock-names = "gp0"; + pinctrl-names = "default"; + i2s-controller = <&i2s>; + status = "okay"; + }; + }; + + // + // Enable I2S + // + fragment@5 { + target = <&i2s>; + __overlay__ { + pinctrl-names = "default"; + pinctrl-0 = <&i2s_pins>; + brcm,enable-mmap; + status = "okay"; + }; + }; + + // + // WS2812B LEDs driver + // + fragment@6 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + ws2812: ws2812 { + compatible = "rpi,ws2812"; + pinctrl-names = "default"; + pinctrl-0 = <&ws2812_pins>; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + rpi,invert = <1>; + rpi,num_leds = <25>; + status = "okay"; + }; + }; + }; + + // + // Disable standard audio + // + fragment@7 { + target = <&audio>; + __overlay__ { + status = "disabled"; + }; + }; +}; diff --git a/projects/RPi/devices/Slice3/config/ws2812-overlay.dts b/projects/RPi/devices/Slice3/config/ws2812-overlay.dts new file mode 100644 index 0000000000..42cde9d73b --- /dev/null +++ b/projects/RPi/devices/Slice3/config/ws2812-overlay.dts @@ -0,0 +1,33 @@ +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2708"; + + fragment@0 { + target = <&soc>; + __overlay__ { + #address-cells = <1>; + #size-cells = <1>; + + ws2812: ws2812 { + compatible = "rpi,ws2812"; + reg = <0x7e20c000 0x100>; /* PWM */ + dmas = <&dma 5>; + dma-names = "pwm_dma"; + led-en-gpios = <&gpio 43 0>; + + rpi,invert = <1>; + rpi,num_leds = <25>; + + status = "okay"; + + }; + }; + }; + + __overrides__ { + invert = <&ws2812>,"rpi,invert:0"; + num_leds = <&ws2812>,"rpi,num_leds:0"; + }; +}; diff --git a/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh b/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh new file mode 100644 index 0000000000..0b6166972b --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/config/autostart.sh @@ -0,0 +1,2 @@ +#!/bin/bash +hdparm -S60 /dev/sda diff --git a/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh b/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh new file mode 100644 index 0000000000..ebd32374e6 --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/config/shutdown.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ -f /storage/.kodi/media/ledpatterns/shutdown.png ]; then + LEDDIR=/storage/.kodi +else + LEDDIR=/usr/share/kodi +fi + +case "$1" in + halt) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + poweroff) + hdparm -y /dev/sda + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + reboot) + led_png $LEDDIR/media/ledpatterns/shutdown.png + ;; + *) + ;; +esac diff --git a/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf b/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf new file mode 100644 index 0000000000..298f43d8e7 --- /dev/null +++ b/projects/RPi/devices/Slice3/filesystem/usr/share/alsa/cards/snd_slice.conf @@ -0,0 +1,25 @@ + + +snd_slice.pcm.iec958.0 { + @args [ CARD AES0 AES1 AES2 AES3 ] + @args.CARD { + type string + } + @args.AES0 { + type integer + } + @args.AES1 { + type integer + } + @args.AES2 { + type integer + } + @args.AES3 { + type integer + } + type hooks + slave.pcm { + type hw + card $CARD + } +} diff --git a/projects/RPi/devices/Slice3/linux/linux.arm.conf b/projects/RPi/devices/Slice3/linux/linux.arm.conf new file mode 120000 index 0000000000..bbe61a7104 --- /dev/null +++ b/projects/RPi/devices/Slice3/linux/linux.arm.conf @@ -0,0 +1 @@ +../../RPi2/linux/linux.arm.conf \ No newline at end of file diff --git a/projects/RPi/devices/Slice3/options b/projects/RPi/devices/Slice3/options new file mode 100644 index 0000000000..a2566ab649 --- /dev/null +++ b/projects/RPi/devices/Slice3/options @@ -0,0 +1,2 @@ + # Additional kernel make parameters + KERNEL_MAKE_EXTRACMD+=" dt-blob.dtb overlays/slice.dtbo overlays/ws2812.dtbo" diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch new file mode 100644 index 0000000000..6ba4cfb403 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-002-slice-led.patch @@ -0,0 +1,677 @@ +--- a/xbmc/windows/GUIWindowHome.cpp 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.cpp 2016-10-01 19:22:20.908566550 +0100 +@@ -30,9 +30,245 @@ + #include "guilib/GUIWindowManager.h" + #include "Application.h" + #include "utils/StringUtils.h" ++extern "C" ++{ ++ #include "readpng.h" ++} + + using namespace ANNOUNCEMENT; + ++int g_pattern = 0; ++int g_halt = 0; ++int g_pattern_playing = 0; ++int g_speed = 30000; ++int g_repeat = 0; ++ ++enum pattern_e { ++ PAT_PLAY, PAT_PAUSE, PAT_STOP, PAT_SLEEP, PAT_WAKE, PAT_FFWD, PAT_REW, PAT_SKIPF, PAT_SKIPR, PAT_STARTUP, PAT_QUIT, PAT_NONE ++}; ++#define NUM_PATTERNS 11 ++const char *patterns[NUM_PATTERNS] = { ++ "play" , "pause", "stop", "sleep", "wake", "ffwd", "rew", "skipf", "skipr", "startup", "quit" ++}; ++ ++void on_speed_changed(const char *message, const CVariant &data) ++{ ++ int speed = data["player"]["speed"].asInteger(); ++ ++ CLog::Log(LOGDEBUG, "speed changed %d", speed); ++ ++ switch(abs(speed)) ++ { ++ case 1: g_speed = 60000; break; ++ case 2: g_speed = 40000; break; ++ case 4: g_speed = 35000; break; ++ case 8: g_speed = 30000; break; ++ case 16: g_speed = 25000; break; ++ case 32: g_speed = 15000; break; ++ } ++ ++ if(speed > 0) ++ g_pattern = PAT_FFWD; ++ else ++ g_pattern = PAT_REW; ++ ++ if(speed != 1) ++ g_repeat = 1; ++ else ++ { ++ g_repeat = 0; ++ g_pattern = PAT_NONE; ++ } ++} ++ ++void on_seek(const char *message, const CVariant &data) ++{ ++ int seek_time = data["player"]["seekoffset"]["seconds"].asInteger() + ++ data["player"]["seekoffset"]["minutes"].asInteger() * 60; ++ ++ CLog::Log(LOGDEBUG, "Seek offset = %d", seek_time); ++ if(seek_time > 0) ++ { ++ g_pattern = PAT_SKIPF; ++ } ++ else ++ { ++ g_pattern = PAT_SKIPR; ++ } ++ ++ g_repeat = 0; ++} ++ ++enum action_e { ++ ACTION_DO, ACTION_REPEAT, ACTION_FN ++ }; ++ ++enum led_state_e { ++ LED_STATE_INVALID = 0, ++ LED_STATE_IDLE, ++ LED_STATE_PLAYING, ++ LED_STATE_PAUSED, ++ LED_STATE_SLEEP ++}; ++ ++struct led_action_s { ++ const char * event_name; ++ enum action_e action; ++ enum pattern_e action_data; ++ void (*action_fn)(const char *, const CVariant &); ++ led_state_e action_state; ++} led_actions[] = { ++ { "OnPlay", ACTION_DO, PAT_PLAY, NULL, LED_STATE_PLAYING }, ++ { "OnPause", ACTION_DO, PAT_PAUSE, NULL, LED_STATE_PAUSED }, ++ { "OnStop", ACTION_DO, PAT_STOP, NULL, LED_STATE_IDLE }, ++ { "OnSpeedChanged", ACTION_FN, PAT_NONE, on_speed_changed, LED_STATE_INVALID }, ++ { "OnSeek", ACTION_FN, PAT_NONE, on_seek, LED_STATE_INVALID }, ++ { "OnScreensaverActivated", ACTION_DO, PAT_SLEEP, NULL, LED_STATE_SLEEP }, ++ { "OnScreensaverDeactivated", ACTION_DO, PAT_WAKE, NULL, LED_STATE_IDLE }, ++ { "OnQuit", ACTION_REPEAT, PAT_QUIT, NULL, LED_STATE_IDLE }, ++}; ++ ++int zeroes[25] = { 0,}; ++ ++class CLedPattern : public IRunnable ++{ ++ int m_going; ++ CEvent *m_ev; ++ struct pattern { ++ unsigned long w; ++ unsigned long h; ++ unsigned long rowbytes; ++ unsigned char * img; ++ } m_pattern[NUM_PATTERNS]; ++ ++ void open_patterns() ++ { ++ unsigned int i; ++ for(i = 0; i < sizeof(patterns)/sizeof(patterns[0]); i++) ++ { ++ FILE * fp; ++ char filename[256]; ++ int channels; ++ ++ m_pattern[i].img = NULL; ++ sprintf(filename, "/storage/.kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename , "rb"); ++ if(fp == NULL) ++ { ++ sprintf(filename, "/usr/share/kodi/media/ledpatterns/%s.png", patterns[i]); ++ fp = fopen(filename, "rb"); ++ if(fp == NULL) ++ { ++ CLog::Log(LOGDEBUG, "Unable to open file %s", filename); ++ goto drop_out; ++ } ++ } ++ ++ if(readpng_init(fp, &m_pattern[i].w, &m_pattern[i].h) != 0) ++ { ++ CLog::Log(LOGERROR, "Unable to parse png files %s", filename); ++ goto drop_out; ++ } ++ ++ m_pattern[i].img = readpng_get_image(1.0, &channels, &m_pattern[i].rowbytes); ++ if(m_pattern[i].img == NULL || channels != 4) ++ { ++ CLog::Log(LOGERROR, "Invalid png %s, width = %lu, height = %lu, channels = %d, rowbytes = %lu", ++ filename, m_pattern[i].w, m_pattern[i].h, channels, m_pattern[i].rowbytes); ++ goto drop_out; ++ } ++ ++ CLog::Log(LOGDEBUG, "Opened %s: (%lu x %lu)", filename, m_pattern[i].w, m_pattern[i].h); ++ ++drop_out: ++ if(fp) ++ fclose(fp); ++ ++ } ++ } ++ ++ void play_pattern(int pat) ++ { ++ int fd = open("/dev/ws2812", O_WRONLY, 0); ++ if(fd < 0) ++ { ++ CLog::Log(LOGERROR, "Unable to open /dev/ws2812"); ++ } ++ else ++ { ++ if(pat < PAT_NONE && m_pattern[pat].img != NULL) ++ { ++ CLog::Log(LOGDEBUG, "playing pattern"); ++ g_pattern_playing = 1; ++ do ++ { ++ unsigned char * p_line = m_pattern[pat].img; ++ unsigned int i; ++ ++ for(i = 0; i < m_pattern[pat].h; i++) ++ { ++ write(fd, p_line, m_pattern[pat].w * 4); ++ if(m_pattern[pat].w == 26) ++ { ++ int *p = (int *) (p_line + (25 * 4)); ++ usleep(*p); ++ } ++ else ++ { ++ usleep(g_speed); ++ } ++ p_line += m_pattern[pat].rowbytes; ++ // If we get the g_halt signal then stop repeating ++ // the pattern ++ if(g_halt) ++ { ++ g_halt = 0; ++ g_repeat = 0; ++ break; ++ } ++ } ++ p_line += m_pattern[pat].rowbytes; ++ } ++ while(g_repeat); ++ g_pattern_playing = 0; ++ ++ if(pat != PAT_QUIT) ++ write(fd, zeroes, sizeof(zeroes)); ++ } ++ else ++ { ++ CLog::Log(LOGDEBUG, "No img for LED pattern %d", pat); ++ } ++ close(fd); ++ } ++ } ++ ++public: ++ CLedPattern(CEvent *ev) ++ { ++ CLog::Log(LOGDEBUG, "Initialising CLedPattern"); ++ open_patterns(); ++ m_ev = ev; ++ } ++ ++ void Run() ++ { ++ m_going = 1; ++ while(m_going) ++ { ++ m_ev->Wait(); ++ CLog::Log(LOGDEBUG, "Led Pattern %d triggered", g_pattern); ++ play_pattern(g_pattern); ++ } ++ } ++ ++ void Stop() ++ { ++ m_going = 0; ++ m_ev->Set(); ++ } ++}; ++ + CGUIWindowHome::CGUIWindowHome(void) : CGUIWindow(WINDOW_HOME, "Home.xml"), + m_recentlyAddedRunning(false), + m_cumulativeUpdateFlag(0) +@@ -40,6 +276,14 @@ CGUIWindowHome::CGUIWindowHome(void) : C + m_updateRA = (Audio | Video | Totals); + m_loadType = KEEP_IN_MEMORY; + ++ m_ledevent = new CEvent(); ++ m_ledthread = new CThread(new CLedPattern(m_ledevent), "LedThread"); ++ m_ledthread->Create(); ++ g_pattern = PAT_STARTUP; ++ g_speed = 30000; ++ g_repeat = 0; ++ m_ledevent->Set(); ++ + CAnnouncementManager::GetInstance().AddAnnouncer(this); + } + +@@ -75,10 +319,49 @@ void CGUIWindowHome::OnInitWindow() + + void CGUIWindowHome::Announce(AnnouncementFlag flag, const char *sender, const char *message, const CVariant &data) + { ++ unsigned int i; + int ra_flag = 0; + + CLog::Log(LOGDEBUG, "GOT ANNOUNCEMENT, type: %i, from %s, message %s",(int)flag, sender, message); + ++ for(i = 0; i < sizeof(led_actions)/sizeof(led_actions[0]); i++) ++ { ++ if(strcmp(message, led_actions[i].event_name) == 0) ++ { ++ switch(led_actions[i].action) { ++ case ACTION_DO: ++ case ACTION_REPEAT: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = (led_actions[i].action == ACTION_DO) ? 0 : 1; ++ g_speed = 30000; ++ g_pattern = (int) led_actions[i].action_data; ++ m_ledevent->Set(); ++ break; ++ } ++ case ACTION_FN: ++ { ++ g_halt = 1; ++ while(g_pattern_playing) ++ usleep(10); ++ g_halt = 0; ++ g_repeat = 0; ++ g_speed = 30000; ++ led_actions[i].action_fn(message, data); ++ m_ledevent->Set(); ++ break; ++ } ++ default: ++ { ++ CLog::Log(LOGERROR, "Failed to execute LED action %d for event %s\n", i, led_actions[i].event_name); ++ } ++ } ++ } ++ } ++ + // we are only interested in library changes + if ((flag & (VideoLibrary | AudioLibrary)) == 0) + return; +--- a/xbmc/windows/GUIWindowHome.h 2016-09-17 16:35:22.000000000 +0100 ++++ b/xbmc/windows/GUIWindowHome.h 2016-10-01 19:34:18.585113811 +0100 +@@ -23,6 +23,8 @@ + #include "guilib/GUIWindow.h" + #include "interfaces/IAnnouncer.h" + #include "utils/Job.h" ++#include "threads/Thread.h" ++#include "threads/Event.h" + + class CVariant; + +@@ -47,4 +49,7 @@ + + bool m_recentlyAddedRunning; + int m_cumulativeUpdateFlag; ++ ++ CThread *m_ledthread; ++ CEvent *m_ledevent; + }; +--- a/xbmc/windows/readpng.c 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.c 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,274 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.c ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#include ++#include ++ ++#include "png.h" /* libpng header; includes zlib.h */ ++#include "readpng.h" /* typedefs, common macros, public prototypes */ ++ ++ ++static png_structp png_ptr = NULL; ++static png_infop info_ptr = NULL; ++ ++png_uint_32 width, height; ++int bit_depth, color_type; ++uch *image_data = NULL; ++ ++ ++void readpng_version_info(void) ++{ ++ fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", ++ PNG_LIBPNG_VER_STRING, png_libpng_ver); ++} ++ ++ ++/* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) ++{ ++ uch sig[8]; ++ ++ ++ /* first do a quick check that the file really is a PNG image; could ++ * have used slightly more general png_sig_cmp() function instead */ ++ ++ fread(sig, 1, 8, infile); ++ if(png_sig_cmp(sig, 0, 8)) ++ return 1; /* bad signature */ ++ ++ ++ /* could pass pointers to user-defined error handlers instead of NULLs: */ ++ ++ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); ++ if (!png_ptr) ++ return 4; /* out of memory */ ++ ++ info_ptr = png_create_info_struct(png_ptr); ++ if (!info_ptr) { ++ png_destroy_read_struct(&png_ptr, NULL, NULL); ++ return 4; /* out of memory */ ++ } ++ ++ ++ /* we could create a second info struct here (end_info), but it's only ++ * useful if we want to keep pre- and post-IDAT chunk info separated ++ * (mainly for PNG-aware image editors and converters) */ ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ png_init_io(png_ptr, infile); ++ png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ ++ ++ png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ ++ ++ ++ /* alternatively, could make separate calls to png_get_image_width(), ++ * etc., but want bit_depth and color_type for later [don't care about ++ * compression_type and filter_type => NULLs] */ ++ ++ png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, ++ NULL, NULL, NULL); ++ *pWidth = width; ++ *pHeight = height; ++ ++ ++ /* OK, that's all we need for now; return happy */ ++ ++ return 0; ++} ++ ++ ++ ++ ++/* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; ++ * scales values to 8-bit if necessary */ ++ ++int readpng_get_bgcolor(uch *red, uch *green, uch *blue) ++{ ++ png_color_16p pBackground; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return 2; ++ } ++ ++ ++ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) ++ return 1; ++ ++ /* it is not obvious from the libpng documentation, but this function ++ * takes a pointer to a pointer, and it always returns valid red, green ++ * and blue values, regardless of color_type: */ ++ ++ png_get_bKGD(png_ptr, info_ptr, &pBackground); ++ ++ ++ /* however, it always returns the raw bKGD data, regardless of any ++ * bit-depth transformations, so check depth and adjust if necessary */ ++ ++ if (bit_depth == 16) { ++ *red = pBackground->red >> 8; ++ *green = pBackground->green >> 8; ++ *blue = pBackground->blue >> 8; ++ } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { ++ if (bit_depth == 1) ++ *red = *green = *blue = pBackground->gray? 255 : 0; ++ else if (bit_depth == 2) ++ *red = *green = *blue = (255/3) * pBackground->gray; ++ else /* bit_depth == 4 */ ++ *red = *green = *blue = (255/15) * pBackground->gray; ++ } else { ++ *red = (uch)pBackground->red; ++ *green = (uch)pBackground->green; ++ *blue = (uch)pBackground->blue; ++ } ++ ++ return 0; ++} ++ ++ ++ ++ ++/* display_exponent == LUT_exponent * CRT_exponent */ ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) ++{ ++ double gamma; ++ png_uint_32 i, rowbytes; ++ png_bytepp row_pointers = NULL; ++ ++ ++ /* setjmp() must be called in every function that calls a PNG-reading ++ * libpng function */ ++ ++ if (setjmp(png_jmpbuf(png_ptr))) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ ++ ++ /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, ++ * transparency chunks to full alpha channel; strip 16-bit-per-sample ++ * images to 8 bits per sample; and convert grayscale to RGB[A] */ ++ ++ if (color_type == PNG_COLOR_TYPE_PALETTE) ++ png_set_expand(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) ++ png_set_expand(png_ptr); ++ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) ++ png_set_expand(png_ptr); ++ if (bit_depth == 16) ++ png_set_strip_16(png_ptr); ++ if (color_type == PNG_COLOR_TYPE_GRAY || ++ color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ++ png_set_gray_to_rgb(png_ptr); ++ ++ ++ /* unlike the example in the libpng documentation, we have *no* idea where ++ * this file may have come from--so if it doesn't have a file gamma, don't ++ * do any correction ("do no harm") */ ++ ++ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) ++ png_set_gamma(png_ptr, display_exponent, gamma); ++ ++ ++ /* all transformations have been registered; now update info_ptr data, ++ * get rowbytes and channels, and allocate image memory */ ++ ++ png_read_update_info(png_ptr, info_ptr); ++ ++ *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); ++ *pChannels = (int)png_get_channels(png_ptr, info_ptr); ++ ++ if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ return NULL; ++ } ++ if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ free(image_data); ++ image_data = NULL; ++ return NULL; ++ } ++ ++ Trace((stderr, "readpng_get_image: rowbytes = %ld, height = %ld\n", rowbytes, height)); ++ ++ ++ /* set the individual row_pointers to point at the correct offsets */ ++ ++ for (i = 0; i < height; ++i) ++ row_pointers[i] = image_data + i*rowbytes; ++ ++ ++ /* now we can go ahead and just read the whole image */ ++ ++ png_read_image(png_ptr, row_pointers); ++ ++ ++ /* and we're done! (png_read_end() can be omitted if no processing of ++ * post-IDAT text/time/etc. is desired) */ ++ ++ free(row_pointers); ++ row_pointers = NULL; ++ ++ png_read_end(png_ptr, NULL); ++ ++ return image_data; ++} ++ ++ ++void readpng_cleanup(int free_image_data) ++{ ++ if (free_image_data && image_data) { ++ free(image_data); ++ image_data = NULL; ++ } ++ ++ if (png_ptr && info_ptr) { ++ png_destroy_read_struct(&png_ptr, &info_ptr, NULL); ++ png_ptr = NULL; ++ info_ptr = NULL; ++ } ++} ++ +--- a/xbmc/windows/readpng.h 1970-01-01 00:00:00.000000000 +0000 ++++ b/xbmc/windows/readpng.h 2016-01-08 06:49:51.049652775 +0000 +@@ -0,0 +1,65 @@ ++/*--------------------------------------------------------------------------- ++ ++ rpng - simple PNG display program readpng.h ++ ++ --------------------------------------------------------------------------- ++ ++ Copyright (c) 1998-2000 Greg Roelofs. All rights reserved. ++ ++ This software is provided "as is," without warranty of any kind, ++ express or implied. In no event shall the author or contributors ++ be held liable for any damages arising in any way from the use of ++ this software. ++ ++ Permission is granted to anyone to use this software for any purpose, ++ including commercial applications, and to alter it and redistribute ++ it freely, subject to the following restrictions: ++ ++ 1. Redistributions of source code must retain the above copyright ++ notice, disclaimer, and this list of conditions. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, disclaimer, and this list of conditions in the documenta- ++ tion and/or other materials provided with the distribution. ++ 3. All advertising materials mentioning features or use of this ++ software must display the following acknowledgment: ++ ++ This product includes software developed by Greg Roelofs ++ and contributors for the book, "PNG: The Definitive Guide," ++ published by O'Reilly and Associates. ++ ++ ---------------------------------------------------------------------------*/ ++ ++#ifndef TRUE ++# define TRUE 1 ++# define FALSE 0 ++#endif ++ ++#ifndef MAX ++# define MAX(a,b) ((a) > (b)? (a) : (b)) ++# define MIN(a,b) ((a) < (b)? (a) : (b)) ++#endif ++ ++#ifdef DEBUG ++# define Trace(x) {fprintf x ; fflush(stderr); fflush(stdout);} ++#else ++# define Trace(x) ; ++#endif ++ ++typedef unsigned char uch; ++typedef unsigned short ush; ++typedef unsigned long ulg; ++ ++ ++/* prototypes for public functions in readpng.c */ ++ ++void readpng_version_info(void); ++ ++int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight); ++ ++int readpng_get_bgcolor(uch *bg_red, uch *bg_green, uch *bg_blue); ++ ++uch *readpng_get_image(double display_exponent, int *pChannels, ++ ulg *pRowbytes); ++ ++void readpng_cleanup(int free_image_data); ++ diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch new file mode 100644 index 0000000000..839cdaeee1 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-003-slice-audio.patch @@ -0,0 +1,18 @@ +--- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-09-17 16:35:20.000000000 +0100 ++++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp 2016-10-01 19:26:40.470553260 +0100 +@@ -527,6 +527,7 @@ + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); + ++#if 0 + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); + m_info.m_streamTypes.clear(); +@@ -548,6 +549,7 @@ + + m_info.m_wantsIECPassthrough = true; + list.push_back(m_info); ++#endif + + m_info.m_channels.Reset(); + m_info.m_dataFormats.clear(); diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch new file mode 100644 index 0000000000..05158c998a --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-004-keyboard.patch @@ -0,0 +1,22 @@ +--- a/system/keymaps/keyboard.xml 2016-09-17 16:35:20.000000000 +0100 ++++ b/system/keymaps/keyboard.xml 2016-10-01 19:31:07.928719606 +0100 +@@ -56,7 +56,7 @@ + Menu + ContextMenu + Menu +- Pause ++ PlayPause + Stop + SkipNext + SkipPrevious +@@ -321,8 +321,8 @@ + NextSubtitle + StepBack + StepForward +- ChapterOrBigStepForward +- ChapterOrBigStepBack ++ VolumeUp ++ VolumeDown + AudioNextLanguage + NextSubtitle + AudioDelay diff --git a/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch b/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch new file mode 100644 index 0000000000..81e238bd44 --- /dev/null +++ b/projects/RPi/devices/Slice3/patches/kodi/kodi-005-cmake.patch @@ -0,0 +1,31 @@ +diff --git a/xbmc/windows/CMakeLists.txt b/xbmc/windows/CMakeLists.txt +index 3700602..c75f78f 100644 +--- a/xbmc/windows/CMakeLists.txt ++++ b/xbmc/windows/CMakeLists.txt +@@ -1,3 +1,5 @@ ++find_package(PNG REQUIRED) ++ + set(SOURCES GUIMediaWindow.cpp + GUIWindowDebugInfo.cpp + GUIWindowFileManager.cpp +@@ -9,7 +11,8 @@ set(SOURCES GUIMediaWindow.cpp + GUIWindowSplash.cpp + GUIWindowStartup.cpp + GUIWindowSystemInfo.cpp +- GUIWindowWeather.cpp) ++ GUIWindowWeather.cpp ++ readpng.c) + + set(HEADERS GUIMediaWindow.h + GUIWindowDebugInfo.h +@@ -22,6 +25,9 @@ set(HEADERS GUIMediaWindow.h + GUIWindowSplash.h + GUIWindowStartup.h + GUIWindowSystemInfo.h +- GUIWindowWeather.h) ++ GUIWindowWeather.h ++ readpng.h) + + core_add_library(windows) ++ ++target_link_libraries(windows PRIVATE ${PNG_LIBRARIES}) From 8954bffc98181cc92da24b1885ce1fff74048323 Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 14 Mar 2017 12:06:21 -0700 Subject: [PATCH 8/9] RPi: add common slice linux patches --- .../patches/linux/linux-01-misc-Kconfig.patch | 12 + .../linux/linux-02-misc-Makefile.patch | 10 + .../RPi/patches/linux/linux-03-ws2807-c.patch | 539 ++++++++++++++++++ .../linux/linux-04-rtc-pcf8523-c.patch | 17 + .../RPi/patches/linux/linux-05-cs4265-c.patch | 20 + .../RPi/patches/linux/linux-06-slice-c.patch | 279 +++++++++ .../linux/linux-07-slice-Kconfig.patch | 17 + .../linux/linux-08-slice-Makefile.patch | 15 + 8 files changed, 909 insertions(+) create mode 100644 projects/RPi/patches/linux/linux-01-misc-Kconfig.patch create mode 100644 projects/RPi/patches/linux/linux-02-misc-Makefile.patch create mode 100644 projects/RPi/patches/linux/linux-03-ws2807-c.patch create mode 100644 projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch create mode 100644 projects/RPi/patches/linux/linux-05-cs4265-c.patch create mode 100644 projects/RPi/patches/linux/linux-06-slice-c.patch create mode 100644 projects/RPi/patches/linux/linux-07-slice-Kconfig.patch create mode 100644 projects/RPi/patches/linux/linux-08-slice-Makefile.patch diff --git a/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch b/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch new file mode 100644 index 0000000000..e30677018d --- /dev/null +++ b/projects/RPi/patches/linux/linux-01-misc-Kconfig.patch @@ -0,0 +1,12 @@ +--- a/drivers/misc/Kconfig 2016-10-01 08:57:18.219952947 +0100 ++++ b/drivers/misc/Kconfig 2016-10-01 09:18:14.792293152 +0100 +@@ -4,6 +4,9 @@ + + menu "Misc devices" + ++config BCM2835_WS2812 ++ tristate "Support DMA user access to WS2812 LEDs" ++ + config SENSORS_LIS3LV02D + tristate + depends on INPUT diff --git a/projects/RPi/patches/linux/linux-02-misc-Makefile.patch b/projects/RPi/patches/linux/linux-02-misc-Makefile.patch new file mode 100644 index 0000000000..f4ad6286bd --- /dev/null +++ b/projects/RPi/patches/linux/linux-02-misc-Makefile.patch @@ -0,0 +1,10 @@ +--- a/drivers/misc/Makefile 2016-10-01 09:14:16.810942127 +0100 ++++ b/drivers/misc/Makefile 2016-10-01 09:14:05.458686888 +0100 +@@ -2,6 +2,7 @@ + # Makefile for misc devices that really don't fit anywhere else. + # + ++obj-$(CONFIG_BCM2835_WS2812) += ws2812.o + obj-$(CONFIG_IBM_ASM) += ibmasm/ + obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o + obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o diff --git a/projects/RPi/patches/linux/linux-03-ws2807-c.patch b/projects/RPi/patches/linux/linux-03-ws2807-c.patch new file mode 100644 index 0000000000..24eedd81ae --- /dev/null +++ b/projects/RPi/patches/linux/linux-03-ws2807-c.patch @@ -0,0 +1,539 @@ +--- a/drivers/misc/ws2812.c 2016-08-17 21:00:22.264000134 +0100 ++++ b/drivers/misc/ws2812.c 2016-10-04 14:12:32.512699063 +0100 +@@ -0,0 +1,536 @@ ++/* ++ * Raspberry Pi WS2812 PWM driver ++ * ++ * Written by: Gordon Hollingworth ++ * Based on DMA PWM driver from Jonathan Bell ++ * ++ * Copyright (C) 2014 Raspberry Pi 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. ++ * ++ * To use this driver you need to make sure that the PWM clock is set to 2.4MHz ++ * and the correct PWM0 output is connected. The best way to do this is to ++ * create a dt-blob.bin on your RaspberryPi, start by downloading the default ++ * dt-blob.dts from ++ * ++ * Note, this uses the same PWM hardware as the standard audio output on the Pi ++ * so you cannot use both simultaneously. ++ * ++ * http://www.raspberrypi.org/documentation/configuration/pin-configuration.md ++ * ++ * (Copy the bit from /dts-v1/; through to the end... This will contain the pin ++ * configuration for all the Raspberry Pi versions (since they are different. ++ * You can get rid of the ones you don't care about. Next alter the PWM0 output ++ * you want to use. ++ * ++ * http://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf ++ * ++ * The link above will help understand what the GPIOs can do, check out page 102 ++ * You can use: GPIO12, GPIO18 or GPIO40, so for the Slice board we use GPIO40 so ++ * we have the following in the dts file ++ * ++ * pin@p40 { ++ * function = "pwm"; ++ * termination = "no_pulling"; ++ * }; ++ * ++ * And at the bottom of the dts file, although still in the 'videocore' block we ++ * have: ++ * ++ * clock_setup { ++ * clock@PWM { freq = <2400000>; }; ++ * }; ++ * ++ * To check whether the changes are correct you can use 'vcgencmd measure_clock 25' ++ * This should return the value 2400000 ++ * ++ * Also if you use wiringPi then you can do 'gpio readall' to check that the pin ++ * alternate setting is set correctly. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define DRIVER_NAME "ws2812" ++ ++struct ws2812_state { ++ struct device * dev; ++ struct cdev cdev; ++ struct class * cl; ++ struct dma_chan * dma_chan; ++ dma_addr_t dma_addr; ++ ++ void __iomem * ioaddr; ++ phys_addr_t phys_addr; ++ ++ uint8_t * buffer; ++ uint32_t * pixbuf; ++ ++ struct gpio_desc * led_en; ++ ++ unsigned char brightness; ++ u32 invert; ++ u32 num_leds; ++}; ++ ++#ifndef BCM2708_PERI_BASE ++ #define BCM2708_PERI_BASE 0x20000000 ++#endif ++ ++#define BCM2835_VCMMU_SHIFT (0x7E000000 - BCM2708_PERI_BASE) ++ ++/* Each LED is controlled with a 24 bit RGB value ++ * each bit is created from a nibble of data either ++ * 1000 or 1110 so to create 24 bits you need 12 bytes ++ * of PWM output ++ */ ++#define BYTES_PER_LED 12 ++ ++// Number of 2.4MHz bits in 50us to create a reset condition ++#define RESET_BYTES ((50 * 24) / 80) ++ ++#define PWM_CTL 0x0 ++#define PWM_STA 0x4 ++#define PWM_DMAC 0x8 ++#define PWM_RNG1 0x10 ++#define PWM_DAT1 0x14 ++#define PWM_FIFO1 0x18 ++#define PWM_ID 0x50 ++ ++#define PWM_DMA_DREQ 5 ++ ++static dev_t devid = MKDEV(1337, 0); ++ ++/* ++** Functions to access the pwm peripheral ++*/ ++static void pwm_writel(struct ws2812_state * state, uint32_t val, uint32_t reg) ++{ ++ writel(val, state->ioaddr + reg); ++} ++ ++#if 0 ++static uint32_t pwm_readl(struct ws2812_state * state, uint32_t reg) ++{ ++ return readl(state->ioaddr + reg); ++} ++#endif ++ ++/* Initialise the PWM module to use serial output ++ * mode ++ */ ++static int pwm_init(struct ws2812_state * state) ++{ ++ uint32_t reg; ++ ++ // serial 32 bits per word ++ pwm_writel(state, 32, PWM_RNG1); ++ // Clear ++ pwm_writel(state, 0, PWM_DAT1); ++ ++ reg = (1 << 0) | /* CH1EN */ ++ (1 << 1) | /* serialiser */ ++ (0 << 2) | /* don't repeat last word */ ++ (0 << 3) | /* silence is zero */ ++ ((state->invert ? 1 : 0) << 4) | /* polarity */ ++ (1 << 5) | /* use fifo */ ++ (1 << 6) | /* Clear fifo */ ++ (1 << 7) | /* MSEN - Mask space enable */ ++ ((state->invert ? 1 : 0) << 11); /* Silence bit = 1 */ ++ pwm_writel(state, reg, PWM_CTL); ++ reg = (1 << 31) | /* DMA enabled */ ++ (4 << 8) | /* Threshold for panic */ ++ (8 << 0); /* Threshold for dreq */ ++ pwm_writel(state, reg, PWM_DMAC); ++ ++ return 0; ++ ++} ++ ++/* ++ * DMA callback function, release the mapping and the calling function ++ */ ++void ws2812_callback(void * param) ++{ ++ struct ws2812_state * state = (struct ws2812_state *) param; ++ ++ dma_unmap_single(state->dev, state->dma_addr, state->num_leds * BYTES_PER_LED, ++ DMA_TO_DEVICE); ++ ++} ++ ++/* ++ * Issue a DMA to the PWM peripheral from the assigned buffer ++ * buffer must be unmapped again before being used ++ */ ++int issue_dma(struct ws2812_state * state, uint8_t *buffer, int length) ++{ ++ struct dma_async_tx_descriptor *desc; ++ ++ state->dma_addr = dma_map_single(state->dev, ++ buffer, length, ++ DMA_TO_DEVICE); ++ ++ if(state->dma_addr == 0) ++ { ++ pr_err("Failed to map buffer for DMA\n"); ++ return -1; ++ } ++ ++ desc = dmaengine_prep_slave_single(state->dma_chan, state->dma_addr, ++ length, DMA_TO_DEVICE, DMA_PREP_INTERRUPT); ++ if(desc == NULL) ++ { ++ pr_err("Failed to prep the DMA transfer\n"); ++ return -1; ++ } ++ ++ desc->callback = ws2812_callback; ++ desc->callback_param = state; ++ dmaengine_submit(desc); ++ dma_async_issue_pending(state->dma_chan); ++ ++ return 0; ++} ++ ++ ++int clear_leds(struct ws2812_state * state) ++{ ++ int i; ++ ++ for(i = 0; i < state->num_leds * BYTES_PER_LED; i++) ++ state->buffer[i] = 0x88; ++ for(i = 0; i < RESET_BYTES; i++) ++ state->buffer[state->num_leds * BYTES_PER_LED + i] = 0; ++ ++ issue_dma(state, state->buffer, state->num_leds * BYTES_PER_LED + RESET_BYTES); ++ ++ return 0; ++} ++ ++static int ws2812_open(struct inode *inode, struct file *file) ++{ ++ struct ws2812_state * state; ++ state = container_of(inode->i_cdev, struct ws2812_state, cdev); ++ ++ file->private_data = state; ++ ++ return 0; ++} ++ ++/* WS2812B gamma correction ++GammaE=255*(res/255).^(1/.45) ++From: http://rgb-123.com/ws2812-color-output/ ++*/ ++unsigned char gamma_(unsigned char brightness, unsigned char val) ++{ ++ int bright = val; ++ unsigned char GammaE[] = { ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, ++ 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, ++ 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, ++ 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, ++ 19, 19, 20, 21, 21, 22, 22, 23, 23, 24, 25, 25, 26, 27, 27, 28, ++ 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, ++ 40, 41, 42, 43, 44, 45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, ++ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, ++ 71, 72, 73, 74, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 88, 89, ++ 90, 91, 93, 94, 95, 96, 98, 99,100,102,103,104,106,107,109,110, ++ 111,113,114,116,117,119,120,121,123,124,126,128,129,131,132,134, ++ 135,137,138,140,142,143,145,146,148,150,151,153,155,157,158,160, ++ 162,163,165,167,169,170,172,174,176,178,179,181,183,185,187,189, ++ 191,193,194,196,198,200,202,204,206,208,210,212,214,216,218,220, ++ 222,224,227,229,231,233,235,237,239,241,244,246,248,250,252,255}; ++ bright = (bright * brightness) / 255; ++ return GammaE[bright]; ++} ++ ++// LED serial output ++// 4 bits make up a single bit of the output ++// 1 1 1 0 -- 1 ++// 1 0 0 0 -- 0 ++// ++// Plus require a space of 50 microseconds for reset ++// 24 bits per led ++// ++// (24 * 4) / 8 = 12 bytes per led ++// ++// red = 0xff0000 == 0xeeeeeeee 0x88888888 0x88888888 ++unsigned char * led_encode(struct ws2812_state * state, int rgb, unsigned char *buf) ++{ ++ int i; ++ unsigned char red = gamma_(state->brightness, rgb >> 8); ++ unsigned char blu = gamma_(state->brightness, rgb); ++ unsigned char grn = gamma_(state->brightness, rgb >> 16); ++ int rearrange = red + ++ (blu << 8) + ++ (grn << 16); ++ for(i = 11; i >= 0; i--) ++ { ++ switch(rearrange & 3) ++ { ++ case 0: *buf++ = 0x88; break; ++ case 1: *buf++ = 0x8e; break; ++ case 2: *buf++ = 0xe8; break; ++ case 3: *buf++ = 0xee; break; ++ } ++ rearrange >>= 2; ++ } ++ ++ return buf; ++} ++ ++ ++/* Write to the PWM through DMA ++ * Function to write the RGB buffer to the WS2812 leds, the input buffer ++ * contains a sequence of up to num_leds RGB32 integers, these are then ++ * converted into the nibble per bit sequence required to drive the PWM ++ */ ++ssize_t ws2812_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) ++{ ++ int32_t *p_rgb; ++ int8_t * p_buffer; ++ int i, length, num_leds; ++ struct ws2812_state * state = (struct ws2812_state *) filp->private_data; ++ ++ num_leds = min(count/4, state->num_leds); ++ ++ if(copy_from_user(state->pixbuf, buf, num_leds * 4)) ++ return -EFAULT; ++ ++ p_rgb = state->pixbuf; ++ p_buffer = state->buffer; ++ for(i = 0; i < num_leds; i++) ++ p_buffer = led_encode(state, *p_rgb++, p_buffer); ++ ++ /* Fill rest with '0' */ ++ memset(p_buffer, 0x00, RESET_BYTES); ++ ++ length = (int) p_buffer - (int) state->buffer + RESET_BYTES; ++ ++ /* Setup DMA engine */ ++ issue_dma(state, state->buffer, length); ++ ++ return count; ++} ++ ++ ++struct file_operations ws2812_fops = { ++ .owner = THIS_MODULE, ++ .llseek = NULL, ++ .read = NULL, ++ .write = ws2812_write, ++ .open = ws2812_open, ++ .release = NULL, ++}; ++ ++/* ++ * Probe function ++ */ ++static int ws2812_probe(struct platform_device *pdev) ++{ ++ int ret; ++ struct device *dev = &pdev->dev; ++ struct device_node *node = dev->of_node; ++ struct ws2812_state * state; ++ const __be32 *addr; ++ struct resource *res; ++ struct dma_slave_config cfg = ++ { ++ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, ++ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, ++ .slave_id = PWM_DMA_DREQ, ++ .direction = DMA_MEM_TO_DEV, ++ .src_addr = 0, ++ }; ++ ++ if(node == NULL) ++ { ++ pr_err("Require device tree entry\n"); ++ goto fail; ++ } ++ ++ state = kmalloc(sizeof(struct ws2812_state), GFP_KERNEL); ++ if (!state) { ++ pr_err("Can't allocate state\n"); ++ goto fail; ++ } ++ ++ state->dev = dev; ++ state->brightness = 255; ++ ++ // Create character device interface /dev/ws2812 ++ if(alloc_chrdev_region(&devid, 0, 1, "ws2812") < 0) ++ { ++ pr_err("Unable to create chrdev region"); ++ goto fail_malloc; ++ } ++ if((state->cl = class_create(THIS_MODULE, "ws2812")) == NULL) ++ { ++ unregister_chrdev_region(devid, 1); ++ pr_err("Unable to create class ws2812"); ++ goto fail_chrdev; ++ } ++ if(device_create(state->cl, NULL, devid, NULL, "ws2812") == NULL) ++ { ++ class_destroy(state->cl); ++ unregister_chrdev_region(devid, 1); ++ pr_err("Unable to create device ws2812"); ++ goto fail_class; ++ } ++ ++ state->cdev.owner = THIS_MODULE; ++ cdev_init(&state->cdev, &ws2812_fops); ++ ++ if(cdev_add(&state->cdev, devid, 1)) { ++ pr_err("CDEV failed\n"); ++ goto fail_device; ++ } ++ ++ platform_set_drvdata(pdev, state); ++ ++ /* get parameters from device tree */ ++ of_property_read_u32(node, ++ "rpi,invert", ++ &state->invert); ++ of_property_read_u32(node, ++ "rpi,num_leds", ++ &state->num_leds); ++ ++ state->pixbuf = kmalloc(state->num_leds * sizeof(int), GFP_KERNEL); ++ if(state->pixbuf == NULL) ++ { ++ pr_err("Failed to allocate internal buffer\n"); ++ goto fail_cdev; ++ } ++ ++ /* base address in dma-space */ ++ addr = of_get_address(node, 0, NULL, NULL); ++ if (!addr) { ++ dev_err(dev, "could not get DMA-register address - not using dma mode\n"); ++ goto fail_pixbuf; ++ } ++ state->phys_addr = be32_to_cpup(addr); ++ pr_err("bus_addr = 0x%x\n", state->phys_addr); ++ ++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ++ state->ioaddr = devm_ioremap_resource(&pdev->dev, res); ++ if (IS_ERR(state->ioaddr)) { ++ pr_err("Failed to get register resource\n"); ++ goto fail_pixbuf; ++ } ++ ++ pr_err("ioaddr = 0x%x\n", (int) state->ioaddr); ++ ++ state->buffer = kmalloc(state->num_leds * BYTES_PER_LED + RESET_BYTES, GFP_KERNEL); ++ if(state->buffer == NULL) ++ { ++ pr_err("Failed to allocate internal buffer\n"); ++ goto fail_pixbuf; ++ } ++ ++ state->dma_chan = dma_request_slave_channel(dev, "pwm_dma"); ++ if(state->dma_chan == NULL) ++ { ++ pr_err("Failed to request DMA channel"); ++ goto fail_buffer; ++ } ++ ++ /* request a DMA channel */ ++ cfg.dst_addr = state->phys_addr + PWM_FIFO1; ++ ret = dmaengine_slave_config(state->dma_chan, &cfg); ++ if (state->dma_chan < 0) { ++ pr_err("Can't allocate DMA channel\n"); ++ goto fail_dma_init; ++ } ++ pwm_init(state); ++ ++ // Enable the LED power ++ state->led_en = devm_gpiod_get(dev, "led-en", GPIOD_OUT_HIGH); ++ ++ clear_leds(state); ++ ++ return 0; ++fail_dma_init: ++ dma_release_channel(state->dma_chan); ++fail_buffer: ++ kfree(state->buffer); ++fail_pixbuf: ++ kfree(state->pixbuf); ++fail_cdev: ++ cdev_del(&state->cdev); ++fail_device: ++ device_destroy(state->cl, devid); ++fail_class: ++ class_destroy(state->cl); ++fail_chrdev: ++ unregister_chrdev_region(devid, 1); ++fail_malloc: ++ kfree(state); ++fail: ++ ++ return -1; ++} ++ ++ ++static int ws2812_remove(struct platform_device *pdev) ++{ ++ struct ws2812_state *state = platform_get_drvdata(pdev); ++ ++ platform_set_drvdata(pdev, NULL); ++ ++ dma_release_channel(state->dma_chan); ++ kfree(state->buffer); ++ kfree(state->pixbuf); ++ cdev_del(&state->cdev); ++ device_destroy(state->cl, devid); ++ class_destroy(state->cl); ++ unregister_chrdev_region(devid, 1); ++ kfree(state); ++ ++ return 0; ++} ++ ++static const struct of_device_id ws2812_match[] = { ++ { .compatible = "rpi,ws2812" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ws2812_match); ++ ++static struct platform_driver ws2812_driver = { ++ .probe = ws2812_probe, ++ .remove = ws2812_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ .owner = THIS_MODULE, ++ .of_match_table = ws2812_match, ++ }, ++}; ++module_platform_driver(ws2812_driver); ++ ++MODULE_ALIAS("platform:ws2812"); ++MODULE_DESCRIPTION("WS2812 PWM driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_AUTHOR("Gordon Hollingworth"); diff --git a/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch b/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch new file mode 100644 index 0000000000..da7593ed7e --- /dev/null +++ b/projects/RPi/patches/linux/linux-04-rtc-pcf8523-c.patch @@ -0,0 +1,17 @@ +--- a/drivers/rtc/rtc-pcf8523.c 2016-10-01 10:16:30.259771931 +0100 ++++ b/drivers/rtc/rtc-pcf8523.c 2016-10-01 10:21:29.762638800 +0100 +@@ -291,7 +291,13 @@ static int pcf8523_probe(struct i2c_clie + if (!pcf) + return -ENOMEM; + +- err = pcf8523_select_capacitance(client, true); ++ if (of_property_read_bool(client->dev.of_node, "nxp,xtalcap-7pf")) { ++ printk(KERN_ERR "PCF8523 - set 7pF crystal load"); ++ err = pcf8523_select_capacitance(client, false); ++ } else { ++ printk(KERN_ERR "PCF8523 - set 12pF crystal load"); ++ err = pcf8523_select_capacitance(client, true); ++ } + if (err < 0) + return err; + diff --git a/projects/RPi/patches/linux/linux-05-cs4265-c.patch b/projects/RPi/patches/linux/linux-05-cs4265-c.patch new file mode 100644 index 0000000000..51939528a9 --- /dev/null +++ b/projects/RPi/patches/linux/linux-05-cs4265-c.patch @@ -0,0 +1,20 @@ +--- linux-4.4-rc7-old/sound/soc/codecs/cs4265.c 2016-01-13 20:56:05.637652775 +0000 ++++ linux-4.4-rc7/sound/soc/codecs/cs4265.c 2016-01-17 11:21:16.977652775 +0000 +@@ -157,7 +157,7 @@ + SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2, + 3, 1, 0), + SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum), +- SOC_SINGLE("MMTLR Data Switch", 0, ++ SOC_SINGLE("MMTLR Data Switch", CS4265_SPDIF_CTL2, + 1, 1, 0), + SOC_ENUM("Mono Channel Select", spdif_mono_select_enum), + SND_SOC_BYTES("C Data Buffer", CS4265_C_DATA_BUFF, 24), +@@ -199,8 +199,6 @@ + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DIN2", NULL, 0, + SND_SOC_NOPM, 0, 0), +- SND_SOC_DAPM_AIF_IN("TXIN", NULL, 0, +- CS4265_SPDIF_CTL2, 5, 1), + + SND_SOC_DAPM_OUTPUT("LINEOUTL"), + SND_SOC_DAPM_OUTPUT("LINEOUTR"), diff --git a/projects/RPi/patches/linux/linux-06-slice-c.patch b/projects/RPi/patches/linux/linux-06-slice-c.patch new file mode 100644 index 0000000000..d2263c61bc --- /dev/null +++ b/projects/RPi/patches/linux/linux-06-slice-c.patch @@ -0,0 +1,279 @@ +--- a/sound/soc/bcm/slice.c 1969-12-31 16:00:00.000000000 -0800 ++++ b/sound/soc/bcm/slice.c 2017-02-15 14:39:20.402591342 -0800 +@@ -0,0 +1,276 @@ ++ /* ++ * ASoC Driver for Slice on-board sound ++ * ++ * Author: James Adams ++ * Based on the HifiBerry DAC driver by Florian Meier ++ * Copyright 2014 ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, but ++ * WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * General Public License for more details. ++ */ ++ ++ #include ++ #include ++ ++ #include ++ #include ++ ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ #include "../codecs/cs4265.h" ++ ++struct clk * gp0_clock; ++ ++ static int snd_slice_init(struct snd_soc_pcm_runtime *rtd) ++ { ++ return 0; ++ } ++ ++ static int snd_slice_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; ++ struct snd_soc_codec *codec = rtd->codec; ++ int err; ++ int ret; ++ unsigned int rate = params_rate(params); ++ unsigned int sysclk = 12288000; ++ ++ switch (rate) { ++ case 32000: ++ sysclk = 12288000; ++ break; ++ case 44100: ++ sysclk = 11289600; ++ break; ++ case 48000: ++ sysclk = 12288000; ++ break; ++ case 64000: ++ sysclk = 12288000; ++ break; ++ case 88200: ++ sysclk = 11289600; ++ break; ++ case 96000: ++ sysclk = 12288000; ++ break; ++ case 128000: ++ dev_err(codec->dev, ++ "Failed to set CS4265 SYSCLK, sample rate not supported in ALSA: 128000\n"); ++ break; ++ case 176400: ++ sysclk = 11289600; ++ break; ++ case 192000: ++ sysclk = 12288000; ++ break; ++ default: ++ dev_err(codec->dev, ++ "Failed to set CS4265 SYSCLK, sample rate not supported\n"); ++ break; ++ } ++ ++ // Need two frequencies: 12.288 or 11.2896MHz ++ // Source is 1,806,336,000 ++ // /4 /40 - 1128960 ++ // /7 /21 - 1228800 ++ clk_disable_unprepare(gp0_clock); ++ ++ err = clk_set_rate(gp0_clock, sysclk); ++ if(err < 0) ++ pr_err("Failed to set clock rate for gp0 clock\n"); ++ ++ if((ret = clk_prepare_enable(gp0_clock)) < 0) ++ pr_err("Failed to enable clock\n"); ++ ++ dev_err(codec->dev, "Set sampling frequency %d, using sysclk %d\n", rate, sysclk); ++ ++ err = snd_soc_dai_set_sysclk(codec_dai, 0, sysclk, ++ SND_SOC_CLOCK_OUT); ++ ++ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM); ++ ++ if (ret) { ++ dev_err(cpu_dai->dev, ++ "Failed to set the cpu dai format.\n"); ++ return ret; ++ } ++ ++ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ++ SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM); ++ if (ret) { ++ dev_err(cpu_dai->dev, ++ "Failed to set the codec format.\n"); ++ return ret; ++ } ++ ++ snd_soc_dai_set_bclk_ratio(cpu_dai, 64); ++ ++ return 0; ++ } ++ ++ static int snd_slice_params_fixup(struct snd_soc_pcm_runtime *rtd, ++ struct snd_pcm_hw_params *params) ++ { ++ printk(KERN_ERR "snd_slice_params_fixup called\n"); ++ /* force 32 bit */ ++ params_set_format(params, SNDRV_PCM_FORMAT_S32_LE); ++ return 0; ++ } ++ ++ /* machine stream operations */ ++ static struct snd_soc_ops snd_slice_ops = { ++ .hw_params = snd_slice_hw_params, ++ }; ++ ++ /* Widgets */ ++ static const struct snd_soc_dapm_widget snd_slice_dapm_widgets[] = { ++ SND_SOC_DAPM_SPK("Speaker 1", NULL), ++ SND_SOC_DAPM_SPK("Speaker 2", NULL), ++ SND_SOC_DAPM_MIC("Mic 1", NULL), ++ SND_SOC_DAPM_MIC("Mic 2", NULL), ++ SND_SOC_DAPM_MIC("LineIn 1", NULL), ++ SND_SOC_DAPM_MIC("LineIn 2", NULL), ++ SND_SOC_DAPM_SPK("Spdif", NULL), ++ }; ++ ++ /* Audio Map */ ++ static const struct snd_soc_dapm_route snd_slice_audio_map[] = { ++ {"Speaker 1", NULL, "LINEOUTL"}, ++ {"Speaker 2", NULL, "LINEOUTR"}, ++ {"MICL", NULL, "Mic 1"}, ++ {"MICR", NULL, "Mic 2"}, ++ {"LINEINL", NULL, "LineIn 1"}, ++ {"LINEINR", NULL, "LineIn 2"}, ++ {"Spdif", NULL, "SPDIF"}, ++ }; ++ ++ static const struct snd_soc_pcm_stream snd_slice_params = { ++ .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, ++ }; ++ ++ static struct snd_soc_dai_link snd_slice_dai[] = { ++ { ++ .name = "Slice", ++ .stream_name = "Slice HiFi", ++ .cpu_dai_name = "bcm2708-i2s.0", ++ .codec_dai_name = "cs4265-dai1", ++ .platform_name = "bcm2708-i2s.0", ++ .codec_name = "cs4265.1-004e", ++ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ++ SND_SOC_DAIFMT_CBM_CFM, ++ .ops = &snd_slice_ops, ++ .init = snd_slice_init, ++ .be_hw_params_fixup = snd_slice_params_fixup, ++ }, ++ }; ++ ++ /* audio machine driver */ ++ static struct snd_soc_card snd_slice = { ++ .name = "snd_slice", ++ .dai_link = snd_slice_dai, ++ .num_links = ARRAY_SIZE(snd_slice_dai), ++ .fully_routed = 1, ++ .dapm_widgets = snd_slice_dapm_widgets, ++ .num_dapm_widgets = ARRAY_SIZE(snd_slice_dapm_widgets), ++ .dapm_routes = snd_slice_audio_map, ++ .num_dapm_routes = ARRAY_SIZE(snd_slice_audio_map), ++ }; ++ ++ static int snd_slice_probe(struct platform_device *pdev) ++ { ++ int ret = 0; ++ snd_slice.dev = &pdev->dev; ++ ++ if (pdev->dev.of_node) { ++ struct device_node *i2s_node; ++ struct snd_soc_dai_link *dai = &snd_slice_dai[0]; ++ i2s_node = of_parse_phandle(pdev->dev.of_node, ++ "i2s-controller", 0); ++ ++ if (i2s_node) { ++ dai->cpu_dai_name = NULL; ++ dai->cpu_of_node = i2s_node; ++ dai->platform_name = NULL; ++ dai->platform_of_node = i2s_node; ++ } ++ } ++ else ++ { ++ printk(KERN_ERR "SLICEAUDIO - ERROR no Device Tree!\n"); ++ } ++ ++ ret = snd_soc_register_card(&snd_slice); ++ if (ret) { ++ dev_err(&pdev->dev, ++ "snd_soc_register_card() failed: %d\n", ret); ++ goto snd_soc_register_card_failed; ++ } ++ ++ gp0_clock = devm_clk_get(&pdev->dev, "gp0"); ++ if (IS_ERR(gp0_clock)) { ++ pr_err("Failed to get gp0 clock\n"); ++ return PTR_ERR(gp0_clock); ++ } ++ ++ ret = clk_set_rate(gp0_clock, 12288000); ++ if (ret) { ++ pr_err("Failed to set the GP0 clock rate\n"); ++ return ret; ++ } ++ ++ ret = clk_prepare_enable(gp0_clock); ++ if (ret) { ++ pr_err("Failed to turn on gp0 clock: %d\n", ret); ++ return ret; ++ } ++ ++ return 0; ++ ++ snd_soc_register_card_failed: ++ ++ return ret; ++ } ++ ++ static int snd_slice_remove(struct platform_device *pdev) ++ { ++ return snd_soc_unregister_card(&snd_slice); ++ } ++ ++ static const struct of_device_id slice_of_match[] = { ++ { .compatible = "fiveninjas,slice", }, ++ {}, ++ }; ++ MODULE_DEVICE_TABLE(of, slice_of_match); ++ ++ static struct platform_driver snd_slice_driver = { ++ .driver = { ++ .name = "snd-slice", ++ .owner = THIS_MODULE, ++ .of_match_table = slice_of_match, ++ }, ++ .probe = snd_slice_probe, ++ .remove = snd_slice_remove, ++ }; ++ ++ module_platform_driver(snd_slice_driver); ++ ++ MODULE_AUTHOR("James Adams "); ++ MODULE_DESCRIPTION("ASoC Driver for Slice on-board audio"); ++ MODULE_LICENSE("GPL v2"); diff --git a/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch b/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch new file mode 100644 index 0000000000..a51dfde8ca --- /dev/null +++ b/projects/RPi/patches/linux/linux-07-slice-Kconfig.patch @@ -0,0 +1,17 @@ +--- a/sound/soc/bcm/Kconfig 2016-10-24 08:46:19.034757161 +0100 ++++ b/sound/soc/bcm/Kconfig 2016-10-24 08:52:36.735342726 +0100 +@@ -131,6 +131,13 @@ config SND_BCM2708_SOC_ALLO_PIANO_DAC + help + Say Y or M if you want to add support for Allo Piano DAC. + ++config SND_BCM2708_SOC_SLICE ++ tristate "Support for Slice on-board sound" ++ depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S ++ select SND_SOC_CS4265 ++ help ++ Say Y or M if you want to add support for Slice on-board sound. ++ + config SND_PISOUND + tristate "Support for Blokas Labs pisound" + depends on SND_BCM2708_SOC_I2S || SND_BCM2835_SOC_I2S + diff --git a/projects/RPi/patches/linux/linux-08-slice-Makefile.patch b/projects/RPi/patches/linux/linux-08-slice-Makefile.patch new file mode 100644 index 0000000000..b1395c95a6 --- /dev/null +++ b/projects/RPi/patches/linux/linux-08-slice-Makefile.patch @@ -0,0 +1,15 @@ +--- a/sound/soc/bcm/Makefile 2016-10-24 08:57:16.805712924 +0100 ++++ b/sound/soc/bcm/Makefile 2016-10-24 08:59:51.541235893 +0100 +@@ -26,6 +26,7 @@ snd-soc-digidac1-soundcard-objs := digid + snd-soc-dionaudio-loco-objs := dionaudio_loco.o + snd-soc-allo-piano-dac-objs := allo-piano-dac.o + snd-soc-pisound-objs := pisound.o ++snd-soc-slice-objs := slice.o + + obj-$(CONFIG_SND_BCM2708_SOC_ADAU1977_ADC) += snd-soc-adau1977-adc.o + obj-$(CONFIG_SND_BCM2708_SOC_HIFIBERRY_DAC) += snd-soc-hifiberry-dac.o +@@ -44,3 +45,4 @@ obj-$(CONFIG_SND_DIGIDAC1_SOUNDCARD) += + obj-$(CONFIG_SND_BCM2708_SOC_DIONAUDIO_LOCO) += snd-soc-dionaudio-loco.o + obj-$(CONFIG_SND_BCM2708_SOC_ALLO_PIANO_DAC) += snd-soc-allo-piano-dac.o + obj-$(CONFIG_SND_PISOUND) += snd-soc-pisound.o ++obj-$(CONFIG_SND_BCM2708_SOC_SLICE) += snd-soc-slice.o From 750bdc7632af17114aefb8c69bdf1c6e4a4de3a3 Mon Sep 17 00:00:00 2001 From: Lukas Rusak Date: Tue, 14 Mar 2017 12:06:21 -0700 Subject: [PATCH 9/9] RPi/options: add Slice/Slice3 support --- projects/RPi/options | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/RPi/options b/projects/RPi/options index a4248b565d..0e2ee8d762 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -18,9 +18,9 @@ # arm1176jz-s arm1176jzf-s cortex-a8 cortex-a9 cortex-r4 # cortex-r4f cortex-m3 cortex-m1 xscale iwmmxt iwmmxt2 ep9312. - if [ "$DEVICE" = "RPi" ]; then + if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then TARGET_CPU="arm1176jzf-s" - elif [ "$DEVICE" = "RPi2" ]; then + elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then TARGET_CPU="cortex-a7" fi @@ -36,9 +36,9 @@ # vfpv3xd vfpv3xd-fp16 neon neon-fp16 vfpv4 vfpv4-d16 fpv4-sp-d16 # neon-vfpv4. - if [ "$DEVICE" = "RPi" ]; then + if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then TARGET_FPU="vfp" - elif [ "$DEVICE" = "RPi2" ]; then + elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then TARGET_FPU="neon-vfpv4" fi @@ -70,7 +70,7 @@ # default: default mainline kernel LINUX="default" -if [ "$DEVICE" = "RPi" ]; then +if [ "$DEVICE" = "RPi" -o "$DEVICE" = "Slice" ]; then # NOOBS supported hex versions (legacy) NOOBS_HEX="2,3,4,5,6,7,8,9,d,e,f,10,11,12,14,19,0092,0093" @@ -78,7 +78,7 @@ if [ "$DEVICE" = "RPi" ]; then # NOOBS supported model versions NOOBS_SUPPORTED_MODELS='"Pi Model","Pi Compute Module","Pi Zero"' -elif [ "$DEVICE" = "RPi2" ]; then +elif [ "$DEVICE" = "RPi2" -o "$DEVICE" = "Slice3" ]; then # NOOBS supported hex versions (legacy) NOOBS_HEX="1040,1041,2082"