MSM8916 Mainlining

From postmarketOS
Revision as of 16:02, 13 September 2019 by Minecrell (talk | contribs) (Sensors)
Jump to: navigation, search

MSM8916/APQ8016 (or Snapdragon 410) is Qualcomm SoC released in 2014. Support in mainline was originally added for the Dragonboard 410c, but most of it also works well on other MSM8916-based devices.

Status

The following features provided by the MSM8916 SoC are supported in mainline and should work on most MSM8916-based devices after the device tree has been set up:

  • UART
  • USB
  • Internal/External Storage (eMMC/SD card)
  • WiFi/Bluetooth
  • GPU, Display (Note: There are many different display panels and each needs a custom panel driver...)
  • Sound (Note: Some devices use a custom speaker amplifier instead of the one provided by PM8916...)
  • Buttons

Certain components (e.g. touchscreen, sensors, ...) are device-specific. With a bit of luck, some will be already supported by mainline, others won't.

Overview

The first MSM8916 devices using mainline were added in pmaports!582. The following components are involved when running mainline on MSM8916 devices.

msm8916-mainline/linux

The close-to-mainline Linux kernel fork with patches that have not been accepted/submitted upstream yet. Patches in the master branch are generally in good shape unless marked otherwise. Submit a PR to add new patches there.

msm8916-mainline/lk2nd

The reference bootloader provided by Qualcomm for MSM8916 is open-source and based on Little Kernel (LK). Most devices will use this bootloader in a more or less modified form. On Samsung devices for example, the standard Fastboot interface was replaced by their proprietary download mode.

lk2nd is a fork of the reference bootloader with the goal to provide an unified boot interface on all MSM8916 devices. It provides a standard Fastboot interface (even on Samsung devices!). It also used for a number of mainline quirks (e.g. to set a WiFi/BT MAC address in the device tree; without lk2nd, WiFi/BT does not work out of the box). Eventually, more quirks may be added in the future. It is therefore recommended for all mainline MSM8916 devices. Porting it is generally much easier than porting mainline.

Note: lk2nd does not replace your stock bootloader. It is packed into a standard Android boot image and loaded by the stock bootloader from the boot partition. The real boot partition used by lk2nd is then placed with 1 MB offset into the boot partition.

soc-qcom-msm8916

The shared device package in postmarketOS. It contains shared dependencies and configuration files.

Getting Started

Requirements

  • MSM8916-based device
  • UART if possible (with a bit of luck you may get USB working without UART)
  • (Downstream) Linux kernel source for your device (explaining ways to mainline without kernel source is out of scope for this article)
  • Basic knowledge about Linux, Git, C, Device Trees, ...
  • Willingness to learn about "mainlining" and to figure out things on your own

Before you start

Warning: Mainlining (or any unintended "modding") may brick your device permanently if you make a mistake. There is a good chance that nothing happens if you are a bit careful, but do not continue with a device that you need every day. You have been warned!

Mainlining is not easy. MSM8916 is a platform where a lot components can be easily enabled by only setting up a device tree, which can be largely copied from other devices with minor changes. However, at some point you will reach the point where you would like to enable a particular component that is device-specific (e.g. the touchscreen, sensors, ...). In this case you will be largely on your own, and need to figure out how to enable it yourself. (Do you just need to add something to the device tree or even write a new kernel driver?) That requires some familiarity with the way the Linux kernel is working for MSM8916.

The best way to make yourself familiar with the process is to attempt to figure out some simple things on your own. Therefore, this guide will only describe everything until (eventually) USB network is working. For everything else, this article provides only some information that might be helpful to figure it out yourself.

If you have any questions, ask in the mainline channel on Matrix or IRC. Make sure to mention "msm8916" if your question is specific to this article.

Preparations

First, let's take a short look at the downstream kernel. The device trees on downstream are usually in arch/arm/boot/dts/qcom/msm8916-*.dts(i) (in Samsung kernels: arch/arm/boot/dts/samsung/msm8916/msm8916-*.dts(i)). You need to find the .dts file that describes the device tree for your device. One way to check this is to look at /proc/device-tree/model on downstream, and search for the same string in that directory.

