<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Rayyan Ansari</title><link>https://ansari.sh/</link><description>A developer experienced with open-source who has worked on a variety of projects, ranging from user interface design to the Linux kernel.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 21 Sep 2022 17:14:42 +0100</lastBuildDate><atom:link href="https://ansari.sh/index.xml" rel="self" type="application/rss+xml"/><item><title>Mainlining Nexus 9: First Boot</title><link>https://ansari.sh/posts/mainline-nexus-9-p1/</link><pubDate>Wed, 21 Sep 2022 17:14:42 +0100</pubDate><guid>https://ansari.sh/posts/mainline-nexus-9-p1/</guid><description><![CDATA[<p>Having received the Google Nexus 9 tablet recently, I decided to try mainlining it, given that it uses the NVIDIA Tegra K1 (tegra132 variant) that has good mainline support. The Nexus 9 is an Android ARM64 tablet branded as Google but made by HTC, codenamed <em>&ldquo;flounder&rdquo;</em>. There seem to be no tegra132 devices with a device tree in mainline right now, apart from a developer board.</p>
<h2 id="information-gathering">Information Gathering</h2>
<h3 id="downstream-device-tree">Downstream Device Tree</h3>
<p>The device tree used by the downstream Linux kernel cannot be used with the mainline kernel - but it is a good reference for writing a new device tree. It can be dumped by a running device using <code>dtc</code>, the device tree compiler. This program can decompile device trees as well as compile them. The benefit of doing it this way is that the entire device tree will be dumped into one file - unlike the downstream released kernel sources which have a mess of a device tree split up across several files.</p>
<p>First, a static, cross-compiled version of dtc needs to be built (unless you want to copy all the libraries over), which can be done by modifying the <code>Makefile</code>. This can then be copied over to either Android with root access, or TWRP. The device tree can then be dumped using this command:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">dtc -I fs -O dts -o flounder-downstream.dts /proc/device-tree
</span></span></code></pre></div><h3 id="command-line-parameters">Command line parameters</h3>
<p>The cmdline parameters often include useful information such as memory addresses or panel types. Some of these are passed by the bootloader, and some of these are hardcoded in the kernel. The cmdline is easier to find compared to the device tree:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">cat /proc/cmdline &gt; cmdline-downstream.txt
</span></span></code></pre></div><p>My cmdline looks like this - I could already see some useful information such as the framebuffer memory address and size, which will be useful later:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-gdscript3" data-lang="gdscript3"><span class="line"><span class="cl"><span class="n">no_console_suspend</span><span class="o">=</span><span class="mi">1</span> <span class="n">tegra_wdt</span><span class="o">.</span><span class="n">enable_on_probe</span><span class="o">=</span><span class="mi">1</span> <span class="n">tegra_wdt</span><span class="o">.</span><span class="n">heartbeat</span><span class="o">=</span><span class="mi">120</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">hardware</span><span class="o">=</span><span class="n">flounder</span> <span class="n">tegraid</span><span class="o">=</span><span class="mf">40.0</span><span class="o">.</span><span class="mf">0.00</span><span class="o">.</span><span class="mi">00</span> <span class="n">vmalloc</span><span class="o">=</span><span class="mi">256</span><span class="n">M</span> <span class="n">video</span><span class="o">=</span><span class="n">tegrafb</span> <span class="n">console</span><span class="o">=</span><span class="n">ttyS0</span><span class="p">,</span><span class="mi">115200</span><span class="n">n8</span> <span class="n">earlyprintk</span> <span class="n">MTS</span> <span class="n">Version</span><span class="o">=</span><span class="mi">33985182</span> <span class="n">memtype</span><span class="o">=</span><span class="mi">0</span> <span class="n">tzram</span><span class="o">=</span><span class="mi">4</span><span class="n">M</span><span class="err">@</span><span class="mi">3962</span><span class="n">M</span> <span class="n">ddr_die</span><span class="o">=</span><span class="mi">1024</span><span class="n">M</span><span class="err">@</span><span class="mi">2048</span><span class="n">M</span> <span class="n">ddr_die</span><span class="o">=</span><span class="mi">1024</span><span class="n">M</span><span class="err">@</span><span class="mi">3072</span><span class="n">M</span> <span class="n">section</span><span class="o">=</span><span class="mi">128</span><span class="n">M</span> <span class="n">lp0_vec</span><span class="o">=</span><span class="mi">2048</span><span class="err">@</span><span class="mh">0xf7fff000</span> <span class="n">tegra_fbmem</span><span class="o">=</span><span class="mi">12713984</span><span class="err">@</span><span class="mh">0xac001000</span> <span class="n">nvdumper_reserved</span><span class="o">=</span><span class="mh">0xf7800000</span> <span class="n">core_edp_mv</span><span class="o">=</span><span class="mi">1150</span> <span class="n">core_edp_ma</span><span class="o">=</span><span class="mi">4000</span> <span class="n">gpt</span> <span class="n">gpt_sector</span><span class="o">=</span><span class="mi">69631</span> <span class="n">watchdog</span><span class="o">=</span><span class="n">disable</span> <span class="n">nck</span><span class="o">=</span><span class="mi">1048576</span><span class="err">@</span><span class="mh">0xf7900000</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">hardware</span><span class="o">=</span><span class="n">flounder</span> <span class="n">buildvariant</span><span class="o">=</span><span class="n">userdebug</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">serialno</span><span class="o">=</span><span class="n">HT4B7JT02439</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">baseband</span><span class="o">=</span><span class="n">N</span><span class="o">/</span><span class="n">A</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">mode</span><span class="o">=</span><span class="n">normal</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">bootloader</span><span class="o">=</span><span class="mf">3.50</span><span class="o">.</span><span class="mf">0.0143</span> <span class="n">swoff</span><span class="o">=</span><span class="mi">128</span> <span class="n">flounder</span><span class="o">.</span><span class="n">wifimacaddr</span><span class="o">=</span><span class="n">B4</span><span class="p">:</span><span class="n">CE</span><span class="p">:</span><span class="n">F6</span><span class="p">:</span><span class="mi">08</span><span class="p">:</span><span class="mi">90</span><span class="p">:</span><span class="mi">37</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">wificountrycode</span><span class="o">=</span><span class="n">DE</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">bootreason</span><span class="o">=</span><span class="n">hard_reset</span> <span class="n">hw_revision</span><span class="o">=</span><span class="mi">128</span> <span class="n">radioflag</span><span class="o">=</span><span class="mh">0x0</span> <span class="n">androidboot</span><span class="o">.</span><span class="n">misc_pagesize</span><span class="o">=</span><span class="mi">2048</span>
</span></span></code></pre></div><h3 id="boot-image">Boot image</h3>
<p>Some bootloaders are picky where certain components such as the kernel and initramfs should be located within the boot image. postmarketOS maintains a tool called <code>pmbootstrap</code>, which amongst many other things, can analyse boot images to find the correct addresses for different sections.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">$ pmbootstrap bootimg_analyze boot-downstream.img
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_kernel_cmdline</span><span class="o">=</span><span class="s2">&#34;androidboot.hardware=flounder&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_generate_bootimg</span><span class="o">=</span><span class="s2">&#34;true&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_bootimg_qcdt</span><span class="o">=</span><span class="s2">&#34;false&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_bootimg_mtk_mkimage</span><span class="o">=</span><span class="s2">&#34;false&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_bootimg_dtb_second</span><span class="o">=</span><span class="s2">&#34;false&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_pagesize</span><span class="o">=</span><span class="s2">&#34;2048&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_header_version</span><span class="o">=</span><span class="s2">&#34;0&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_offset_base</span><span class="o">=</span><span class="s2">&#34;0x10000000&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_offset_kernel</span><span class="o">=</span><span class="s2">&#34;0x00008000&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_offset_ramdisk</span><span class="o">=</span><span class="s2">&#34;0x01000000&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_offset_second</span><span class="o">=</span><span class="s2">&#34;0x00f00000&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nv">deviceinfo_flash_offset_tags</span><span class="o">=</span><span class="s2">&#34;0x00000100&#34;</span>
</span></span></code></pre></div><p>This information can be used with <code>mkbootimg</code> to create a boot image that will work with this device.</p>
<h2 id="writing-the-mainline-device-tree">Writing the mainline device tree</h2>
<p>A basic device tree can be written with simple information such as the device compatible and memory address. For tegra132 a source for <code>clk32_in</code> is also needed, but for now I&rsquo;ve just used a dummy <code>fixed-clock</code> which should be changed later.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// SPDX-License-Identifier: GPL-2.0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">/</span><span class="n">dts</span><span class="o">-</span><span class="n">v1</span><span class="o">/</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;tegra132.dtsi&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="o">/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">model</span> <span class="o">=</span> <span class="s">&#34;Google Nexus 9&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;google,flounder64&#34;</span><span class="p">,</span> <span class="s">&#34;nvidia,tegra132&#34;</span><span class="p">;</span> <span class="cm">/* bootloader wants this */</span>
</span></span><span class="line"><span class="cl">	<span class="n">chassis</span> <span class="o">=</span> <span class="s">&#34;tablet&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">memory</span><span class="err">@</span><span class="mi">80000000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">device_type</span> <span class="o">=</span> <span class="s">&#34;memory&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0x80000000</span> <span class="mh">0x0</span> <span class="mh">0x80000000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nl">clk32k_in</span><span class="p">:</span> <span class="n">clock</span><span class="o">-</span><span class="mi">32</span><span class="n">k</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;fixed-clock&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">clock</span><span class="o">-</span><span class="n">frequency</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">32768</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="cp">#clock-cells = &lt;0&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>After some testing I found out that I needed to use <code>google,flounder64</code> as the compatible, like the downstream kernel, otherwise HBOOT (the bootloader) would not select it.</p>
<h3 id="framebuffer">Framebuffer</h3>
<p>I don&rsquo;t have UART access, so I had to setup a framebuffer using the memory address provided by the bootloader to check if mainline is booting. The cmdline has this parameter: <code>tegra_fbmem=12713984@0xac001000</code> which contains the memory address and size. This, along with the framebuffer size (screen size), is enough to make a simplefb node.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">		<span class="nl">framebufffer</span><span class="p">:</span> <span class="n">framebuffer</span><span class="err">@</span><span class="n">ac001000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;simple-framebuffer&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0xac001000</span> <span class="mh">0x0</span> <span class="mh">0xc20000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">width</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">1536</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">height</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">2048</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">stride</span> <span class="o">=</span> <span class="o">&lt;</span><span class="p">(</span><span class="mi">1536</span> <span class="o">*</span> <span class="mi">4</span><span class="p">)</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">format</span> <span class="o">=</span> <span class="s">&#34;a8b8g8r8&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span></code></pre></div><p>A <code>reserved-memory</code> node should also be added to make sure that the framebuffer memory is not overwitten by something else:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl">	<span class="n">reserved</span><span class="o">-</span><span class="n">memory</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="cp">#address-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="cp">#size-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="n">ranges</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">framebuffer</span><span class="err">@</span><span class="n">ac001000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0xac001000</span> <span class="mh">0x0</span> <span class="mh">0xc20000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">no</span><span class="o">-</span><span class="n">map</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span></code></pre></div><p>I found out that the framebuffer turns into garbage after a while, which is due to the kernel automatically turning off unused clocks. This should be fixed by adding the correct <code>clocks</code> to the simplefb node, but for now I added the <code>clk_ignore_unused</code> bootarg.</p>
<h3 id="complete-device-tree">Complete Device Tree</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="c1">// SPDX-License-Identifier: GPL-2.0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="o">/</span><span class="n">dts</span><span class="o">-</span><span class="n">v1</span><span class="o">/</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&#34;tegra132.dtsi&#34;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="o">/</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">model</span> <span class="o">=</span> <span class="s">&#34;Google Nexus 9&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;google,flounder64&#34;</span><span class="p">,</span> <span class="s">&#34;nvidia,tegra132&#34;</span><span class="p">;</span> <span class="cm">/* bootloader wants this */</span>
</span></span><span class="line"><span class="cl">	<span class="n">chassis</span> <span class="o">=</span> <span class="s">&#34;tablet&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">chosen</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="cp">#address-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="cp">#size-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="n">ranges</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="n">bootargs</span> <span class="o">=</span> <span class="s">&#34;clk_ignore_unused&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="nl">framebufffer</span><span class="p">:</span> <span class="n">framebuffer</span><span class="err">@</span><span class="n">ac001000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;simple-framebuffer&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0xac001000</span> <span class="mh">0x0</span> <span class="mh">0xc20000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">width</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">1536</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">height</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">2048</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">stride</span> <span class="o">=</span> <span class="o">&lt;</span><span class="p">(</span><span class="mi">1536</span> <span class="o">*</span> <span class="mi">4</span><span class="p">)</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">format</span> <span class="o">=</span> <span class="s">&#34;a8b8g8r8&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">memory</span><span class="err">@</span><span class="mi">80000000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">device_type</span> <span class="o">=</span> <span class="s">&#34;memory&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0x80000000</span> <span class="mh">0x0</span> <span class="mh">0x80000000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="n">reserved</span><span class="o">-</span><span class="n">memory</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="cp">#address-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="cp">#size-cells = &lt;2&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>		<span class="n">ranges</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">framebuffer</span><span class="err">@</span><span class="n">ac001000</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0</span> <span class="mh">0xac001000</span> <span class="mh">0x0</span> <span class="mh">0xc20000</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">			<span class="n">no</span><span class="o">-</span><span class="n">map</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="p">};</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nl">clk32k_in</span><span class="p">:</span> <span class="n">clock</span><span class="o">-</span><span class="mi">32</span><span class="n">k</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;fixed-clock&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">clock</span><span class="o">-</span><span class="n">frequency</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">32768</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="cp">#clock-cells = &lt;0&gt;;
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h2 id="booting">Booting</h2>
<p>The bootloader for this device requires that the DTB be appended to the kernel. This can be done with <code>cat</code>:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">cat arch/arm64/boot/Image.gz arch/arm64/boot/dts/nvidia/tegra132-flounder.dtb &gt; image-dtb
</span></span></code></pre></div><p>A boot image can be made with <code>mkbootimg</code> using the information found by analysing the stock boot image:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">mkbootimg --kernel image-dtb -o boot.img --base 0x10000000 --kernel_offset 0x00008000 --ramdisk_offset 0x01000000 --second_offset 0x00f00000 --tags_offset 0x00000100
</span></span></code></pre></div><p>Now with the mainline boot image, all that&rsquo;s left to do is test it:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">fastboot boot boot.img
</span></span></code></pre></div><p>And it boots! The Linux boot logs print on the screen until it kernel panics because it can&rsquo;t find a root file system.</p>
<h2 id="next-steps">Next steps</h2>
<p>While seeing mainline Linux boot on the device is pretty cool, there needs to be a way for me to be able to run commands on it.</p>
<p>For this, I&rsquo;ll need to:</p>
<ul>
<li>Get USB working</li>
<li>Make a custom initramfs with busybox</li>
<li>Find out more information about this device and the Tegra architecture</li>
</ul>
]]></description></item><item><title>Finding unknown sensors with I²C probing</title><link>https://ansari.sh/posts/finding_sensors_i2c/</link><pubDate>Fri, 07 Jan 2022 19:27:26 +0000</pubDate><guid>https://ansari.sh/posts/finding_sensors_i2c/</guid><description><![CDATA[<p>The <a href="https://github.com/Mainline4Lumia/" target="_blank" rel="noopener noreffer">Mainline4Lumia project</a> aims to bring mainline Linux to the Nokia/Microsoft Lumia phone series, which run a version of Windows Phone. We were making progress quickly, enabling I²C components such as the touchscreen and proximity/light sensor with information found in the stock UEFI tables. However, we couldn&rsquo;t find any information regarding other sensors (accelerometer, gyroscope, magnetometer in the files; not even any GPIO references or I²C bus addresses. Unlike Android devices, which run a fork of the Linux kernel, we can&rsquo;t go and look at the downstream kernel source - so I delved into the schematics to find out.</p>
<h2 id="schematics">Schematics</h2>
<p></p>
<p>This looked like it has the devices I was searching for. They were both wired up to I2C2, and the one with interrupts on <code>GPIO_63</code> and <code>GPIO_49</code> appeared to be an accelerometer (I assumed ACC was the abbreviation for it).
So, the information I knew so far:</p>
<h3 id="accelerometer">Accelerometer</h3>
<ul>
<li>Wired up to I2C2</li>
<li>Two interrupts: INT1 on <code>GPIO_63</code> and INT2 on <code>GPIO_49</code></li>
<li>Supplied by L15 (VDD) and L6 (VID)</li>
</ul>
<h3 id="unknown-device">Unknown device</h3>
<ul>
<li>Wired up to I2C2</li>
<li>No interrupts</li>
<li>Supplied by L15 (VDD) and L6 (VDDIO)</li>
</ul>
<p>This was not enough information to enable support for these devices in the Device Tree (.dts) files. I still didn&rsquo;t know what I²C address they were at, which chips they were, and in the case of the second one what it actually was! It looked like I would have to manually poke I²C addresses&hellip;</p>
<h2 id="ic-probing">I²C Probing</h2>
<h3 id="prerequisites">Prerequisites</h3>
<p>Fortunately, such tools already existed - the aptly named <a href="https://i2c.wiki.kernel.org/index.php/I2C_Tools" target="_blank" rel="noopener noreffer"><code>i2c-tools</code></a> collection, which contained:</p>
<ul>
<li>i2cdetect - <em>detect I2C chips</em></li>
<li>i2cdump - <em>examine I2C registers</em></li>
<li>i2cget - <em>read from I2C/SMBus chip registers</em></li>
<li>i2cset - <em>set I2C registers</em></li>
</ul>
<p>By enabling the I2C2 node in my device&rsquo;s <code>.dts</code> file I could now probe it from userspace.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">&amp;</span><span class="n">blsp1_i2c2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="s">&#34;okay&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><h3 id="ic-addresses">I²C addresses</h3>
<p><div class="details admonition warning open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-exclamation-triangle fa-fw"></i>Warning<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content">Carelessly running I²C commands could lead to components being damaged.</div>
        </div>
    </div>
