<p>Harald Welte has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/13030">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">Support for sysmoOCTSIM NCN8025/SX1503 control<br><br>This adds an I2C bit-banging layer, defines the four busses on the<br>sysmoOCTSIM and adds some high-level functions to control the NCN8025<br>for each SIM slot.<br><br>Change-Id: Ic5287cf80d2be2070c504e9d40f7c6fc0d37d8b9<br>---<br>M sysmoOCTSIM/gcc/Makefile<br>A sysmoOCTSIM/i2c_bitbang.c<br>A sysmoOCTSIM/i2c_bitbang.h<br>M sysmoOCTSIM/main.c<br>A sysmoOCTSIM/ncn8025.c<br>A sysmoOCTSIM/ncn8025.h<br>A sysmoOCTSIM/octsim_i2c.c<br>A sysmoOCTSIM/octsim_i2c.h<br>8 files changed, 438 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/30/13030/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/sysmoOCTSIM/gcc/Makefile b/sysmoOCTSIM/gcc/Makefile</span><br><span>index 572fb21..5e3c38c 100644</span><br><span>--- a/sysmoOCTSIM/gcc/Makefile</span><br><span>+++ b/sysmoOCTSIM/gcc/Makefile</span><br><span>@@ -70,6 +70,9 @@</span><br><span> gcc/gcc/startup_same54.o \</span><br><span> hal/src/hal_usb_device.o \</span><br><span> main.o \</span><br><span style="color: hsl(120, 100%, 40%);">+i2c_bitbang.o \</span><br><span style="color: hsl(120, 100%, 40%);">+octsim_i2c.o \</span><br><span style="color: hsl(120, 100%, 40%);">+ncn8025.o \</span><br><span> hpl/osc32kctrl/hpl_osc32kctrl.o \</span><br><span> examples/driver_examples.o \</span><br><span> driver_init.o \</span><br><span>@@ -108,6 +111,9 @@</span><br><span> "gcc/gcc/startup_same54.o" \</span><br><span> "hal/src/hal_usb_device.o" \</span><br><span> "main.o" \</span><br><span style="color: hsl(120, 100%, 40%);">+"i2c_bitbang.o" \</span><br><span style="color: hsl(120, 100%, 40%);">+"octsim_i2c.o" \</span><br><span style="color: hsl(120, 100%, 40%);">+"ncn8025.o" \</span><br><span> "hpl/osc32kctrl/hpl_osc32kctrl.o" \</span><br><span> "examples/driver_examples.o" \</span><br><span> "driver_init.o" \</span><br><span>@@ -152,6 +158,9 @@</span><br><span> "hal/src/hal_usart_async.d" \</span><br><span> "hpl/osc32kctrl/hpl_osc32kctrl.d" \</span><br><span> "main.d" \</span><br><span style="color: hsl(120, 100%, 40%);">+"i2c_bitbang.d" \</span><br><span style="color: hsl(120, 100%, 40%);">+"octsim_i2c.d" \</span><br><span style="color: hsl(120, 100%, 40%);">+"ncn8025.d" \</span><br><span> "examples/driver_examples.d" \</span><br><span> "hal/src/hal_cache.d" \</span><br><span> "hal/src/hal_sleep.d" \</span><br><span>diff --git a/sysmoOCTSIM/i2c_bitbang.c b/sysmoOCTSIM/i2c_bitbang.c</span><br><span>new file mode 100644</span><br><span>index 0000000..b1a9a62</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/i2c_bitbang.c</span><br><span>@@ -0,0 +1,189 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Bit-banging I2C layer, inspired to a large extent from Linux kernel</span><br><span style="color: hsl(120, 100%, 40%);">+ * i2c-algo-bit.c code (C) 1995-2000 Simon G. Vogl.  This particular</span><br><span style="color: hsl(120, 100%, 40%);">+ * implementation is (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  SPDX-License-Identifier: GPL-2.0-or-later</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <hal_gpio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <hal_delay.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <err_codes.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "i2c_bitbang.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define setsda(adap, val)   gpio_set_pin_level((adap)->pin_sda, val)</span><br><span style="color: hsl(120, 100%, 40%);">+#define setscl(adap, val)  gpio_set_pin_level((adap)->pin_scl, val)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int getsda(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       gpio_set_pin_direction(adap->pin_sda, GPIO_DIRECTION_IN);</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = gpio_get_pin_level(adap->pin_sda);</span><br><span style="color: hsl(120, 100%, 40%);">+    gpio_set_pin_direction(adap->pin_sda, GPIO_DIRECTION_OUT);</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int getscl(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       gpio_set_pin_direction(adap->pin_scl, GPIO_DIRECTION_IN);</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = gpio_get_pin_level(adap->pin_scl);</span><br><span style="color: hsl(120, 100%, 40%);">+    gpio_set_pin_direction(adap->pin_scl, GPIO_DIRECTION_OUT);</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void sdalo(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  setsda(adap, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      delay_us((adap->udelay+1) / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void sdahi(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  setsda(adap, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+      delay_us((adap->udelay+1) / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static inline void scllo(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  setscl(adap, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      delay_us(adap->udelay / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sclhi(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    setscl(adap, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* wait for slow slaves' clock stretching to complete */</span><br><span style="color: hsl(120, 100%, 40%);">+  while (!getscl(adap)) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* FIXME: abort at some point */</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void i2c_start(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Assert: SCL + SDA are high */</span><br><span style="color: hsl(120, 100%, 40%);">+      setsda(adap, 0);                /* set SDA to low */</span><br><span style="color: hsl(120, 100%, 40%);">+  delay_us(adap->udelay);              /* delay */</span><br><span style="color: hsl(120, 100%, 40%);">+   scllo(adap);                    /* Set SCL to low */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void i2c_repstart(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Assert: SCL is low */</span><br><span style="color: hsl(120, 100%, 40%);">+      sdahi(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  sclhi(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  setsda(adap, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+      delay_us(adap->udelay);</span><br><span style="color: hsl(120, 100%, 40%);">+    scllo(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void i2c_stop(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Assert: SCL is low */</span><br><span style="color: hsl(120, 100%, 40%);">+      sdalo(adap);                    /* set SDA low */</span><br><span style="color: hsl(120, 100%, 40%);">+     sclhi(adap);                    /* set SCL to high */</span><br><span style="color: hsl(120, 100%, 40%);">+ setsda(adap, 1);                /* set SDA to high */</span><br><span style="color: hsl(120, 100%, 40%);">+ delay_us(adap->udelay);              /* delay */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int i2c_outb(const struct i2c_adapter *adap, uint8_t outdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t sb;</span><br><span style="color: hsl(120, 100%, 40%);">+   int ack, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Assert: SCL is low */</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 7; i >= 0; i--) {</span><br><span style="color: hsl(120, 100%, 40%);">+         sb = (outdata >> i) & 1;</span><br><span style="color: hsl(120, 100%, 40%);">+            setsda(adap, sb);</span><br><span style="color: hsl(120, 100%, 40%);">+             delay_us((adap->udelay + 1) / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (sclhi(adap) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -ERR_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+          scllo(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     sdahi(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (sclhi(adap) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+               return -ERR_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+  ack = !getsda(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  scllo(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  return ack;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int i2c_inb(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t indata = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Assert: CSL is low */</span><br><span style="color: hsl(120, 100%, 40%);">+      sdahi(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < 8; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* SCL high */</span><br><span style="color: hsl(120, 100%, 40%);">+                if (sclhi(adap) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return -ERR_TIMEOUT;</span><br><span style="color: hsl(120, 100%, 40%);">+          indata = indata << 1;</span><br><span style="color: hsl(120, 100%, 40%);">+           if (getsda(adap))</span><br><span style="color: hsl(120, 100%, 40%);">+                     indata |= 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+               setscl(adap, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (i == 7)</span><br><span style="color: hsl(120, 100%, 40%);">+                   delay_us(adap->udelay / 2);</span><br><span style="color: hsl(120, 100%, 40%);">+                else</span><br><span style="color: hsl(120, 100%, 40%);">+                  delay_us(adap->udelay);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Assert: SCL is low */</span><br><span style="color: hsl(120, 100%, 40%);">+      return indata;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Single-byte register write. Assumes 8bit register address + 8bit values */</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_write_reg(const struct i2c_adapter *adap, uint8_t addr, uint8_t reg, uint8_t val)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     i2c_start(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = i2c_outb(adap, addr << 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = i2c_outb(adap, reg);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = i2c_outb(adap, val);</span><br><span style="color: hsl(120, 100%, 40%);">+out_stop:</span><br><span style="color: hsl(120, 100%, 40%);">+  i2c_stop(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Single-byte register read. Assumes 8bit register address + 8bit values */</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_read_reg(const struct i2c_adapter *adap, uint8_t addr, uint8_t reg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     i2c_start(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = i2c_outb(adap, addr << 1);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = i2c_outb(adap, reg);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+        i2c_repstart(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = i2c_outb(adap, addr << 1 | 1);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto out_stop;</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = i2c_inb(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+out_stop:</span><br><span style="color: hsl(120, 100%, 40%);">+        i2c_stop(adap);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Initialize a given I2C adapter/bus */</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_init(const struct i2c_adapter *adap)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   gpio_set_pin_direction(adap->pin_sda, GPIO_DIRECTION_OUT);</span><br><span style="color: hsl(120, 100%, 40%);">+ gpio_set_pin_direction(adap->pin_scl, GPIO_DIRECTION_OUT);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* Bring bus to a known state. Looks like STOP if bus is not free yet */</span><br><span style="color: hsl(120, 100%, 40%);">+      setscl(adap, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+      delay_us(adap->udelay);</span><br><span style="color: hsl(120, 100%, 40%);">+    setsda(adap, 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/sysmoOCTSIM/i2c_bitbang.h b/sysmoOCTSIM/i2c_bitbang.h</span><br><span>new file mode 100644</span><br><span>index 0000000..7157c2e</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/i2c_bitbang.h</span><br><span>@@ -0,0 +1,13 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct i2c_adapter {</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t pin_scl;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint8_t pin_sda;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint32_t udelay;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_init(const struct i2c_adapter *adap);</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_write_reg(const struct i2c_adapter *adap, uint8_t addr, uint8_t reg, uint8_t val);</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_read_reg(const struct i2c_adapter *adap, uint8_t addr, uint8_t reg);</span><br><span style="color: hsl(120, 100%, 40%);">+int i2c_init(const struct i2c_adapter *adap);</span><br><span>diff --git a/sysmoOCTSIM/main.c b/sysmoOCTSIM/main.c</span><br><span>index d74153d..40f2147 100644</span><br><span>--- a/sysmoOCTSIM/main.c</span><br><span>+++ b/sysmoOCTSIM/main.c</span><br><span>@@ -19,6 +19,10 @@</span><br><span> #include "atmel_start.h"</span><br><span> #include "atmel_start_pins.h"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include "i2c_bitbang.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "octsim_i2c.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ncn8025.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> volatile static bool data_arrived = false;</span><br><span> </span><br><span> static void tx_cb_UART_debug(const struct usart_async_descriptor *const io_descr)</span><br><span>@@ -34,6 +38,18 @@</span><br><span>   data_arrived = true;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void board_init()</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < 4; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            i2c_init(&i2c[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* only 7 slots, as last slot is debug uart! */</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < 7; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+            ncn8025_init(i);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> int main(void)</span><br><span> {</span><br><span>         atmel_start_init();</span><br><span>@@ -44,6 +60,8 @@</span><br><span> </span><br><span>  usb_start();</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+      board_init();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      const char* welcome = "\r\n\r\nsysmocom sysmoOCTSIM\r\n";</span><br><span>  while (io_write(&UART_debug.io, (const uint8_t*)welcome, strlen(welcome)) != strlen(welcome)); // print welcome message</span><br><span>  while (true) { // main loop</span><br><span>diff --git a/sysmoOCTSIM/ncn8025.c b/sysmoOCTSIM/ncn8025.c</span><br><span>new file mode 100644</span><br><span>index 0000000..0dd4dd2</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/ncn8025.c</span><br><span>@@ -0,0 +1,136 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Access functions for the per-SIM-slot NCN8025 chip card interface,</span><br><span style="color: hsl(120, 100%, 40%);">+ * which is controlled via (half) a SX1503 I2C GPIO expander.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  SPDX-License-Identifier: GPL-2.0-or-later</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <utils_assert.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include "octsim_i2c.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "ncn8025.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define SX1503_ADDR     0x20</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! translate from ncn8025_settings into SX1503 register value */</span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t ncn8025_encode(const struct ncn8025_settings *set)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t reg = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      if (set->rstin)</span><br><span style="color: hsl(120, 100%, 40%);">+            reg |= 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!set->cmdvcc)</span><br><span style="color: hsl(120, 100%, 40%);">+          reg |= 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (set->clkdiv & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+           reg |= 0x04;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (set->clkdiv & 2)</span><br><span style="color: hsl(120, 100%, 40%);">+           reg |= 0x08;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (set->vsel & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+             reg |= 0x10;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (set->vsel & 2)</span><br><span style="color: hsl(120, 100%, 40%);">+             reg |= 0x20;</span><br><span style="color: hsl(120, 100%, 40%);">+  if (set->led)</span><br><span style="color: hsl(120, 100%, 40%);">+              reg |= 0x80;</span><br><span style="color: hsl(120, 100%, 40%);">+  return reg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! translate from register value to ncn8025_settings */</span><br><span style="color: hsl(120, 100%, 40%);">+static int ncn8025_decode(uint8_t reg, struct ncn8025_settings *set)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   memset(set, 0, sizeof(*set));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (reg & 0x01)</span><br><span style="color: hsl(120, 100%, 40%);">+           set->rstin = true;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(reg & 0x02))</span><br><span style="color: hsl(120, 100%, 40%);">+                set->cmdvcc = true;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (reg & 0x04)</span><br><span style="color: hsl(120, 100%, 40%);">+           set->clkdiv |= 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (reg & 0x08)</span><br><span style="color: hsl(120, 100%, 40%);">+           set->clkdiv |= 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (reg & 0x10)</span><br><span style="color: hsl(120, 100%, 40%);">+           set->vsel |= 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (reg & 0x20)</span><br><span style="color: hsl(120, 100%, 40%);">+           set->vsel |= 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!(reg & 0x40))</span><br><span style="color: hsl(120, 100%, 40%);">+                set->simpres = true;</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!(reg & 0x80))</span><br><span style="color: hsl(120, 100%, 40%);">+                set->led = true;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct i2c_adapter *slot2adapter(unsigned int slot)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int idx = slot / 2;</span><br><span style="color: hsl(120, 100%, 40%);">+  ASSERT(idx < ARRAY_SIZE(i2c));</span><br><span style="color: hsl(120, 100%, 40%);">+     return &i2c[idx];</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t slot2data_reg(unsigned int slot)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (slot & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0x00;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0x01;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const uint8_t slot2dir_reg(unsigned int slot)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    if (slot & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+             return 0x02;</span><br><span style="color: hsl(120, 100%, 40%);">+  else</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0x03;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Set a given NCN8025 as described in 'set'.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] slot Slot number (0..7)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] set Settings that shall be written</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_set(uint8_t slot, const struct ncn8025_settings *set)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct i2c_adapter *adap = slot2adapter(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t reg = slot2data_reg(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t raw = ncn8025_encode(set);</span><br><span style="color: hsl(120, 100%, 40%);">+    return i2c_write_reg(adap, SX1503_ADDR, reg, raw);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Get a given NCN8025 state from the chip.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] slot Slot number (0..7)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] set Settings that are retrieved</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 0 on success; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_get(uint8_t slot, struct ncn8025_settings *set)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const struct i2c_adapter *adap = slot2adapter(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t reg = slot2data_reg(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = i2c_read_reg(adap, SX1503_ADDR, reg);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    return ncn8025_decode(rc, set);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! default settings we use at start-up: powered off, in reset, slowest clock, 3V */</span><br><span style="color: hsl(120, 100%, 40%);">+static const struct ncn8025_settings def_settings = {</span><br><span style="color: hsl(120, 100%, 40%);">+     .rstin = true,</span><br><span style="color: hsl(120, 100%, 40%);">+        .cmdvcc = false,</span><br><span style="color: hsl(120, 100%, 40%);">+      .led = false,</span><br><span style="color: hsl(120, 100%, 40%);">+ .clkdiv = SIM_CLKDIV_8,</span><br><span style="color: hsl(120, 100%, 40%);">+       .vsel = SIM_VOLT_3V0,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Initialize a given NCN8025/slot. */</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_init(unsigned int slot)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  const struct i2c_adapter *adap = slot2adapter(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+  uint8_t reg = slot2dir_reg(slot);</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* IO6 of each bank is input (!PRESENT), rest are outputs */</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = i2c_write_reg(adap, SX1503_ADDR, reg, 0x40);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+    return ncn8025_set(slot, &def_settings);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/sysmoOCTSIM/ncn8025.h b/sysmoOCTSIM/ncn8025.h</span><br><span>new file mode 100644</span><br><span>index 0000000..a392c5d</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/ncn8025.h</span><br><span>@@ -0,0 +1,28 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ncn8025_sim_voltage {</span><br><span style="color: hsl(120, 100%, 40%);">+ SIM_VOLT_3V0 = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_VOLT_5V0 = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_VOLT_1V8 = 3</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum ncn8025_sim_clkdiv {</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_CLKDIV_1 = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_CLKDIV_2 = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_CLKDIV_4 = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+     SIM_CLKDIV_8 = 0,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ncn8025_settings {</span><br><span style="color: hsl(120, 100%, 40%);">+    bool rstin;     /* high: active */</span><br><span style="color: hsl(120, 100%, 40%);">+    bool cmdvcc;    /* high: active */</span><br><span style="color: hsl(120, 100%, 40%);">+    bool simpres;   /* high: active */</span><br><span style="color: hsl(120, 100%, 40%);">+    bool led;       /* high: active */</span><br><span style="color: hsl(120, 100%, 40%);">+    enum ncn8025_sim_clkdiv clkdiv; /* raw 2bit value */</span><br><span style="color: hsl(120, 100%, 40%);">+  enum ncn8025_sim_voltage vsel;  /* raw 2bit value */</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_set(uint8_t slot, const struct ncn8025_settings *set);</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_get(uint8_t slot, struct ncn8025_settings *set);</span><br><span style="color: hsl(120, 100%, 40%);">+int ncn8025_init(unsigned int slot);</span><br><span>diff --git a/sysmoOCTSIM/octsim_i2c.c b/sysmoOCTSIM/octsim_i2c.c</span><br><span>new file mode 100644</span><br><span>index 0000000..c552794</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/octsim_i2c.c</span><br><span>@@ -0,0 +1,41 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#include "atmel_start_pins.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "i2c_bitbang.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define I2C_DELAY_US  5       /* 100 kHz */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef SDA1</span><br><span style="color: hsl(120, 100%, 40%);">+/* We should define those pins in Atmel START. Until they are, define them here */</span><br><span style="color: hsl(120, 100%, 40%);">+#define SDA1 GPIO(GPIO_PORTB, 15)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCL1 GPIO(GPIO_PORTB, 14)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SDA2 GPIO(GPIO_PORTB, 3)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCL2 GPIO(GPIO_PORTB, 2)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SDA3 GPIO(GPIO_PORTB, 7)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCL3 GPIO(GPIO_PORTB, 6)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SDA4 GPIO(GPIO_PORTC, 28)</span><br><span style="color: hsl(120, 100%, 40%);">+#define SCL4 GPIO(GPIO_PORTC, 27)</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Unfortunately the schematics count I2C busses from '1', not from '0' :(</span><br><span style="color: hsl(120, 100%, 40%);">+ * In software, we [obviously] count from '0' upwards. */</span><br><span style="color: hsl(120, 100%, 40%);">+const struct i2c_adapter i2c[4] = {</span><br><span style="color: hsl(120, 100%, 40%);">+   [0] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .pin_sda = SDA1,</span><br><span style="color: hsl(120, 100%, 40%);">+              .pin_scl = SCL1,</span><br><span style="color: hsl(120, 100%, 40%);">+              .udelay = I2C_DELAY_US,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [1] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .pin_sda = SDA2,</span><br><span style="color: hsl(120, 100%, 40%);">+              .pin_scl = SCL2,</span><br><span style="color: hsl(120, 100%, 40%);">+              .udelay = I2C_DELAY_US,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [2] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .pin_sda = SDA3,</span><br><span style="color: hsl(120, 100%, 40%);">+              .pin_scl = SCL3,</span><br><span style="color: hsl(120, 100%, 40%);">+              .udelay = I2C_DELAY_US,</span><br><span style="color: hsl(120, 100%, 40%);">+       },</span><br><span style="color: hsl(120, 100%, 40%);">+    [3] = {</span><br><span style="color: hsl(120, 100%, 40%);">+               .pin_sda = SDA4,</span><br><span style="color: hsl(120, 100%, 40%);">+              .pin_scl = SCL4,</span><br><span style="color: hsl(120, 100%, 40%);">+              .udelay = I2C_DELAY_US,</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span>diff --git a/sysmoOCTSIM/octsim_i2c.h b/sysmoOCTSIM/octsim_i2c.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5e20ea0</span><br><span>--- /dev/null</span><br><span>+++ b/sysmoOCTSIM/octsim_i2c.h</span><br><span>@@ -0,0 +1,4 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include "i2c_bitbang.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+extern const struct i2c_adapter i2c[4];</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13030">change 13030</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13030"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-ccid-firmware </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ic5287cf80d2be2070c504e9d40f7c6fc0d37d8b9 </div>
<div style="display:none"> Gerrit-Change-Number: 13030 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>