Now, let's check how it looks on mainline. Clone msm8916-mainline/linux and take a look at arch/arm64/boot/dts/qcom/. This is the directory where you will add your device tree later.

lk2nd

Note: lk2nd is not strictly required to boot mainline. However, certain features (e.g. WiFi and BT) only work with some additional mainline quirks included in lk2nd. In the future, there may be more features that depend on extra code that needs to be run in the bootloader. Therefore, lk2nd is recommended for all devices, even if your stock bootloader already provides a standard Fastboot interface.

msm8916-mainline/lk2nd does not require any device-specific code. Normally, it should just run out of the box on your device. However, most stock bootloaders require a valid device tree to be present in the Android boot image. To avoid problems, a dummy device tree with the qcom,board-id from the downstream kernel needs to be added to lk2nd.

Before you make any changes, try building it. Then, add a new file for your device to dts/ that looks like:

// SPDX-License-Identifier: GPL-2.0-only

/dts-v1/;

/include/ "msm8916.dtsi"

/ {
	// This is used by the bootloader to find the correct DTB
	qcom,msm-id = <206 0>; // qcom,msm-id = <247 0>; for APQ8016
	qcom,board-id = /* FIXME: Check your downstream device tree */;

	model = "Device Name"; // FIXME
	compatible = "<vendor>,<codename>", "qcom,msm8916", "lk2nd,device"; // FIXME
};


Note the FIXME lines in the example above. This is where you still need to make changes for your device. For example, replace the model with a display name for your device, and the placeholders in the compatible string.

Make sure to add the new file to dts/rules.mk, and re-compile lk2nd.

With a bit of luck, flashing the boot image on your device should make it boot into a Fastboot screen, and the device should show up via USB. If either of that is not the case, we need to investigate further. Sometimes, there is some kind of Micro-USB_Interface_Controller that sits between USB and the SoC, which may require manual setup to work correctly. Setting that up would require device-specific code. If you need help, ask in the mainline channel on Matrix or IRC.

Device Package

Before you can build the mainline kernel for your device, you need to setup the postmarketOS device packages. Avoid creating the device/kernel package directly through pmbootstrap. There is no need to analyze a boot image. (The boot image offsets are not actually used on MSM8916; plus, all MSM8916 devices should use Fastboot through lk2nd...) You can start with the following examples:

device/device-<vendor>-<codename>/APKBUILD:

# Reference: <https://postmarketos.org/devicepkg>
pkgname="device-<vendor>-<codename>"
pkgdesc="Device Name"
pkgver=1
pkgrel=0
url="https://postmarketos.org"
license="MIT"
arch="aarch64"
options="!check !archcheck"
depends="postmarketos-base mkbootimg linux-postmarketos-qcom-msm8916 soc-qcom-msm8916"
makedepends="devicepkg-dev"
source="deviceinfo"

build() {
	devicepkg_build $startdir $pkgname
}

package() {
	devicepkg_package $startdir $pkgname
}

device/device-<vendor>-<codename>/deviceinfo:

# Reference: <https://postmarketos.org/deviceinfo>
# Please use double quotes only. You can source this file in shell scripts.

deviceinfo_format_version="0"
deviceinfo_name="Device Name"
deviceinfo_manufacturer="Vendor"
deviceinfo_codename="<vendor>-<codename>"
deviceinfo_date=""
deviceinfo_dtb="qcom/msm8916-<vendor>-<codename>"
#deviceinfo_append_dtb="true"
deviceinfo_modules_initfs=""
deviceinfo_arch="aarch64"

# Device related
deviceinfo_keyboard="false"
deviceinfo_external_storage="true"
deviceinfo_screen_width="720"
deviceinfo_screen_height="1280"
deviceinfo_dev_touchscreen=""
deviceinfo_dev_touchscreen_calibration=""
deviceinfo_dev_keyboard=""

# MSM DRM cannot take over the framebuffer from the bootloader at the moment
deviceinfo_no_framebuffer="true"