After SSHing into my Lumia 735 over USB and adding the packages, I first probed all the addresses on the I2C2 bus with <code>i2cdetect</code>.
<div class="details admonition tip open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-lightbulb fa-fw"></i>Tip<i class="details-icon fas fa-angle-right fa-fw"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content">The I²C bus number in the <code>.dts</code> is <strong>not</strong> the same as the I²C bus number that the <code>i2c-tools</code> suite expects. See the <a href="https://www.kernel.org/doc/Documentation/i2c/dev-interface.rst" target="_blank" rel="noopener noreffer">Linux I²C Interface Docs</a>.</div>
        </div>
    </div></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo i2cdetect -y -r [number]
</span></span><span class="line"><span class="cl">     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
</span></span><span class="line"><span class="cl">00:                         -- -- -- -- 0c -- -- --
</span></span><span class="line"><span class="cl">10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 1e --
</span></span><span class="line"><span class="cl">20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
</span></span><span class="line"><span class="cl">30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
</span></span><span class="line"><span class="cl">40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
</span></span><span class="line"><span class="cl">50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
</span></span><span class="line"><span class="cl">60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
</span></span><span class="line"><span class="cl">70: -- -- -- -- -- -- -- --
</span></span></code></pre></div><p>Our two sensors are located at <code>0x0c</code> and <code>0x1e</code>, so now I know what addresses to poke.
To find out which devices are actually located at these addresses, I used <a href="https://i2cdevices.org/" target="_blank" rel="noopener noreffer">i2cdevices.org</a> to find out which I²C devices are known to reside at a specific address.</p>
<h3 id="0x0c"><code>0x0c</code></h3>
<p>According to i2cdevices, <code>0x0c</code> is where Asahi Kasei&rsquo;s magnetometers <a href="https://i2cdevices.org/addresses/0x0c" target="_blank" rel="noopener noreffer">are known to be</a>. To verify this, I enlisted the help of another tool: <code>i2cget</code>. First, I looked up the <code>WHO_AM_I</code> register in the datasheet.</p>
<p>
Asahi Kasei I²C devices should read <code>0x48</code> from the <code>0x00</code> register. So I tested this out:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo i2cget -y [number] 0x0c 0x00
</span></span><span class="line"><span class="cl">0x48
</span></span></code></pre></div><p>It indeed read <code>0x48</code> from <code>0x00</code>. So I tested out the INFO register, <code>0x01</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo i2cget -y [number] 0x0c 0x01
</span></span><span class="line"><span class="cl">0x05
</span></span></code></pre></div><p>So which Asahi Kasei magnetometer was it then? I opened up Linux&rsquo;s <code>ak8975.c</code> driver (which actually supports quite a few Asahi Kasei magnetometers, not just the AK8975) and lo and behold:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define AK09916_DEVICE_ID		0x09
</span></span></span><span class="line"><span class="cl"><span class="cp">#define AK09912_DEVICE_ID		0x04
</span></span></span><span class="line hl"><span class="cl"><span class="cp">#define AK09911_DEVICE_ID		0x05
</span></span></span></code></pre></div><p>It was an <strong>Asahi Kasei AK09911.</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">&amp;</span><span class="n">blsp1_i2c2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="s">&#34;okay&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl">    <span class="nl">ak09911</span><span class="p">:</span> <span class="n">magnetometer</span><span class="err">@</span><span class="n">c</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl">		<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;asahi-kasei,ak09911&#34;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">		<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0c</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">
</span></span><span class="line hl"><span class="cl">		<span class="n">vdd</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l15</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">		<span class="n">vid</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l6</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>I added the highlighted code to the device tree, rebuilt, and checked that the magnetometer was working by checking the values in the iio bus sysfs:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ cat /sys/bus/iio/devices/iio\:device2/in_magn_x_raw
</span></span><span class="line"><span class="cl">7
</span></span></code></pre></div><p>[rotate phone]</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ cat /sys/bus/iio/devices/iio\:device2/in_magn_x_raw
</span></span><span class="line"><span class="cl">12
</span></span></code></pre></div><p>Now that was done and dusted, I moved on to the accelerometer.</p>
<h3 id="0x1e"><code>0x1e</code></h3>
<p>Unfortunately, <code>i2cdevices.org</code> this time didn&rsquo;t show any devices known to be at <code>0x1e</code> that were just accelerometers. There were accelerometer+magnetometer modules listed, but none on their own. I would have to use a different source - existing device trees in the Linux kernel source.</p>
<p><code>$ grep -rn arch/arm64/boot/dts -e '&lt;0x1e&gt;' -B 2</code></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi-180-    lis3mdl: magnetometer@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi-181-            compatible = &#34;st,lis3mdl-magn&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/allwinner/sun50i-a64-pinephone.dtsi:182:            reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts-154-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts-155-         qsgmii_phy3: ethernet-phy@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1046a-frwy.dts:156:                 reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts-115-  mdio1_phy3: ethernet-phy@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts-116-          interrupts-extended = &lt;&amp;extirq 1 IRQ_TYPE_LEVEL_LOW&gt;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-rdb.dts:117:          reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-lx2162a-qds.dts-99-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-lx2162a-qds.dts-100-          mdio@1e { /* Slot #7 */
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-lx2162a-qds.dts:101:                  reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts-514-    magnetometer@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts-515-            compatible = &#34;st,lsm9ds1-magn&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5-devkit.dts:516:            reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts-44-   accelerometer@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts-45-           compatible = &#34;nxp,fxos8700&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1012a-rdb.dts:46:           reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi-885-  magnetometer@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi-886-          compatible = &#34;st,lsm9ds1-magn&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi:887:          reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts-200-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts-201-        mdio1_phy3: ethernet-phy@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/freescale/fsl-ls1088a-ten64.dts:202:                reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-smaug.dts-1316-             ec@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-smaug.dts-1317-                     compatible = &#34;google,cros-ec-i2c&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-smaug.dts:1318:                     reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts-262-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts-263-                         xbar_dspk1_port: port@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra186-p2771-0000.dts:264:                                 reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi-225-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi-226-                                        xbar_dspk1_port: port@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra194-p3509-0000.dtsi:227:                                                reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts-977-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts-978-                         xbar_amx1_in1_port: port@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p2371-2180.dts:979:                                 reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts-1352-
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts-1353-                                xbar_amx1_in1_port: port@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/nvidia/tegra210-p3450-0000.dts:1354:                                        reg = &lt;0x1e&gt;;
</span></span><span class="line"><span class="cl">--
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts-105-     accelerometer@1e {
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts-106-             compatible = &#34;kionix,kx023-1025&#34;;
</span></span><span class="line"><span class="cl">arch/arm64/boot/dts/qcom/msm8916-huawei-g7.dts:107:             reg = &lt;0x1e&gt;;
</span></span></code></pre></div><p>After finding all their specifications, none of them looked like it could be my accelerometer - except the last one. The Kionix KX023-1025, a three-axis accelerometer. I searched online for the datasheet and looked for the <code>WHO_AM_I</code> register.</p>
<p></p>
<p>So the KX023-1025 <em>should</em> report <code>0x15</code> from <code>0x0F</code>.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ i2cget -y [number] 0x1e 0x0f
</span></span><span class="line"><span class="cl">0x14
</span></span></code></pre></div><p>Hmm.
So it isn&rsquo;t the Kionix KX023-1025, but this <code>0x14</code> could mean something. I searched up <code>Kionix WHO_AM_I 0x14h</code> and the first result was the <strong>Kionix KX022-1020</strong> datasheet. I eagerly opened it up, went to the <code>WHO_AM_I</code> register page, and there it was.</p>
<p></p>
<p>Linux didn&rsquo;t seem to have a driver for the KX022-1020, but after skimming over both datasheets, they seemed similar enough.
I added a new accelerometer node in the <code>.dts</code> using the GPIO and supplier information I found previously, along with the I²C address and chip that I found here.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">&amp;</span><span class="n">blsp1_i2c2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="s">&#34;okay&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nl">ak09911</span><span class="p">:</span> <span class="n">magnetometer</span><span class="err">@</span><span class="n">c</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;asahi-kasei,ak09911&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0c</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="n">vdd</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l15</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">vid</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l6</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line hl"><span class="cl">    <span class="nl">kx022_1020</span><span class="p">:</span> <span class="n">accelerometer</span><span class="err">@</span><span class="mi">1</span><span class="n">e</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl">        <span class="cm">/*
</span></span></span><span class="line hl"><span class="cl"><span class="cm">         * This is actually the Kionix KX022-1020, but the KX023-1025 driver
</span></span></span><span class="line hl"><span class="cl"><span class="cm">         * seems to work fine for now.
</span></span></span><span class="line hl"><span class="cl"><span class="cm">         */</span>
</span></span><span class="line hl"><span class="cl">        <span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;kionix,kx023-1025&#34;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">        <span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x1e</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">
</span></span><span class="line hl"><span class="cl">        <span class="n">interrupt</span><span class="o">-</span><span class="n">parent</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">tlmm</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">        <span class="n">interrupts</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">63</span> <span class="n">IRQ_TYPE_EDGE_RISING</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">
</span></span><span class="line hl"><span class="cl">        <span class="n">vdd</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l15</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">        <span class="n">vddio</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l6</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line hl"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>To test, I used the iio-sensor-proxy and monitor-sensor programs.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ sudo service iio-sensor-proxy start
</span></span><span class="line"><span class="cl"> * Starting iio-sensor-proxy ... [ ok ]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">$ monitor-sensor
</span></span><span class="line"><span class="cl">    Waiting for iio-sensor-proxy to appear
</span></span><span class="line"><span class="cl">+++ iio-sensor-proxy appeared
</span></span><span class="line"><span class="cl">=== Has accelerometer (orientation: normal)
</span></span><span class="line"><span class="cl">=== Has ambient light sensor (value: 38.000000, unit: lux)
</span></span><span class="line"><span class="cl">=== No proximity sensor
</span></span><span class="line"><span class="cl">[rotate phone clockwise 360 degrees]
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: normal
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: right-up
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: bottom-up
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: left-up
</span></span></code></pre></div><p>All seemed to be well, except the <code>right-up</code> and <code>left-up</code> orientations were switched. An diagram of these orientations is below.
</p>
<p>This was fixed by using Linux&rsquo;s <code>mount-matrix</code> in the device tree. An explanation of these mount-matrices can be found <a href="https://gitlab.freedesktop.org/hadess/iio-sensor-proxy/#accelerometer-orientation]" target="_blank" rel="noopener noreffer">here</a>.
The <code>mount-matrix</code> that I needed was this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">mount-matrix =  &#34;1&#34;,  &#34;0&#34;,  &#34;0&#34;,
</span></span><span class="line"><span class="cl">                &#34;0&#34;, &#34;-1&#34;,  &#34;0&#34;,
</span></span><span class="line"><span class="cl">                &#34;0&#34;,  &#34;0&#34;,  &#34;1&#34;;
</span></span></code></pre></div><p>This <code>mount-matrix</code> negated the <code>y</code> reading, leading <code>monitor-sensor</code> to report the correct orientations.</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">$ monitor-sensor
</span></span><span class="line"><span class="cl">    Waiting for iio-sensor-proxy to appear
</span></span><span class="line"><span class="cl">+++ iio-sensor-proxy appeared
</span></span><span class="line"><span class="cl">=== Has accelerometer (orientation: normal)
</span></span><span class="line"><span class="cl">=== Has ambient light sensor (value: 19.000000, unit: lux)
</span></span><span class="line"><span class="cl">=== No proximity sensor
</span></span><span class="line"><span class="cl">[rotate phone clockwise 360 degrees]
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: normal
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: left-up
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: bottom-up
</span></span><span class="line"><span class="cl">    Accelerometer orientation changed: right-up
</span></span></code></pre></div><h2 id="final-dts-node">Final DTS node</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="o">&amp;</span><span class="n">blsp1_i2c2</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">status</span> <span class="o">=</span> <span class="s">&#34;okay&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nl">ak09911</span><span class="p">:</span> <span class="n">magnetometer</span><span class="err">@</span><span class="n">c</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;asahi-kasei,ak09911&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x0c</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="n">vdd</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l15</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">		<span class="n">vid</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l6</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">	<span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="nl">kx022_1020</span><span class="p">:</span> <span class="n">accelerometer</span><span class="err">@</span><span class="mi">1</span><span class="n">e</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="cm">/*
</span></span></span><span class="line"><span class="cl"><span class="cm">         * This is actually the Kionix KX022-1020, but the KX023-1025 driver
</span></span></span><span class="line"><span class="cl"><span class="cm">         * seems to work fine for now.
</span></span></span><span class="line"><span class="cl"><span class="cm">         */</span>
</span></span><span class="line"><span class="cl">        <span class="n">compatible</span> <span class="o">=</span> <span class="s">&#34;kionix,kx023-1025&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">reg</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mh">0x1e</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">interrupt</span><span class="o">-</span><span class="n">parent</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">tlmm</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">interrupts</span> <span class="o">=</span> <span class="o">&lt;</span><span class="mi">63</span> <span class="n">IRQ_TYPE_EDGE_RISING</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">vdd</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l15</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="n">vddio</span><span class="o">-</span><span class="n">supply</span> <span class="o">=</span> <span class="o">&lt;&amp;</span><span class="n">pm8226_l6</span><span class="o">&gt;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">mount</span><span class="o">-</span><span class="n">matrix</span> <span class="o">=</span>  <span class="s">&#34;1&#34;</span><span class="p">,</span>  <span class="s">&#34;0&#34;</span><span class="p">,</span>  <span class="s">&#34;0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s">&#34;0&#34;</span><span class="p">,</span> <span class="s">&#34;-1&#34;</span><span class="p">,</span>  <span class="s">&#34;0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s">&#34;0&#34;</span><span class="p">,</span>  <span class="s">&#34;0&#34;</span><span class="p">,</span>  <span class="s">&#34;1&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl"><span class="p">};</span>
</span></span></code></pre></div><p>Now that the sensor collection is complete, we&rsquo;re looking into enabling features such as charging, WiFi and camera. Once more progress is made, there&rsquo;ll be more Lumia-related articles here! ;-)</p>
]]></description></item></channel></rss>