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.orgHarald 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>