Change in osmo-ccid-firmware[master]: Support for sysmoOCTSIM NCN8025/SX1503 control

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Harald Welte gerrit-no-reply at lists.osmocom.org
Sun Feb 24 08:46:58 UTC 2019


Harald Welte has uploaded this change for review. ( https://gerrit.osmocom.org/13030


Change subject: Support for sysmoOCTSIM NCN8025/SX1503 control
......................................................................

Support for sysmoOCTSIM NCN8025/SX1503 control

This adds an I2C bit-banging layer, defines the four busses on the
sysmoOCTSIM and adds some high-level functions to control the NCN8025
for each SIM slot.

Change-Id: Ic5287cf80d2be2070c504e9d40f7c6fc0d37d8b9
---
M sysmoOCTSIM/gcc/Makefile
A sysmoOCTSIM/i2c_bitbang.c
A sysmoOCTSIM/i2c_bitbang.h
M sysmoOCTSIM/main.c
A sysmoOCTSIM/ncn8025.c
A sysmoOCTSIM/ncn8025.h
A sysmoOCTSIM/octsim_i2c.c
A sysmoOCTSIM/octsim_i2c.h
8 files changed, 438 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-ccid-firmware refs/changes/30/13030/1

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

-- 
To view, visit https://gerrit.osmocom.org/13030
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-ccid-firmware
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic5287cf80d2be2070c504e9d40f7c6fc0d37d8b9
Gerrit-Change-Number: 13030
Gerrit-PatchSet: 1
Gerrit-Owner: Harald Welte <laforge at gnumonks.org>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20190224/398051db/attachment.htm>


More information about the gerrit-log mailing list