# Bootloader related
deviceinfo_flash_method="fastboot"
deviceinfo_kernel_cmdline="earlycon=msm_serial_dm,0x78b0000 console=ttyMSM0,115200,n8 PMOS_NO_OUTPUT_REDIRECT"
deviceinfo_generate_bootimg="true"
#deviceinfo_bootimg_qcdt="true"
deviceinfo_flash_offset_base="0x80000000"
deviceinfo_flash_offset_kernel="0x00080000"
deviceinfo_flash_offset_ramdisk="0x02000000"
deviceinfo_flash_offset_second="0x00f00000"
deviceinfo_flash_offset_tags="0x01e00000"
deviceinfo_flash_pagesize="2048"
deviceinfo_flash_sparse="true"

To load a generic kernel image, the device must be able to find the correct device tree. MSM8916 devices usually use QCDT (multiple device tree blobs (dtb) are packaged in one Android boot image; the correct one is selected based on the qcom,board-id). However, not all devices implement the specification correctly: For example, all Samsung devices use the same qcom,board-id - it is therefore useless to pick the correct device tree. In that case, we append a single DTB to the kernel image instead and load it directly from there (note: works only with lk2nd).

ToDo Explain how to check if the device implements the QCDT specification properly.
  • QCDT: Uncomment deviceinfo_bootimg_qcdt="true"
    ToDo Explain how to figure out which compatible string to use in this case.
  • Appended device tree: Uncomment deviceinfo_append_dtb="true"

Follow the postmarketOS porting guide until the device package builds successfully.

Build Kernel

Go back to your msm8916-mainline/linux clone. Try to build it with envkernel.sh:

$ cd path/to/msm8916-mainline/linux
$ source path/to/pmbootstrap/helpers/envkernel.sh

# Initialize kernel configuration
$ make msm8916_defconfig pmos.config

# Compile kernel; replace <cores> with the number of cores you'd like to use for compilation
$ make -j<cores>

# Create postmarketOS package with your built kernel
$ pmbootstrap build --envkernel linux-postmarketos-qcom-msm8916

This is how you can build and test local changes for the kernel from now on. Now we will continue setting up an initial device tree for your device.

Initial Device Tree

The available hardware components of a device are described in the device tree (see e.g. this introduction). Components provided by the SoC (MSM8916) are described in the common include msm8916.dtsi. You need to create a device tree with the device-specific configuration, plus additional components used in your device (e.g. touchscreen).

The device tree for your device should be placed in a new file at arch/arm64/boot/dts/qcom/msm8916-<vendor>-<codename>.dts. A very simple device tree that only enables UART output could look like this:

// SPDX-License-Identifier: GPL-2.0-only

/dts-v1/;

#include "msm8916.dtsi"
#include "pm8916.dtsi"

/ {
	model = "Device Name"; // FIXME
	compatible = "<vendor>,<codename>", "qcom,msm8916"; // FIXME

	aliases {
		serial0 = &blsp1_uart2;
	};

	chosen {
		stdout-path = "serial0";
	};

	soc {
		serial@78b0000 {
			status = "okay";
			pinctrl-names = "default", "sleep";
			pinctrl-0 = <&blsp1_uart2_default>;
			pinctrl-1 = <&blsp1_uart2_sleep>;
		};
	};
};

MSM8916 has 122 GPIO pins that can be configured with different functions. GPIO 4 and 5 can be configured to provide UART ("blsp1_uart2"). In the Linux kernel, the Pin Control Subsystem (pinctrl) handles configuring the pins with a specific function.

