diff --git a/adafruit-pitft.py b/adafruit-pitft.py index 42999a3..bd2292c 100755 --- a/adafruit-pitft.py +++ b/adafruit-pitft.py @@ -7,7 +7,7 @@ import time try: import click except ImportError: - raise RuntimeError("The library 'Click' was not found. To install, try typing: sudo pip3 install Click==7.0") + raise RuntimeError("The library 'Click' was not found. To install, try typing: sudo pip3 install Click") try: from adafruit_shell import Shell except ImportError: @@ -16,7 +16,7 @@ except ImportError: shell = Shell() shell.group = 'PITFT' -__version__ = "3.0.0" +__version__ = "3.1.1" """ This is the main configuration. Displays should be placed in the order @@ -53,7 +53,6 @@ config = [ "menulabel": "PiTFT 2.2\" no touch", "product": "2.2\" no touch", "kernel_upgrade": False, - "touchscreen": False, "overlay" : "dtoverlay=pitft22,rotate={pitftrot},speed=64000000,fps=30", "width": 320, "height": 240, @@ -118,9 +117,15 @@ dtoverlay=pitft28-capacitive,{rotation}""", "kernel_upgrade": True, "overlay_src": "overlays/minipitft13-overlay.dts", "overlay_dest": "/boot/overlays/drm-minipitft13.dtbo", - "overlay": "dtoverlay=drm-minipitft13,rotate={pitftrot}", + "overlay": "dtoverlay=drm-minipitft13,rotate={pitftrot},fps=60", "width": 240, "height": 240, + "fbcp_rotations": { + "0": "0", + "90": "1", + "180": "2", + "270": "3", + }, }, { "type": "st7789_240x320", @@ -129,10 +134,9 @@ dtoverlay=pitft28-capacitive,{rotation}""", "kernel_upgrade": True, "overlay_src": "overlays/st7789v_240x320-overlay.dts", "overlay_dest": "/boot/overlays/drm-st7789v_240x320.dtbo", - "overlay": "dtoverlay=drm-st7789v_240x320,rotate={pitftrot}", + "overlay": "dtoverlay=drm-st7789v_240x320,rotate={pitftrot},fps=30", "width": 320, "height": 240, - "rotate": False, }, { "type": "st7789_240x135", @@ -141,15 +145,53 @@ dtoverlay=pitft28-capacitive,{rotation}""", "kernel_upgrade": True, "overlay_src": "overlays/minipitft114-overlay.dts", "overlay_dest": "/boot/overlays/drm-minipitft114.dtbo", - "overlay": "dtoverlay=drm-minipitft114,rotation={pitftrot}", + "overlay": "dtoverlay=drm-minipitft114,rotate={pitftrot},fps=60", + "rotations": { + "0": None, + "90": "90", + "180": None, + "270": "270", + }, "width": 240, "height": 135, + "fbcp_rotations": { + "0": "3", + "90": "2", + "180": "1", + "270": "0", + }, + }, + { + "type": "st7789v_bonnet_240x240", + "menulabel": "TFT 1.3\" Bonnet + Joystick", + "product": "1.3\" Joystick", + "kernel_upgrade": True, + "overlay_src": "overlays/tftbonnet13-overlay.dts", + "overlay_dest": "/boot/overlays/drm-tftbonnet13.dtbo", + "overlay": "dtoverlay=drm-tftbonnet13,rotate={pitftrot},fps=60", + "width": 240, + "height": 240, + "fbcp_rotations": { + "0": "0", + "90": "1", + "180": "2", + "270": "3", + }, }, ] +# default rotations +fbcp_rotations = { + "0": "1", + "90": "0", + "180": "3", + "270": "2", +} + PITFT_ROTATIONS = ("90", "180", "270", "0") UPDATE_DB = False SYSTEMD = None +REMOVE_KERNEL_PINNING = False pitft_config = None pitftrot = None auto_reboot = None @@ -196,7 +238,7 @@ def softwareinstall(): if not shell.run_command("apt-get install -y libts0", True): if not shell.run_command("apt-get install -y tslib"): warn_exit("Apt failed to install TSLIB!") - if not shell.run_command("apt-get install -y bc fbi git python-dev python-pip python-smbus python-spidev evtest libts-bin device-tree-compiler"): + if not shell.run_command("apt-get install -y bc fbi git python3-dev python3-pip python3-smbus python3-spidev evtest libts-bin device-tree-compiler libraspberrypi-dev build-essential"): warn_exit("Apt failed to install software!") if not shell.run_command("pip3 install evdev"): warn_exit("Pip failed to install software!") @@ -219,6 +261,34 @@ def uninstall_etc_modules(): shell.pattern_replace("/etc/modules", 'fbtft_device') return True +def install_drivers(): + """Compile display driver and overlay if required""" + if "overlay_src" in pitft_config and "overlay_dest" in pitft_config: + print("Compiling Device Tree Overlay") + shell.run_command("dtc --warning no-unit_address_vs_reg -I dts -O dtb -o {dest} {src}".format(dest=pitft_config['overlay_dest'], src=pitft_config['overlay_src'])) + + if pitft_config['kernel_upgrade']: + print("############# UPGRADING KERNEL ###############") + print("Updating packages...") + if not shell.run_command("sudo apt-get update", True): + warn_exit("Apt failed to update itself!") + print("Upgrading packages...") + if not shell.run_command("sudo apt-get -y upgrade", False): + warn_exit("Apt failed to install software!") + print("Installing Kernel Headers. This may take a few minutes...") + if not shell.run_command("apt-get install -y raspberrypi-kernel-headers", True): + warn_exit("Apt failed to install software!") + if not shell.isdir("/lib/modules/{}/build".format(shell.release())): + warn_exit("Kernel was updated, but needs to be loaded. Please reboot now and re-run script!") + print("Compiling and installing display driver...") + shell.pushd("st7789_module") + if not shell.run_command("make"): + warn_exit("Apt failed to compile ST7789V drivers!") + shell.run_command("mv /lib/modules/{rel}/kernel/drivers/staging/fbtft/fb_st7789v.ko /lib/modules/{rel}/kernel/drivers/staging/fbtft/fb_st7789v.BACK".format(rel=shell.release())) + shell.run_command("mv fb_st7789v.ko /lib/modules/{rel}/kernel/drivers/staging/fbtft/fb_st7789v.ko".format(rel=shell.release())) + shell.popd() + return True + def update_configtxt(rotation_override=None): """update /boot/config.txt with appropriate values""" uninstall_bootconfigtxt() @@ -227,31 +297,8 @@ def update_configtxt(rotation_override=None): if "{pitftrot}" in overlay: rotation = str(rotation_override) if rotation_override is not None else pitftrot overlay = overlay.format(pitftrot=rotation) - if "{rotation}" in overlay and isinstance(pitft_config['rotations'], dict): + if "{rotation}" in overlay and isinstance(pitft_config['rotations'], dict) and pitft_config['rotations'][pitftrot] is not None: overlay = overlay.format(rotation=pitft_config['rotations'][pitftrot]) - if "overlay_src" in pitft_config and "overlay_dest" in pitft_config: - shell.run_command("dtc -@ -I dts -O dtb -o {dest} {src}".format(dest=pitft_config['overlay_dest'], src=pitft_config['overlay_src'])) - - print("############# UPGRADING KERNEL ###############") - print("Updating packages...") - if not shell.run_command("sudo apt-get update", True): - warn_exit("Apt failed to update itself!") - print("Upgrading packages...") - if not shell.run_command("sudo apt-get upgrade", True): - warn_exit("Apt failed to install software!") - print("Installing Kernel Headers...") - if not shell.run_command("apt-get install -y raspberrypi-kernel-headers", True): - warn_exit("Apt failed to install software!") - if not shell.isdir("/lib/modules/{}/build".format(shell.release())): - warn_exit("Kernel was updated, please reboot now and re-run script!") - shell.pushd("st7789_module") - if not shell.run_command("make -C /lib/modules/$(uname -r)/build M=$(pwd) modules"): - warn_exit("Apt failed to compile ST7789V drivers!") - shell.run_command("mv /lib/modules/{rel}/kernel/drivers/gpu/drm/tiny/mi0283qt.ko /lib/modules/{rel}/kernel/drivers/gpu/drm/tiny/mi0283qt.BACK".format(rel=shell.release())) - shell.run_command("mv /lib/modules/{rel}/kernel/drivers/staging/fbtft/fb_st7789v.ko /lib/modules/{rel}/kernel/drivers/gpu/drm/tiny/mi0283qt.BACK".format(rel=shell.release())) - shell.run_command("mv st7789v_ada.ko /lib/modules/{rel}/kernel/drivers/gpu/drm/tiny/mi0283qt.ko".format(rel=shell.release())) - shell.run_command("mv fb_st7789v.ko /lib/modules/{rel}/kernel/drivers/staging/fbtft/fb_st7789v.ko".format(rel=shell.release())) - shell.popd() shell.write_text_file("/boot/config.txt", """ # --- added by adafruit-pitft-helper {date} --- @@ -327,6 +374,7 @@ def uninstall_console(): return True def install_fbcp(): + global fbcp_rotations print("Installing cmake...") if not shell.run_command("apt-get --yes --allow-downgrades --allow-remove-essential --allow-change-held-packages install cmake", True): warn_exit("Apt failed to install software!") @@ -351,6 +399,9 @@ def install_fbcp(): shell.popd() shell.run_command("rm -rf /tmp/rpi-fbcp-master") + if "fbcp_rotations" in pitft_config: + fbcp_rotations = pitft_config['fbcp_rotations'] + # Start fbcp in the appropriate place, depending on init system: if SYSTEMD: # Add fbcp to /etc/rc.local: @@ -381,7 +432,7 @@ def install_fbcp(): shell.reconfig("/boot/config.txt", "^.*hdmi_force_hotplug.*$", "hdmi_force_hotplug=1") shell.reconfig("/boot/config.txt", "^.*hdmi_group.*$", "hdmi_group=2") shell.reconfig("/boot/config.txt", "^.*hdmi_mode.*$", "hdmi_mode=87") - shell.reconfig("/boot/config.txt", "^[^#]*dtoverlay=vc4-fkms-v3d.*$", "#dtoverlay=vc4-fkms-v3d") + shell.pattern_replace("/boot/config.txt", "^[^#]*dtoverlay=vc4-fkms-v3d.*$", "#dtoverlay=vc4-fkms-v3d") # if there's X11 installed... scale = 1 @@ -395,15 +446,19 @@ def install_fbcp(): shell.reconfig("/boot/config.txt", "^.*hdmi_cvt.*$", "hdmi_cvt={} {} 60 1 0 0 0".format(WIDTH, HEIGHT)) - if pitftrot == "90" or pitftrot == "270" or ("rotate" in pitft_config and not pitft_config['rotate']): - # dont rotate HDMI on 90 or 270 - shell.reconfig("/boot/config.txt", "^.*display_hdmi_rotate.*$", "") + try: + default_orientation = int(list(fbcp_rotations.keys())[list(fbcp_rotations.values()).index("0")]) + except ValueError: + default_orientation = 90 - if pitftrot in ("0", "180"): - display_rotate = "3" if pitftrot == "180" else "0" + if fbcp_rotations[pitftrot] == "0": + # dont rotate HDMI on default orientation + shell.reconfig("/boot/config.txt", "^.*display_hdmi_rotate.*$", "") + else: + display_rotate = fbcp_rotations[pitftrot] shell.reconfig("/boot/config.txt", "^.*display_hdmi_rotate.*$", "display_hdmi_rotate={}".format(display_rotate)) # Because we rotate HDMI we have to 'unrotate' the TFT by overriding pitftrot! - if not update_configtxt(90): + if not update_configtxt(default_orientation): shell.bail("Unable to update /boot/config.txt") return True @@ -431,7 +486,7 @@ def uninstall_fbcp(): shell.run_command("raspi-config nonint do_overscan 0") print("Configuring boot/config.txt for default HDMI") shell.reconfig("/boot/config.txt", "^.*hdmi_force_hotplug.*$", "hdmi_force_hotplug=0") - shell.reconfig("/boot/config.txt", "^.*#.*dtoverlay=vc4-fkms-v3d.*$", "dtoverlay=vc4-fkms-v3d") + shell.pattern_replace("/boot/config.txt", "^.*#.*dtoverlay=vc4-fkms-v3d.*$", "dtoverlay=vc4-fkms-v3d") shell.pattern_replace("/boot/config.txt", '^hdmi_group=2.*$') shell.pattern_replace("/boot/config.txt", '^hdmi_mode=87.*$') shell.pattern_replace("/boot/config.txt", '^hdmi_cvt=.*$') @@ -571,6 +626,18 @@ Run time of up to 5 minutes. Reboot required! )) pitftrot = PITFT_ROTATIONS[PITFT_ROTATE - 1] + if 'rotations' in pitft_config and isinstance(pitft_config['rotations'], dict) and pitftrot in pitft_config['rotations'] and pitft_config['rotations'][pitftrot] is None: + shell.bail("""Unfortunately {rotation} degrees for the {display} is not working at this time. Please +restart the script and choose a different orientation.""".format(rotation=pitftrot, display=pitft_config["menulabel"])) + + if REMOVE_KERNEL_PINNING: + # Checking if kernel is pinned + if shell.exists('/etc/apt/preferences.d/99-adafruit-pin-kernel'): + shell.warn("WARNING! Script detected your system is currently pinned to an older kernel. The pin will be removed and your system will be updated.") + if not shell.prompt("Continue?"): + shell.exit() + shell.remove('/etc/apt/preferences.d/99-adafruit-pin-kernel') + # check init system (technique borrowed from raspi-config): shell.info('Checking init system...') if shell.run_command("which systemctl", True) and shell.run_command("systemctl | grep '\-\.mount'", True): @@ -602,6 +669,11 @@ Run time of up to 5 minutes. Reboot required! if not softwareinstall(): shell.bail("Unable to install software") + if "overlay_src" in pitft_config and "overlay_dest" in pitft_config: + shell.info("Installing display drivers and device tree overlay...") + if not install_drivers(): + shell.bail("Unable to install display drivers") + shell.info("Updating /boot/config.txt...") if not update_configtxt(): shell.bail("Unable to update /boot/config.txt") diff --git a/adafruit_fanservice.py b/adafruit_fanservice.py index d5bac81..c8b1139 100644 --- a/adafruit_fanservice.py +++ b/adafruit_fanservice.py @@ -1,3 +1,5 @@ +import os + try: from adafruit_shell import Shell except ImportError: @@ -8,7 +10,17 @@ shell.group = 'ADAFRUIT' def main(): shell.clear() - print("""This script will install Adafruit + if shell.is_raspberry_pi(): + print("""This script will enable the Raspberry Pi +fan service, which will turn on an +external fan controlled by a given pin + +Operations performed include: +- Enable Fan Service + +Run time < 1 minute. Reboot required.""") + else: + print("""This script will install Adafruit fan service, which will turn on an external fan controlled by a given pin @@ -29,14 +41,20 @@ Run time < 1 minute. Reboot not required.""") shell.group = 'FAN' shell.info('Checking init system...') if shell.run_command("which systemctl", True) and shell.run_command("systemctl | grep '\-\.mount'", True): - print("Found systemd, OK!") + print("Found systemd, OK!") elif os.path.isfile("/etc/init.d/cron") and not os.path.islink("/etc/init.d/cron"): - shell.bail("Found sysvinit, but we require systemd") + shell.bail("Found sysvinit, but we require systemd") else: - shell.bail("Unrecognised init system") + shell.bail("Unrecognised init system") - shell.info('Adding adafruit_fan.service') - contents = """[Unit] + if shell.is_raspberry_pi(): + shell.info('Enabling Raspberry Pi Fan Service on GPIO 4') + shell.run_command("sudo raspi-config nonint do_fan 0 4") + shell.info('Done!') + shell.prompt_reboot() + else: + shell.info('Adding adafruit_fan.service') + contents = """[Unit] Description=Fan service for some Adafruit boards After=network.target @@ -52,14 +70,14 @@ StandardOutput=journal [Install] WantedBy=multi-user.target""" - shell.write_text_file("/etc/systemd/system/adafruit_fan.service", contents, append=False) - - shell.info('Enabling adafruit_fan.service') - shell.run_command("sudo systemctl enable adafruit_fan.service") - shell.run_command("sudo systemctl start adafruit_fan.service") - shell.info('Done!') - print("You can stop the fan service with 'sudo systemctl stop adafruit_fan.service'") - print("You can start the fan service with 'sudo systemctl start adafruit_fan.service'") + shell.write_text_file("/etc/systemd/system/adafruit_fan.service", contents, append=False) + + shell.info('Enabling adafruit_fan.service') + shell.run_command("sudo systemctl enable adafruit_fan.service") + shell.run_command("sudo systemctl start adafruit_fan.service") + shell.info('Done!') + print("You can stop the fan service with 'sudo systemctl stop adafruit_fan.service'") + print("You can start the fan service with 'sudo systemctl start adafruit_fan.service'") # Main function diff --git a/adafruit-pitft.sh b/converted_shell_scripts/adafruit-pitft.sh similarity index 100% rename from adafruit-pitft.sh rename to converted_shell_scripts/adafruit-pitft.sh diff --git a/adafruit_fanservice.sh b/converted_shell_scripts/adafruit_fanservice.sh similarity index 100% rename from adafruit_fanservice.sh rename to converted_shell_scripts/adafruit_fanservice.sh diff --git a/i2smic.sh b/converted_shell_scripts/i2smic.sh similarity index 100% rename from i2smic.sh rename to converted_shell_scripts/i2smic.sh diff --git a/i2smic.py b/i2smic.py index 8f4d93f..b6cc63c 100644 --- a/i2smic.py +++ b/i2smic.py @@ -18,7 +18,7 @@ I2S microphone support. pimodel_select = 0 elif pi_model in ("RASPBERRY_PI_2B", "RASPBERRY_PI_3B", "RASPBERRY_PI_3B_PLUS", "RASPBERRY_PI_3A_PLUS"): pimodel_select = 1 - elif pi_model in ("RASPBERRY_PI_4B", ): + elif pi_model in ("RASPBERRY_PI_4B", "RASPBERRY_PI_CM4"): pimodel_select = 2 else: shell.bail("Unsupported Pi board detected.") @@ -59,12 +59,7 @@ Installing...""") Settings take effect on next boot. """) - if not shell.prompt("REBOOT NOW?", default="n"): - print("Exiting without reboot.") - shell.exit() - print("Reboot started...") - shell.reboot() - shell.exit() + shell.prompt_reboot() # Main function if __name__ == "__main__": diff --git a/joy-bonnet.py b/joy-bonnet.py new file mode 100755 index 0000000..5aa145e --- /dev/null +++ b/joy-bonnet.py @@ -0,0 +1,114 @@ +try: + from adafruit_shell import Shell +except ImportError: + raise RuntimeError("The library 'adafruit_shell' was not found. To install, try typing: sudo pip3 install adafruit-python-shell") + +shell = Shell() +shell.group = "JOY" + +def main(): + shell.clear() + print("""This script installs software for the Adafruit +Joy Bonnet for Raspberry Pi. Steps include: +- Update package index files (apt-get update). +- Install Python libraries: smbus, evdev. +- Install joyBonnet.py in /boot and + configure /etc/rc.local to auto-start script. +- Enable I2C bus. +- OPTIONAL: disable overscan. +Run time ~10 minutes. Reboot required. +EXISTING INSTALLATION, IF ANY, WILL BE OVERWRITTEN. +""") + if not shell.prompt("CONTINUE?", default='n'): + print("Canceled.") + shell.exit() + print("Continuing...") + disable_overscan = shell.prompt("Disable overscan?", default='n') + install_halt = shell.prompt("Install GPIO-halt utility?", default='n') + if install_halt: + #halt_pin = shell.prompt("Install GPIO-halt utility?" + halt_pin = input("GPIO pin for halt: ").strip() + print("\n") + if disable_overscan: + print("Overscan: disable.") + else: + print("Overscan: keep current setting.") + + if install_halt: + print("Install GPIO-halt: YES (GPIO{})".format(halt_pin)) + else: + print("Install GPIO-halt: NO") + + if not shell.prompt("CONTINUE?", default='n'): + print("Canceled.") + shell.exit() + + # START INSTALL ------------------------------------------------------------ + # All selections are validated at this point... + + print(""" +Starting installation... +Updating package index files...""") + shell.run_command('sudo apt-get update', True) + + print("Installing Python libraries...") + shell.run_command('sudo apt-get install -y python3-pip python3-dev python3-smbus') + shell.run_command('pip3 install evdev --upgrade') + + print("Installing Adafruit code in /boot...") + shell.chdir("/tmp") + shell.run_command("curl -LO https://raw.githubusercontent.com/adafruit/Adafruit-Retrogame/master/joyBonnet.py") + # Moving between filesystems requires copy-and-delete: + shell.copy("joyBonnet.py", "/boot") + shell.remove("joyBonnet.py") + if install_halt: + print("Installing gpio-halt in /usr/local/bin...") + shell.run_command("curl -LO https://github.com/adafruit/Adafruit-GPIO-Halt/archive/master.zip") + shell.run_command("unzip -u master.zip") + shell.chdir("Adafruit-GPIO-Halt-master") + shell.run_command("make") + shell.move("gpio-halt", "/usr/local/bin") + shell.chdir("..") + shell.remove("Adafruit-GPIO-Halt-master") + + # CONFIG ------------------------------------------------------------------- + + print("Configuring system...") + + # Enable I2C using raspi-config + shell.run_command("sudo raspi-config nonint do_i2c 0") + + # Disable overscan compensation (use full screen): + if disable_overscan: + shell.run_command("sudo raspi-config nonint do_overscan 1") + + if install_halt: + if shell.pattern_search("/etc/rc.local", "gpio-halt"): + # gpio-halt already in rc.local, but make sure correct: + shell.pattern_replace("/etc/rc.local", "^.*gpio-halt.*$", "/usr/local/bin/gpio-halt {} &".format(halt_pin)) + else: + # Insert gpio-halt into rc.local before final 'exit 0' + shell.pattern_replace("/etc/rc.local", "^exit 0", "/usr/local/bin/gpio-halt {} &\\nexit 0".format(halt_pin)) + + # Auto-start joyBonnet.py on boot + if shell.pattern_search("/etc/rc.local", "joyBonnet.py"): + # joyBonnet.py already in rc.local, but make sure correct: + shell.pattern_replace("/etc/rc.local", "^.*joyBonnet.py.*$", "cd /boot;python3 joyBonnet.py &") + else: + # Insert joyBonnet.py into rc.local before final 'exit 0' + shell.pattern_replace("/etc/rc.local", "^exit 0", "cd /boot;python3 joyBonnet.py &\\nexit 0") + + # Add udev rule (will overwrite if present) + shell.write_text_file("/etc/udev/rules.d/10-retrogame.rules", "SUBSYSTEM==\"input\", ATTRS{name}==\"retrogame\", ENV{ID_INPUT_KEYBOARD}=\"1\"", append=False) + + # PROMPT FOR REBOOT -------------------------------------------------------- + print("""DONE. + +Settings take effect on next boot. +""") + shell.prompt_reboot() + +# Main function +if __name__ == "__main__": + shell.require_root() + main() diff --git a/libgpiod.py b/libgpiod.py new file mode 100755 index 0000000..d71348a --- /dev/null +++ b/libgpiod.py @@ -0,0 +1,61 @@ +# Instructions! +# cd ~ +# sudo apt-get install python3-pip +# sudo pip3 install --upgrade adafruit-python3-shell click +# wget https://raw.githubusercontent.com/adafruit/Raspberry-Pi-Installer-Scripts/master/libgpiod.py +# sudo python3 libgpiod.py + +try: + import click +except ImportError: + raise RuntimeError("The library 'Click' was not found. To install, try typing: sudo pip3 install Click==7.0") +try: + from adafruit_shell import Shell +except ImportError: + raise RuntimeError("The library 'adafruit_shell' was not found. To install, try typing: sudo pip3 install adafruit-python-shell") + +shell = Shell() +shell.group = 'LIBGPIOD' + +@click.command() +@click.option('-l', '--legacy', is_flag=True, help="Install a legacy version of libgpiod for systems with older libraries") +def main(legacy): + print("""Installing build requirements - this may take a few minutes! +""") + + # install generic linux packages required + shell.run_command("sudo apt-get update") + shell.run_command("sudo apt-get install -y autoconf autoconf-archive automake build-essential git libtool pkg-config python3-dev python3-setuptools swig3.0 wget") + + # for raspberry pi we need... + shell.run_command("sudo apt-get install -y raspberrypi-kernel-headers") + + build_dir = shell.run_command("mktemp -d /tmp/libgpiod.XXXX", return_output=True) + print("""Cloning libgpiod repository to {} +""".format(build_dir)) + + shell.chdir(build_dir) + shell.run_command("git clone git://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git .") + + if legacy: + shell.run_command("git checkout v1.4.2 -b v1.4.2") + + print("""Building libgpiod +""") + + include_path = shell.run_command("python3 -c \"from sysconfig import get_paths; print(get_paths()['include'])\"", return_output=True) + + shell.run_command("export PYTHON_VERSION=3") + shell.run_command("./autogen.sh --enable-tools=yes --prefix=/usr/local/ --enable-bindings-python CFLAGS=\"-I/{}\" && make && sudo make install && sudo ldconfig".format(include_path)) + + if shell.exists("bindings/python/.libs"): + # This is not the right way to do this, but it works + shell.run_command("sudo cp bindings/python/.libs/gpiod.so /usr/local/lib/python3.?/dist-packages/") + shell.run_command("sudo cp bindings/python/.libs/gpiod.la /usr/local/lib/python3.?/dist-packages/") + shell.run_command("sudo cp bindings/python/.libs/gpiod.a /usr/local/lib/python3.?/dist-packages/") + shell.exit() + +# Main function +if __name__ == "__main__": + shell.require_root() + main() diff --git a/overlays/minipitft114-overlay.dts b/overlays/minipitft114-overlay.dts index 5e1e7d0..1ddb4f3 100644 --- a/overlays/minipitft114-overlay.dts +++ b/overlays/minipitft114-overlay.dts @@ -1,5 +1,5 @@ /* - * Device Tree overlay for Adafruit Mini PiTFT 1.14" Display + * Device Tree overlay for Adafruit Mini PiTFT 1.14" 135x240 Display * */ @@ -7,73 +7,65 @@ /plugin/; / { - compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; - fragment@0 { - target = <&spi0>; - __overlay__ { - status = "okay"; + fragment@0 { + target = <&spi0>; + __overlay__ { + status = "okay"; - spidev@0{ - status = "disabled"; - }; + spidev@0{ + status = "disabled"; + }; - }; - }; + spidev@1{ + status = "disabled"; + }; + }; + }; - fragment@1 { - target = <&gpio>; - __overlay__ { - pitft_pins: pitft_pins { - brcm,pins = <25>; /* dc pin */ - brcm,function = <1>; /* out */ - brcm,pull = <0>; /* no pull */ - }; - }; - }; + fragment@1 { + target = <&gpio>; + __overlay__ { + pitft_pins: pitft_pins { + brcm,pins = <25>; + brcm,function = <1>; /* out */ + brcm,pull = <0>; /* none */ + }; + }; + }; - fragment@2 { - target = <&spi0>; - __overlay__ { - /* needed to avoid dtc warning */ - #address-cells = <1>; - #size-cells = <0>; + fragment@2 { + target = <&spi0>; + __overlay__ { + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; - pitft: pitft@0{ - compatible = "multi-inno,mi0283qt"; - reg = <0>; - pinctrl-names = "default"; - pinctrl-0 = <&pitft_pins>; + pitft: pitft@0{ + compatible = "sitronix,st7789v"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pitft_pins>; + spi-max-frequency = <32000000>; + rotate = <270>; + width = <135>; + height = <240>; + txbuflen = <32768>; + buswidth = <8>; + dc-gpios = <&gpio 25 0>; + led-gpios = <&gpio 26 1>; + debug = <0>; + }; + }; + }; - spi-max-frequency = <32000000>; - rotation = <90>; - width = <136>; - height = <240>; - col_offset = <53>; - row_offset = <40>; - txbuflen = <32768>; - dc-gpios = <&gpio 25 0>; - backlight = <&backlight>; - }; - }; - }; - - fragment@3 { - target-path = "/soc"; - __overlay__ { - backlight: backlight { - compatible = "gpio-backlight"; - gpios = <&gpio 22 0>; - }; - }; - }; - - __overrides__ { - speed = <&pitft>,"spi-max-frequency:0"; - rotation = <&pitft>,"rotation:0"; - width = <&pitft>,"width:0"; - height = <&pitft>,"height:0"; - col_offset = <&pitft>,"col_offset:0"; - row_offset = <&pitft>,"row_offset:0"; - }; + __overrides__ { + speed = <&pitft>,"spi-max-frequency:0"; + rotate = <&pitft>,"rotate:0"; + width = <&pitft>,"width:0"; + height = <&pitft>,"height:0"; + fps = <&pitft>,"fps:0"; + debug = <&pitft>,"debug:0"; + }; }; diff --git a/overlays/minipitft13-overlay.dts b/overlays/minipitft13-overlay.dts index fa497cb..20b1cdd 100644 --- a/overlays/minipitft13-overlay.dts +++ b/overlays/minipitft13-overlay.dts @@ -43,7 +43,7 @@ #size-cells = <0>; pitft: pitft@0{ - compatible = "sitronix,st7789v"; + compatible = "sitronix,st7789v"; reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&pitft_pins>; @@ -54,7 +54,7 @@ txbuflen = <32768>; buswidth = <8>; dc-gpios = <&gpio 25 0>; - led-gpios = <&gpio 26 0>; + led-gpios = <&gpio 26 1>; debug = <0>; }; }; diff --git a/overlays/st7789v_240x320-overlay.dts b/overlays/st7789v_240x320-overlay.dts index 1e0d6d5..9f89971 100644 --- a/overlays/st7789v_240x320-overlay.dts +++ b/overlays/st7789v_240x320-overlay.dts @@ -43,7 +43,7 @@ #size-cells = <0>; pitft: pitft@0{ - compatible = "sitronix,st7789v"; + compatible = "sitronix,st7789v"; reg = <0>; pinctrl-names = "default"; pinctrl-0 = <&pitft_pins>; @@ -54,7 +54,7 @@ txbuflen = <32768>; buswidth = <8>; dc-gpios = <&gpio 25 0>; - led-gpios = <&gpio 12 0>; + led-gpios = <&gpio 12 1>; debug = <0>; }; }; diff --git a/overlays/tftbonnet13-overlay.dts b/overlays/tftbonnet13-overlay.dts new file mode 100644 index 0000000..df2ef14 --- /dev/null +++ b/overlays/tftbonnet13-overlay.dts @@ -0,0 +1,115 @@ +/* + * Device Tree overlay for Adafruit TFT Bonnet 1.3" 240x240 Display + Joystick + * + */ + +/dts-v1/; +/plugin/; + +/ { + compatible = "brcm,bcm2835", "brcm,bcm2708", "brcm,bcm2709"; + + fragment@0 { + target = <&spi0>; + __overlay__ { + status = "okay"; + + spidev@0{ + status = "disabled"; + }; + + spidev@1{ + status = "disabled"; + }; + }; + }; + + fragment@1 { + target = <&gpio>; + __overlay__ { + pitft_pins: pitft_pins { + brcm,pins = <25>; + brcm,function = <1>; /* out */ + brcm,pull = <0>; /* none */ + }; + }; + }; + + fragment@2 { + target = <&spi0>; + __overlay__ { + /* needed to avoid dtc warning */ + #address-cells = <1>; + #size-cells = <0>; + + pitft: pitft@0{ + compatible = "sitronix,st7789v"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pitft_pins>; + spi-max-frequency = <32000000>; + rotate = <0>; + width = <240>; + height = <240>; + buswidth = <8>; + dc-gpios = <&gpio 25 0>; + led-gpios = <&gpio 26 1>; + debug = <0>; + }; + }; + }; + + fragment@3 { + target-path = "/"; + __overlay__ { + keypad: tft_bonnet_keys { + compatible = "gpio-keys"; + + button@17 { + label = "Controller Up"; + linux,code = <103>; + gpios = <&gpio 17 1>; + }; + button@22 { + label = "Controller Down"; + linux,code = <108>; + gpios = <&gpio 22 1>; + }; + button@27 { + label = "Controller Left"; + linux,code = <105>; + gpios = <&gpio 27 1>; + }; + button@23 { + label = "Controller Right"; + linux,code = <106>; + gpios = <&gpio 23 1>; + }; + button@4 { + label = "Controller Center"; + linux,code = <28>; + gpios = <&gpio 4 1>; + }; + button@5 { + label = "Controller B"; + linux,code = <48>; + gpios = <&gpio 5 1>; + }; + button@6 { + label = "Controller A"; + linux,code = <30>; + gpios = <&gpio 6 1>; + }; + }; + }; + }; + + __overrides__ { + speed = <&pitft>,"spi-max-frequency:0"; + rotate = <&pitft>,"rotate:0"; + width = <&pitft>,"width:0"; + height = <&pitft>,"height:0"; + fps = <&pitft>,"fps:0"; + debug = <&pitft>,"debug:0"; + }; +}; diff --git a/raspi-blinka.py b/raspi-blinka.py index 8310717..523516f 100644 --- a/raspi-blinka.py +++ b/raspi-blinka.py @@ -12,6 +12,7 @@ import os shell = Shell() shell.group="Blinka" default_python = 3 +blinka_minimum_python_version = 3.6 def default_python_version(numeric=True): version = shell.run_command("python -c 'import platform; print(platform.python_version())'", suppress_message=True, return_output=True) @@ -19,14 +20,26 @@ def default_python_version(numeric=True): return float(version[0:version.rfind(".")]) return version +def get_python3_version(numeric=True): + version = shell.run_command("python3 -c 'import platform; print(platform.python_version())'", suppress_message=True, return_output=True) + if numeric: + return float(version[0:version.rfind(".")]) + return version + +def check_blinka_python_version(): + """ + Check the Python 3 version for Blinka (which may be a later version than we're running this script with) + """ + print("Making sure the required version of Python is installed") + if get_python3_version() < blinka_minimum_python_version: + shell.bail("Blinka requires a minimum of Python version {} to install. Please update your OS!".format(blinka_minimum_python_version)) + def sys_update(): print("Updating System Packages") - if not shell.run_command('sudo apt update', True): - shell.bail("Apt failed to update indexes!") - if not shell.run_command('sudo apt-get update', True): + if not shell.run_command("sudo apt-get update"): shell.bail("Apt failed to update indexes!") print("Upgrading packages...") - if not shell.run_command("sudo apt-get upgrade"): + if not shell.run_command("sudo apt-get -y upgrade"): shell.bail("Apt failed to install software!") def set_raspiconfig(): @@ -61,8 +74,10 @@ def update_pip(): def install_blinka(): print("Installing latest version of Blinka locally") + shell.run_command("sudo apt-get install -y i2c-tools") + shell.run_command("pip3 install --upgrade RPi.GPIO") shell.run_command("pip3 install --upgrade adafruit-blinka") - + def main(): global default_python shell.clear() @@ -74,16 +89,19 @@ Raspberry Pi and installs Blinka print("{} detected.\n".format(pi_model)) if not shell.is_raspberry_pi(): shell.bail("Non-Raspberry Pi board detected. This must be run on a Raspberry Pi") - if shell.get_os() != "Raspbian": - shell.bail("Sorry. This script currently only runs on Raspberry Pi OS.") + os_identifier = shell.get_os() + if os_identifier != "Raspbian": + shell.bail("Sorry, the OS detected was {}. This script currently only runs on Raspberry Pi OS.".format(os_identifier)) if not shell.is_python3(): shell.bail("You must be running Python 3. Older versions have now been deprecated.") + shell.check_kernel_update_reboot_required() if default_python_version() < 3: shell.warn("WARNING Default System python version is {}. It will be updated to Version 3.".format(default_python_version(False))) default_python = 2 if not shell.prompt("Continue?"): shell.exit() sys_update() + check_blinka_python_version() set_raspiconfig() update_python() update_pip() @@ -94,13 +112,7 @@ Raspberry Pi and installs Blinka Settings take effect on next boot. """) - if not shell.prompt("REBOOT NOW?", default="y"): - print("Exiting without reboot.") - shell.exit() - print("Reboot started...") - os.sync() - shell.reboot() - shell.exit() + shell.prompt_reboot() # Main function if __name__ == "__main__": diff --git a/raspi-spi-reassign.py b/raspi-spi-reassign.py new file mode 100644 index 0000000..ae1cb24 --- /dev/null +++ b/raspi-spi-reassign.py @@ -0,0 +1,144 @@ +""" +Adafruit Raspberry Pi SPI Chip Enable Reassignment Script +(C) Adafruit Industries, Creative Commons 3.0 - Attribution Share Alike +""" + +try: + import click +except ImportError: + raise RuntimeError("The library 'Click' was not found. To install, try typing: sudo pip3 install Click") +try: + from adafruit_shell import Shell +except ImportError: + raise RuntimeError("The library 'adafruit_shell' was not found. To install, try typing: sudo pip3 install adafruit-python-shell") +import os + +shell = Shell() +shell.group="SPI Reassign" + +allowed_gpios = (4, 5, 6, 7, 8, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27) +spi0_default_pins = (8, 7) + +""" +For now this will only ask about SPI0, but we can later add SPI1 +""" + +def valid_pins(ce0_pin, ce1_pin): + if ce0_pin is None or ce1_pin is None: + return False + if ce0_pin == ce1_pin: + return False + if int(ce0_pin) not in allowed_gpios: + return False + if int(ce1_pin) not in allowed_gpios: + return False + return True + +def disable_spi(): + print("Disabling SPI") + shell.run_command("sudo raspi-config nonint do_spi 1") + +def enable_spi(): + print("Enabling SPI") + shell.run_command("sudo raspi-config nonint do_spi 0") + +def remove_custom(): + shell.pattern_replace("/boot/config.txt", 'dtoverlay=spi0-2cs,cs.*?\n', multi_line=True) + +def write_new_custom(ce0_pin, ce1_pin): + if (ce0_pin, ce1_pin) == spi0_default_pins: + enable_spi() + else: + overlay_command = "dtoverlay=spi0-2cs" + if ce0_pin != spi0_default_pins[0]: + overlay_command += ",cs0_pin={}".format(ce0_pin) + if ce1_pin != spi0_default_pins[1]: + overlay_command += ",cs1_pin={}".format(ce1_pin) + shell.write_text_file("/boot/config.txt", overlay_command + "\n") + +@click.command() +@click.option('--ce0', nargs=1, default=None, help="Specify a GPIO for CE0") +@click.option('--ce1', nargs=1, default=None, help="Specify a GPIO for CE1") +@click.option('--reboot', nargs=1, default=None, type=click.Choice(['yes', 'no']), help="Specify whether to reboot after the script is finished") +def main(ce0, ce1, reboot): + ask_reboot = True + auto_reboot = False + if reboot is not None: + ask_reboot = False + auto_reboot = reboot.lower() == 'yes' + if valid_pins(ce0, ce1): + remove_custom() + disable_spi() + write_new_custom(ce0, ce1) + if auto_reboot: + shell.reboot() + if ask_reboot: + shell.prompt_reboot() + exit(0) + else: + print("Invalid ce0 or ce1", ce0, ce1) + #shell.clear() + # Check Raspberry Pi and Bail + pi_model = shell.get_board_model() + print("""This script allows you +to easily reassign the SPI Chip Enable +pins so the OS automatic handling of the +lines doesn't interfere with CircuitPython. +Run time of < 1 minute. Reboot required for +changes to take effect! +""") + shell.info("{} detected.\n".format(pi_model)) + if not shell.is_raspberry_pi(): + shell.bail("Non-Raspberry Pi board detected. This must be run on a Raspberry Pi") + os_identifier = shell.get_os() + if os_identifier != "Raspbian": + shell.bail("Sorry, the OS detected was {}. This script currently only runs on Raspberry Pi OS.".format(os_identifier)) + menu_selection = shell.select_n( + "Select an option:", ( + "Reassign SPI Chip Enable Pins", + "Reset to Defaults Pins", + "Disable SPI", + "Exit", + ) + ) + if menu_selection == 1: + while True: + # Reassign + gpio_pool = list(allowed_gpios) + # Ask for pin for CE0 + ce0_selection = shell.select_n("Select a new GPIO for CE0", ["GPIO {}".format(x) for x in gpio_pool]) + ce0_pin = gpio_pool[ce0_selection - 1] + gpio_pool.remove(ce0_pin) + # Ask for pin for CE1 + ce1_selection = shell.select_n("Select a new GPIO for CE1", ["GPIO {}".format(x) for x in gpio_pool]) + ce1_pin = gpio_pool[ce1_selection - 1] + if shell.prompt("The new GPIO {} for CE0 and GPIO {} for CE1. Is this correct?".format(ce0_pin, ce1_pin)): + break + remove_custom() + disable_spi() + write_new_custom(ce0_pin, ce1_pin) + elif menu_selection == 2: + # Reset to Defaults + remove_custom() + enable_spi() + elif menu_selection == 3: + # Disable + remove_custom() + disable_spi() + elif menu_selection == 4: + # Exit + shell.exit(0) + # Done + print("""DONE. + +Settings take effect on next boot. +""") + if auto_reboot: + shell.reboot() + if ask_reboot: + shell.prompt_reboot() + +# Main function +if __name__ == "__main__": + shell.require_root() + main() diff --git a/rpi-pin-kernel-firmware.sh b/rpi-pin-kernel-firmware.sh new file mode 100644 index 0000000..c8b509f --- /dev/null +++ b/rpi-pin-kernel-firmware.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# rpi-pin-kernel-firmware: Pin a specific version of the rpi kernel and firmware + +set -e + +if [ $# -ne 1 ]; then + echo "Usage: $0 kernel-version" + echo + echo "e.g., $0 1.20201126-1" + exit 1 +fi + +if ! dpkg -l raspberrypi-kernel:armhf > /dev/null 2>&1; then + echo "This command is designed to run only on Raspbian with the armhf kernel" + echo 99 +fi + + +if [ `id -u` -ne 0 ]; then + echo "If necessary, enter your password to run this script as root" + exec sudo sh "$0" "$1" +fi + +version=$1 +fileversion=$(echo $version | cut -d':' -f 2) +base=http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/ +packagelist="libraspberrypi0 libraspberrypi-bin libraspberrypi-dev libraspberrypi-doc raspberrypi-bootloader raspberrypi-kernel raspberrypi-kernel-headers" + +set -- +for package in $packagelist; do + filename="${package}_${fileversion}_armhf.deb" + set -- "$@" "$filename" + wget --continue -O "$filename" "$base/$filename" +done + +dpkg -i "$@" + +for package in $packagelist; do + /usr/bin/printf "Package: $package\nPin: version ${version}\nPin-Priority:999\n\n" +done > /etc/apt/preferences.d/99-adafruit-pin-kernel diff --git a/rpi_pin_kernel_firmware.py b/rpi_pin_kernel_firmware.py new file mode 100644 index 0000000..43935b8 --- /dev/null +++ b/rpi_pin_kernel_firmware.py @@ -0,0 +1,60 @@ +""" +Adafruit Raspberry Pi Script to Pin a specific version of the rpi kernel and firmware +(C) Adafruit Industries, Creative Commons 3.0 - Attribution Share Alike +""" + +try: + from adafruit_shell import Shell +except ImportError: + raise RuntimeError("The library 'adafruit_shell' was not found. To install, try typing: sudo pip3 install adafruit-python-shell") +import os + +shell = Shell() +shell.group = 'PINNING' + +def main(): + shell.clear() + # Check Raspberry Pi and Bail + pi_model = shell.get_board_model() + print("{} detected.\n".format(pi_model)) + if not shell.is_raspberry_pi(): + shell.bail("Non-Raspberry Pi board detected. This must be run on a Raspberry Pi") + if shell.get_os() != "Raspbian": + print("OS Detected:" + shell.get_os()) + shell.bail("Sorry. This script currently only runs on Raspberry Pi OS.") + if len(shell.args) == 1: + print("Usage: sudo python3 {} kernel-version\n".format(shell.script())) + print("e.g., {} 1.20201126-1".format(shell.script())) + shell.exit(1) + version = shell.args[1] + base = "http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/" + packagelist = [ + "libraspberrypi0", + "libraspberrypi-bin", + "libraspberrypi-dev", + "libraspberrypi-doc", + "raspberrypi-bootloader", + "raspberrypi-kernel", + "raspberrypi-kernel-headers" + ] + new_packages = [] + for package in packagelist: + filename = "{}_{}_armhf.deb".format(package, version) + new_packages.append(filename) + shell.run_command("wget --continue -O {} {}".format(filename, base + filename)) + + shell.run_command("dpkg -i " + " ".join(new_packages)) + + for package in packagelist: + write_text_file("/etc/apt/preferences.d/99-adafruit-pin-kernel", +"""Package: {} +Pin: version {} +Pin-Priority:999 + +""".format(package, version)) + shell.prompt_reboot() + +# Main function +if __name__ == "__main__": + shell.require_root() + main() diff --git a/st7789_module/Makefile b/st7789_module/Makefile index cc8e020..0f7575d 100644 --- a/st7789_module/Makefile +++ b/st7789_module/Makefile @@ -1,15 +1,13 @@ -obj-m += st7789v_ada.o obj-m += fb_st7789v.o KDIR ?= /lib/modules/`uname -r`/build default: - $(MAKE) -C $(KDIR) M=$(pwd) modules + $(MAKE) -C $(KDIR) M=$(shell pwd) modules install: - $(MAKE) -C $(KDIR) M=$(PWD) modules_install + $(MAKE) -C $(KDIR) M=$(shell pwd) modules_install $(DEPMOD) clean: - $(MAKE) -C $(KDIR) M=$(PWD) clean - + $(MAKE) -C $(KDIR) M=$(shell pwd) clean diff --git a/st7789_module/fb_st7789v.c b/st7789_module/fb_st7789v.c index 5ac7f7e..f312ed5 100644 --- a/st7789_module/fb_st7789v.c +++ b/st7789_module/fb_st7789v.c @@ -16,31 +16,16 @@ #define DRVNAME "fb_st7789v" -static unsigned int width; -module_param(width, uint, 0000); -MODULE_PARM_DESC(width, "Display width"); - -static unsigned int height; -module_param(height, uint, 0000); -MODULE_PARM_DESC(height, "Display height"); - -static u32 col_offset = 0; -static u32 row_offset = 0; -static u8 col_hack_fix_offset = 0; -static short x_offset = 0; -static short y_offset = 0; - -#define ST77XX_MADCTL_MY 0x80 -#define ST77XX_MADCTL_MX 0x40 -#define ST77XX_MADCTL_MV 0x20 -#define ST77XX_MADCTL_ML 0x10 -#define ST77XX_MADCTL_BGR 0x08 -#define ST77XX_MADCTL_RGB 0x00 - #define DEFAULT_GAMMA \ "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \ "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25" +#define HSD20_IPS_GAMMA \ + "D0 05 0A 09 08 05 2E 44 45 0F 17 16 2B 33\n" \ + "D0 05 0A 09 08 05 2E 43 45 0F 16 16 2B 33" + +#define HSD20_IPS 1 + /** * enum st7789v_command - ST7789V display controller commands * @@ -76,6 +61,18 @@ enum st7789v_command { NVGAMCTRL = 0xE1, }; +#define MADCTL_BGR BIT(3) /* bitmask for RGB/BGR order */ +#define MADCTL_MV BIT(5) /* bitmask for page/column order */ +#define MADCTL_MX BIT(6) /* bitmask for column address order */ +#define MADCTL_MY BIT(7) /* bitmask for page address order */ + +static u32 col1_offset = 0; +static u32 col2_offset = 0; +static u32 row1_offset = 0; +static u32 row2_offset = 0; +static short x_offset = 0; +static short y_offset = 0; + /** * init_display() - initialize the display controller * @@ -92,44 +89,85 @@ enum st7789v_command { */ static int init_display(struct fbtft_par *par) { - printk(KERN_INFO "ST7789 adafruit fbtft driver\n"); - - width = par->info->var.xres; - height = par->info->var.yres; - - if ((width == 0) || (width > 240)) { - width = 240; - } - if ((height == 0) || (height > 320)) { - height = 320; - } - printk(KERN_INFO "Size: (%d, %d)\n", width, height); - - // Go to sleep - write_reg(par, MIPI_DCS_SET_DISPLAY_OFF); - // Soft reset - write_reg(par, MIPI_DCS_SOFT_RESET); - mdelay(150); - /* turn off sleep mode */ write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE); - mdelay(10); + mdelay(120); /* set pixel format to RGB-565 */ write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT); + if (HSD20_IPS) + write_reg(par, PORCTRL, 0x05, 0x05, 0x00, 0x33, 0x33); - write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, 0); - write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, 0, 240); - write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, 320>>8, 320&0xFF); - write_reg(par, MIPI_DCS_ENTER_INVERT_MODE); // odd hack, displays are inverted - write_reg(par, MIPI_DCS_ENTER_NORMAL_MODE); - mdelay(10); + else + write_reg(par, PORCTRL, 0x08, 0x08, 0x00, 0x22, 0x22); + /* + * VGH = 13.26V + * VGL = -10.43V + */ + if (HSD20_IPS) + write_reg(par, GCTRL, 0x75); + else + write_reg(par, GCTRL, 0x35); + + /* + * VDV and VRH register values come from command write + * (instead of NVM) + */ + write_reg(par, VDVVRHEN, 0x01, 0xFF); + + /* + * VAP = 4.1V + (VCOM + VCOM offset + 0.5 * VDV) + * VAN = -4.1V + (VCOM + VCOM offset + 0.5 * VDV) + */ + if (HSD20_IPS) + write_reg(par, VRHS, 0x13); + else + write_reg(par, VRHS, 0x0B); + + /* VDV = 0V */ + write_reg(par, VDVS, 0x20); + + /* VCOM = 0.9V */ + if (HSD20_IPS) + write_reg(par, VCOMS, 0x22); + else + write_reg(par, VCOMS, 0x20); + + /* VCOM offset = 0V */ + write_reg(par, VCMOFSET, 0x20); + + /* + * AVDD = 6.8V + * AVCL = -4.8V + * VDS = 2.3V + */ + write_reg(par, PWCTRL1, 0xA4, 0xA1); write_reg(par, MIPI_DCS_SET_DISPLAY_ON); + + if (HSD20_IPS) + write_reg(par, MIPI_DCS_ENTER_INVERT_MODE); + return 0; } +static void minipitft_set_addr_win(struct fbtft_par *par, int xs, int ys, + int xe, int ye) +{ + xs += x_offset; + xe += x_offset; + ys += y_offset; + ye += y_offset; + write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, + xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF); + + write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, + ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF); + + write_reg(par, MIPI_DCS_WRITE_MEMORY_START); +} + /** * set_var() - apply LCD properties like rotation and BGR mode * @@ -139,36 +177,104 @@ static int init_display(struct fbtft_par *par) */ static int set_var(struct fbtft_par *par) { - u8 addr_mode = 0; + u8 madctl_par = 0; + struct fbtft_display *display = &par->pdata->display; + u32 width = display->width; + u32 height = display->height; + if (par->bgr) + madctl_par |= MADCTL_BGR; + + if (width < 240) { + // Display is centered + row1_offset = row2_offset = (int)((320 - height + 1) / 2); + col1_offset = (int)((240 - width) / 2); + col2_offset = (int)((240 - width + 1) / 2); + } else { + row1_offset = 0; + row2_offset = (320 - height); + col1_offset = col2_offset = (240 - width); + } switch (par->info->var.rotate) { case 0: - addr_mode = 0; - x_offset = col_offset; - y_offset = row_offset; + x_offset = col1_offset; + y_offset = row1_offset; break; case 90: - addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MX; - x_offset = row_offset; - y_offset = col_offset; - break; + madctl_par |= (MADCTL_MV | MADCTL_MY); + x_offset = row1_offset; + y_offset = col1_offset; + break; case 180: - addr_mode = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY; - x_offset = (240 - width) - col_offset + col_hack_fix_offset; - // hack tweak to account for extra pixel width to make even - y_offset = (320 - height) - row_offset; + madctl_par |= (MADCTL_MX | MADCTL_MY); + x_offset = col2_offset; + y_offset = row2_offset; break; case 270: - addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MY; - x_offset = (320 - height) - row_offset; - y_offset = (240 - width) - col_offset; + madctl_par |= (MADCTL_MV | MADCTL_MX); + x_offset = row2_offset; + y_offset = col2_offset; break; default: return -EINVAL; } - printk(KERN_INFO "Rotation %d offsets %d %d\n", par->info->var.rotate, x_offset, y_offset); + write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, madctl_par); + return 0; +} - write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, addr_mode); +/** + * set_gamma() - set gamma curves + * + * @par: FBTFT parameter object + * @curves: gamma curves + * + * Before the gamma curves are applied, they are preprocessed with a bitmask + * to ensure syntactically correct input for the display controller. + * This implies that the curves input parameter might be changed by this + * function and that illegal gamma values are auto-corrected and not + * reported as errors. + * + * Return: 0 on success, < 0 if error occurred. + */ +static int set_gamma(struct fbtft_par *par, u32 *curves) +{ + int i; + int j; + int c; /* curve index offset */ + + /* + * Bitmasks for gamma curve command parameters. + * The masks are the same for both positive and negative voltage + * gamma curves. + */ + static const u8 gamma_par_mask[] = { + 0xFF, /* V63[3:0], V0[3:0]*/ + 0x3F, /* V1[5:0] */ + 0x3F, /* V2[5:0] */ + 0x1F, /* V4[4:0] */ + 0x1F, /* V6[4:0] */ + 0x3F, /* J0[1:0], V13[3:0] */ + 0x7F, /* V20[6:0] */ + 0x77, /* V36[2:0], V27[2:0] */ + 0x7F, /* V43[6:0] */ + 0x3F, /* J1[1:0], V50[3:0] */ + 0x1F, /* V57[4:0] */ + 0x1F, /* V59[4:0] */ + 0x3F, /* V61[5:0] */ + 0x3F, /* V62[5:0] */ + }; + + for (i = 0; i < par->gamma.num_curves; i++) { + c = i * par->gamma.num_values; + for (j = 0; j < par->gamma.num_values; j++) + curves[c + j] &= gamma_par_mask[j]; + write_reg(par, PVGAMCTRL + i, + curves[c + 0], curves[c + 1], curves[c + 2], + curves[c + 3], curves[c + 4], curves[c + 5], + curves[c + 6], curves[c + 7], curves[c + 8], + curves[c + 9], curves[c + 10], curves[c + 11], + curves[c + 12], curves[c + 13]); + } return 0; } @@ -195,11 +301,13 @@ static struct fbtft_display display = { .height = 320, .gamma_num = 2, .gamma_len = 14, - .gamma = DEFAULT_GAMMA, + .gamma = HSD20_IPS_GAMMA, .fbtftops = { .init_display = init_display, .set_var = set_var, + .set_gamma = set_gamma, .blank = blank, + .set_addr_win = minipitft_set_addr_win, }, }; diff --git a/st7789_module/fbtft.h b/st7789_module/fbtft.h index 9b6bdb6..f4f5ff0 100644 --- a/st7789_module/fbtft.h +++ b/st7789_module/fbtft.h @@ -251,7 +251,8 @@ void fbtft_register_backlight(struct fbtft_par *par); void fbtft_unregister_backlight(struct fbtft_par *par); int fbtft_init_display(struct fbtft_par *par); int fbtft_probe_common(struct fbtft_display *display, struct spi_device *sdev, - struct platform_device *pdev); + struct platform_device *pdev, + const struct of_device_id *dt_ids); int fbtft_remove_common(struct device *dev, struct fb_info *info); /* fbtft-io.c */ @@ -272,11 +273,13 @@ void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...); void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...); -#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ +#define FBTFT_REGISTER_DRIVER_START(_display) \ + \ +static const struct of_device_id dt_ids[]; \ \ static int fbtft_driver_probe_spi(struct spi_device *spi) \ { \ - return fbtft_probe_common(_display, spi, NULL); \ + return fbtft_probe_common(_display, spi, NULL, dt_ids); \ } \ \ static int fbtft_driver_remove_spi(struct spi_device *spi) \ @@ -288,7 +291,7 @@ static int fbtft_driver_remove_spi(struct spi_device *spi) \ \ static int fbtft_driver_probe_pdev(struct platform_device *pdev) \ { \ - return fbtft_probe_common(_display, NULL, pdev); \ + return fbtft_probe_common(_display, NULL, pdev, dt_ids); \ } \ \ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ @@ -298,8 +301,16 @@ static int fbtft_driver_remove_pdev(struct platform_device *pdev) \ return fbtft_remove_common(&pdev->dev, info); \ } \ \ -static const struct of_device_id dt_ids[] = { \ - { .compatible = _compatible }, \ +static const struct of_device_id dt_ids[] = { + +#define FBTFT_COMPATIBLE(_compatible) \ + { .compatible = _compatible }, + +#define FBTFT_VARIANT_COMPATIBLE(_compatible, _variant) \ + { .compatible = _compatible, .data = _variant }, + +#define FBTFT_REGISTER_DRIVER_END(_name, _display) \ + \ {}, \ }; \ \ @@ -309,7 +320,7 @@ MODULE_DEVICE_TABLE(of, dt_ids); \ static struct spi_driver fbtft_driver_spi_driver = { \ .driver = { \ .name = _name, \ - .of_match_table = of_match_ptr(dt_ids), \ + .of_match_table = dt_ids, \ }, \ .probe = fbtft_driver_probe_spi, \ .remove = fbtft_driver_remove_spi, \ @@ -319,7 +330,7 @@ static struct platform_driver fbtft_driver_platform_driver = { \ .driver = { \ .name = _name, \ .owner = THIS_MODULE, \ - .of_match_table = of_match_ptr(dt_ids), \ + .of_match_table = dt_ids, \ }, \ .probe = fbtft_driver_probe_pdev, \ .remove = fbtft_driver_remove_pdev, \ @@ -344,13 +355,26 @@ static void __exit fbtft_driver_module_exit(void) \ module_init(fbtft_driver_module_init); \ module_exit(fbtft_driver_module_exit); +#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \ + FBTFT_REGISTER_DRIVER_START(_display) \ + FBTFT_COMPATIBLE(_compatible) \ + FBTFT_REGISTER_DRIVER_END(_name, _display) + /* Debug macros */ /* shorthand debug levels */ #define DEBUG_LEVEL_1 DEBUG_REQUEST_GPIOS -#define DEBUG_LEVEL_2 (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE) -#define DEBUG_LEVEL_3 (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS) -#define DEBUG_LEVEL_4 (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK) +#define DEBUG_LEVEL_2 (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS \ + | DEBUG_TIME_FIRST_UPDATE) +#define DEBUG_LEVEL_3 (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY \ + | DEBUG_BLANK | DEBUG_REQUEST_GPIOS \ + | DEBUG_FREE_GPIOS \ + | DEBUG_VERIFY_GPIOS \ + | DEBUG_BACKLIGHT | DEBUG_SYSFS) +#define DEBUG_LEVEL_4 (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE \ + | DEBUG_FB_FILLRECT \ + | DEBUG_FB_COPYAREA \ + | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK) #define DEBUG_LEVEL_5 (DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY) #define DEBUG_LEVEL_6 (DEBUG_LEVEL_4 | DEBUG_LEVEL_5) #define DEBUG_LEVEL_7 0xFFFFFFFF @@ -398,8 +422,8 @@ do { \ #define fbtft_par_dbg(level, par, format, arg...) \ do { \ - if (unlikely(par->debug & level)) \ - dev_info(par->info->device, format, ##arg); \ + if (unlikely((par)->debug & (level))) \ + dev_info((par)->info->device, format, ##arg); \ } while (0) #define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \ diff --git a/st7789_module/st7789v_ada.c b/st7789_module/st7789v_ada.c deleted file mode 100644 index f2e6784..0000000 --- a/st7789_module/st7789v_ada.c +++ /dev/null @@ -1,408 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * DRM driver for ST7789V panels with flexible config - * - * Copyright 2019 Limor Fried - * Copyright 2016 Noralf Trønnes - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include