Therefore, the above device tree does the following:

  • aliases and chosen: Set up BLSP UART2 as default console output
  • serial@78b0000: This node is defined in msm8916.dtsi but disabled by default (status = "disabled")
    • status = "okay" Enable it
    • pinctrl: configure GPIO 4 and 5 for UART (blsp1_uart2_default and blsp1_uart2_sleep are default pin configurations that are defined in the common msm8916-pins.dtsi

Before you build, don't forget to add an entry to arch/arm64/boot/dts/qcom/Makefile. This device tree should be already enough to boot with working serial console if you are able to access UART. If you don't have UART you will need to skip testing this step and hope that USB works out of the box in the next step.

Storage & USB

Let's look at a more complex device tree now. The goal is to enable internal/external storage (eMMC) and to make USB gadget mode working so you can attach your device to a PC and get a debugging console. This is where things start to get slightly different between devices.

Update your device tree with something like the following:

// SPDX-License-Identifier: GPL-2.0-only

/dts-v1/;

#include "msm8916.dtsi"
#include "pm8916.dtsi"
#include <dt-bindings/gpio/gpio.h>

/ {
	model = "Device Name"; // FIXME
	compatible = "<vendor>,<codename>", "qcom,msm8916"; // FIXME

	aliases {
		serial0 = &blsp1_uart2;
	};

	chosen {
		stdout-path = "serial0";
	};

	soc {
		sdhci@7824000 {
			status = "okay";

			vmmc-supply = <&pm8916_l8>;
			vqmmc-supply = <&pm8916_l5>;

			pinctrl-names = "default", "sleep";
			pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on>;
			pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off>;
		};

		sdhci@7864000 {
			status = "okay";

			vmmc-supply = <&pm8916_l11>;
			vqmmc-supply = <&pm8916_l12>;

			pinctrl-names = "default", "sleep";

			pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>; // add &sdc2_cd_on if you use cd-gpios below
			pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; // add &sdc2_cd_off if you use cd-gpios below

			// FIXME: Either or - compare with downstream
			//non-removable;
			//cd-gpios = <&msmgpio 38 GPIO_ACTIVE_LOW>;
		};

		serial@78b0000 {
			status = "okay";
			pinctrl-names = "default", "sleep";
			pinctrl-0 = <&blsp1_uart2_default>;
			pinctrl-1 = <&blsp1_uart2_sleep>;
		};

		usb@78d9000 {
			status = "okay";
			dr_mode = "peripheral";

			hnp-disable;
			srp-disable;
			adp-disable;

			ulpi {
				phy {
					v1p8-supply = <&pm8916_l7>;
					v3p3-supply = <&pm8916_l13>;
				};
			};
		};

		/*
		 * Attempting to enable these devices causes a "synchronous
		 * external abort". Suspected cause is that the debug power
		 * domain is not enabled by default on this device.
		 * Disable these devices for now to avoid the crash.
		 *
		 * See: https://lore.kernel.org/linux-arm-msm/20190618202623.GA53651@gerhold.net/
		 */
		tpiu@820000 { status = "disabled"; };
		funnel@821000 { status = "disabled"; };
		replicator@824000 { status = "disabled"; };
		etf@825000 { status = "disabled"; };
		etr@826000 { status = "disabled"; };
		funnel@841000 { status = "disabled"; };
		debug@850000 { status = "disabled"; };
		debug@852000 { status = "disabled"; };
		debug@854000 { status = "disabled"; };
		debug@856000 { status = "disabled"; };
		etm@85c000 { status = "disabled"; };
		etm@85d000 { status = "disabled"; };
		etm@85e000 { status = "disabled"; };
		etm@85f000 { status = "disabled"; };
	};
};

// TODO (wiki): Explain setup of dummy extcon device to make USB work

// FIXME: Verify all regulators with downstream
&smd_rpm_regulators {
	vdd_l1_l2_l3-supply = <&pm8916_s3>;
	vdd_l4_l5_l6-supply = <&pm8916_s4>;
	vdd_l7-supply = <&pm8916_s4>;

	s1 {
		regulator-min-microvolt = <500000>;
		regulator-max-microvolt = <1300000>;
	};

	s3 {
		regulator-min-microvolt = <1200000>;
		regulator-max-microvolt = <1300000>;
	};

	s4 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <2100000>;
	};

	l1 {
		regulator-min-microvolt = <1225000>;
		regulator-max-microvolt = <1225000>;
	};

	l2 {
		regulator-min-microvolt = <1200000>;
		regulator-max-microvolt = <1200000>;
	};

	l3 {
		regulator-min-microvolt = <500000>;
		regulator-max-microvolt = <1287500>;
	};

	l4 {
		regulator-min-microvolt = <2050000>;
		regulator-max-microvolt = <2050000>;
	};

	l5 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
	};

	l6 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
	};

	l7 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <1800000>;
	};

	l8 {
		regulator-min-microvolt = <2850000>;
		regulator-max-microvolt = <2900000>;
	};

	l9 {
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
	};

	l10 {
		regulator-min-microvolt = <2700000>;
		regulator-max-microvolt = <2800000>;
	};

	l11 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <2950000>;
		regulator-allow-set-load;
		regulator-system-load = <200000>;
	};

	l12 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <2950000>;
	};

	l13 {
		regulator-min-microvolt = <3075000>;
		regulator-max-microvolt = <3075000>;
	};

	l14 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <3300000>;
	};

	l15 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <3300000>;
	};

	l16 {
		regulator-min-microvolt = <1800000>;
		regulator-max-microvolt = <3300000>;
	};

	l17 {
		regulator-min-microvolt = <2850000>;
		regulator-max-microvolt = <2850000>;
	};

	l18 {
		regulator-min-microvolt = <2700000>;
		regulator-max-microvolt = <2700000>;
	};
};

Whoa! That's quite a lot of new stuff. Let's look at the new lines in detail:

  • sdhci@7824000: This enables the internal storage. There should not be any change needed here, it should work as-is.
  • sdhci@7864000: This is the external storage. There is a FIXME in there because there is an implementation detail that differs between devices. Some devices have their SD card slot behind the battery. In that case, they may have avoided implementing the chip detect ("cd") GPIO that is used to detect if a SD card is inserted (or removed). In any case, check if downstream defines cd-gpios, usually on the &sdhc_2 node. If yes, add it together with the other comment, otherwise put non-removable.
  • usb@78d9000: This enables the USB code and forces it to USB gadget ("peripheral") mode. (If you want, you can attempt to get OTG/Host mode working later...)
  • tpiu@820000, funnel@821000, ...: This is a workaround to avoid a boot error on production MSM8916 devices. Check the link in the comment if you are curious.
  • &smd_rpm_regulators: This block defines constraints for the regulators provided by PM8916 (the PMIC used by MSM8916). Most importantly, you define the voltage range that can be set by drivers for the regulators. Unless your device manufacturer felt very special, all MSM8916 devices should use these regulator voltages. Nevertheless it is important to check for differences in downstream. Here are some tips and tricks:
    • Downstream regulators look a bit different, but they are usually defined in msm8916-regulators.dtsi. Note that some device trees may override the regulator voltages in a device-specific .dts(i).
    • "Corner" regulators are a special type of regulators downstream that are used for some kind of voting mechanism. The idea is that different components in the SoC vote for the voltage level they currently require, and the Resource Power Manager (RPM) picks the appropriate voltage based on the votes. Mainline does not have corner regulators, so just ignore them for now.
    • s2 is special (used to control the voltage for the CPU cores) and is not touched by mainline at the moment. Just ignore it.
    • Also ignore the -ao and -so regulators (usually just on l7)
Warning: Make sure to check the regulators carefully and ask for feedback before testing the changes in the next step.

For testing, consider enabling the debug-shell hook so you can avoid flashing the rootfs as a first step. (Note that you need to remove it explicitly using hook_del when you want to try flashing the rootfs later...) With a bit of luck, the device should show up on telnet via USB after booting with these changes.

If USB is working, try flashing the rootfs to check if the internal storage is working. Your device should then boot into the full postmarketOS installation and provide SSH over the USB network interface.

ToDo USB does not actually work out of the box with the instructions above (note the TODO comment in the device tree example). Please ask for help in the chat for now.

Finishing up

If the features enabled during the guide are working, then it is a good time to do some cleanup and propose your changes "upstream" on msm8916-mainline/linux. This repository is intended as a temporary place for patches that are already in good quality, but either pending or not quite finished to submit them on the Linux mainline mailing lists.

To maintain the quality, all patches are required to:

  • Compile without warnings
  • Have no criticial (ERROR:) checkpatch failures (also see Style-check your changes in the mainline "Submitting patches" guide)
    • Sometimes it makes sense to ignore notes and warnings from checkpatch if the code is more readable without fixing them.
  • Have a properly formatted one-line summary in the commit message (there is no need to write a detailed commit message, yet)
    • Look at similar commits in the commit history for examples.

The first two will be automatically checked for you when you open a PR - the CI build will fail otherwise - so you don't have to check it locally. Eventually, you should expect a few additional review comments to improve your code. This will help you to speed up submission of the patches upstream later! ;)

When this is done, then you can continue working on whatever you would like to work on! Below are a few tips and tricks for common features. However, it is hard to write a definitive guide as they differ between devices, so you will need to do some investigation on your own.

Reference

The general approach for mainlining is:

  • Look at all resources you can find, e.g.:
    • Commits in msm8916-mainline/linux
    • Existing device trees in mainline and/or commits with relevant changes (sometimes there is helpful information in the commit message)
    • The kernel documentation, especially the device tree binding documentation (all available device tree properties should be documented there)

and compare it with what you can find on downstream (e.g. device tree, kernel code, ...). Do not take the downstream device tree as a base or even copy it as-is. That is the wrong approach. Downstream code tends to be full of mistakes and unnecessarily verbose. It's easier to start from scratch and rather take something in mainline as a base.

Additional tips and tricks:

  • When making changes to kernel code compiled as modules, you need to update the kernel modules on the rootfs (they are not part of the boot image that is loaded via Fastboot). There are different options to do this:

WiFi/Bluetooth

WiFi/Bluetooth are usually provided by the Qualcomm Wireless Connectivity Subsystem (WCNSS), which is partially built into the SoC but paired with an external RF module ("iris").[1] Therefore, enabling it is usually as simple as enabling the wcnss node in the device tree:[2]

wcnss@a21b000 {
	status = "okay";
};

By default mainline expects WCN3620 as external RF module. However, MSM8916 can be also paired with other RF modules - another common chip is WCN3660B which has dual-band (5 GHz) support additionally. The chip identifier can be obtained from a downstream kernel log (dmesg): There should be a message like wcnss: IRIS Reg: 04000004.[3] Take the first 4 hex chars (i.e. >> 16) and compare it with the chip IDs listed in downstream.

If you do not have WCN3620, you need to override the compatible property of the iris node:[4]

wcnss@a21b000 {
	status = "okay";

	iris {
		compatible = "qcom,wcn3680"; // For WCN3660B or WCN3680
	};
};

Note the use of qcom,wcn3680 instead of qcom,wcn3660 for WCN3660B. WCN3660B is actually more similar to WCN3680 since it requires different regulator voltages compared to WCN3660. qcom,wcn3680 enables the correct configuration.[4]

  • WiFi and Bluetooth share the same antenna, and they tend to conflict with each other when they are used at the same time ("WiFi/BT coexistence"). In case of problems, try disabling one of them.
  • Dual-band support on WCN3660B seems to be broken at the moment: only 2.4 GHz networks show up in the WiFi network list.

Display/GPU

ToDo

Touchscreen

ToDo

Audio

ToDo

Buttons

The Power and Volume Down buttons are usually connected to the PMIC (PM8916). (The Power button is - obviously - used to power on the device. Volume Down is used in combination with the Power button to force a reboot, essentially simulating removing the battery and putting it back in. On devices without removable battery holding these two buttons allows rebooting the device...)

qcom,pm8941-pwrkey (Power) and qcom,pm8941-resin (Volume Down) are used to expose these two buttons to user-space. qcom,pm8941-pwrkey is already set up in the common pm8916.dtsi and should out of the box. A new device node for qcom,pm8941-resin needs to be added manually:

&spmi_bus {
	pm8916@0 {
		pon@800 {
			volume-down {
				compatible = "qcom,pm8941-resin";
				interrupts = <0x0 0x8 1 IRQ_TYPE_EDGE_BOTH>;
				bias-pull-up;
				linux,code = <KEY_VOLUMEDOWN>;
			};
		};
	};
};

Volume Up and other additional keys (e.g. Home on Samsung devices) are usually connected to a GPIO pin on the SoC. Therefore, setting them up is trivial using gpio-keys.

Sensors

Like the touchscreen, sensors are usually connected to a I²C bus, e.g. blsp_i2c2 and usually supplied by L17. This is where similarities end. There can be all sorts of sensors connected to the I²C bus and manufacturers like to use many different ones. Look through the supported sensors in mainline to see if a driver exists already, or can be modified eventually to support another version of a similar chip. Otherwise, you may need to write a simple driver yourself.

Some devices have a Hall effect sensor that is used to detect if the screen is covered by some kind of flip cover. It is usually a simple GPIO like the buttons, and can be set up easily using gpio-keys.

Battery/Charging

ToDo