From 398459b5998ed1a3f9b82d6ca85f0c62e55445ba Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 15 Feb 2015 19:48:34 +0100 Subject: Add code to control the PA of the SOB-BTS At least in v1 of the SOB-BTS, there is a SX1502 I2C GPIO expander to control the two different PAs in the system. This adds a SX150x driver on top of Linux userspae i2c-dev access, and a thin layer of API functions as well as a command line tool. The code is currently still untested. --- src/osmo-bts-sysmo/Makefile.am | 7 +- src/osmo-bts-sysmo/misc/i2c-dev.h | 335 ++++++++++++++++++++++++++++++ src/osmo-bts-sysmo/misc/sob_bts_pa.c | 73 +++++++ src/osmo-bts-sysmo/misc/sob_bts_pa.h | 4 + src/osmo-bts-sysmo/misc/sob_bts_pa_ctrl.c | 48 +++++ src/osmo-bts-sysmo/misc/sx150x.c | 137 ++++++++++++ src/osmo-bts-sysmo/misc/sx150x.h | 19 ++ 7 files changed, 621 insertions(+), 2 deletions(-) create mode 100644 src/osmo-bts-sysmo/misc/i2c-dev.h create mode 100644 src/osmo-bts-sysmo/misc/sob_bts_pa.c create mode 100644 src/osmo-bts-sysmo/misc/sob_bts_pa.h create mode 100644 src/osmo-bts-sysmo/misc/sob_bts_pa_ctrl.c create mode 100644 src/osmo-bts-sysmo/misc/sx150x.c create mode 100644 src/osmo-bts-sysmo/misc/sx150x.h diff --git a/src/osmo-bts-sysmo/Makefile.am b/src/osmo-bts-sysmo/Makefile.am index 68e3ce64..83c557fd 100644 --- a/src/osmo-bts-sysmo/Makefile.am +++ b/src/osmo-bts-sysmo/Makefile.am @@ -4,9 +4,10 @@ COMMON_LDADD = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOVTY_LIBS) $(LIBOS EXTRA_DIST = misc/sysmobts_mgr.h misc/sysmobts_misc.h misc/sysmobts_par.h \ misc/sysmobts_eeprom.h misc/sysmobts_nl.h femtobts.h hw_misc.h \ - l1_fwd.h l1_if.h l1_transp.h eeprom.h utils.h oml_router.h + l1_fwd.h l1_if.h l1_transp.h eeprom.h utils.h oml_router.h \ + misc/sx150x.h misc/sob_bts_pa.h misc/i2c-dev.h -bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy sysmobts-mgr sysmobts-util +bin_PROGRAMS = sysmobts sysmobts-remote l1fwd-proxy sysmobts-mgr sysmobts-util sob-bts-pa-ctrl COMMON_SOURCES = main.c femtobts.c l1_if.c oml.c sysmobts_vty.c tch.c hw_misc.c calib_file.c \ eeprom.c calib_fixup.c utils.c misc/sysmobts_par.c oml_router.c sysmobts_ctrl.c @@ -33,3 +34,5 @@ sysmobts_mgr_LDADD = $(LIBGPS_LIBS) $(LIBOSMOCORE_LIBS) $(LIBOSMOVTY_LIBS) $(LIB sysmobts_util_SOURCES = misc/sysmobts_util.c misc/sysmobts_par.c eeprom.c sysmobts_util_LDADD = $(LIBOSMOCORE_LIBS) + +sob_bts_pa_ctrl_SOURCES = misc/sx150x.c misc/sob_bts_pa.c misc/sob_bts_pa_ctrl.c diff --git a/src/osmo-bts-sysmo/misc/i2c-dev.h b/src/osmo-bts-sysmo/misc/i2c-dev.h new file mode 100644 index 00000000..b9358174 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/i2c-dev.h @@ -0,0 +1,335 @@ +/* + i2c-dev.h - i2c-bus driver, char device interface + + Copyright (C) 1995-97 Simon G. Vogl + Copyright (C) 1998-99 Frodo Looijaard + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301 USA. +*/ + +/* $Id: i2c-dev.h 5894 2010-12-12 13:22:29Z khali $ */ + +#ifndef LIB_I2CDEV_H +#define LIB_I2CDEV_H + +#include +#include + + +/* -- i2c.h -- */ + + +/* + * I2C Message - used for pure i2c transaction, also from /dev interface + */ +struct i2c_msg { + __u16 addr; /* slave address */ + unsigned short flags; +#define I2C_M_TEN 0x10 /* we have a ten bit chip address */ +#define I2C_M_RD 0x01 +#define I2C_M_NOSTART 0x4000 +#define I2C_M_REV_DIR_ADDR 0x2000 +#define I2C_M_IGNORE_NAK 0x1000 +#define I2C_M_NO_RD_ACK 0x0800 + short len; /* msg length */ + char *buf; /* pointer to msg data */ +}; + +/* To determine what functionality is present */ + +#define I2C_FUNC_I2C 0x00000001 +#define I2C_FUNC_10BIT_ADDR 0x00000002 +#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 /* I2C_M_{REV_DIR_ADDR,NOSTART,..} */ +#define I2C_FUNC_SMBUS_PEC 0x00000008 +#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 /* SMBus 2.0 */ +#define I2C_FUNC_SMBUS_QUICK 0x00010000 +#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 +#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 +#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 +#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 +#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 +#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 +#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 +#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 +#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 +#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 /* I2C-like block xfer */ +#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 /* w/ 1-byte reg. addr. */ + +#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ + I2C_FUNC_SMBUS_WRITE_BYTE) +#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ + I2C_FUNC_SMBUS_WRITE_BYTE_DATA) +#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ + I2C_FUNC_SMBUS_WRITE_WORD_DATA) +#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ + I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) +#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) + +/* Old name, for compatibility */ +#define I2C_FUNC_SMBUS_HWPEC_CALC I2C_FUNC_SMBUS_PEC + +/* + * Data for SMBus Messages + */ +#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */ +#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */ +union i2c_smbus_data { + __u8 byte; + __u16 word; + __u8 block[I2C_SMBUS_BLOCK_MAX + 2]; /* block[0] is used for length */ + /* and one more for PEC */ +}; + +/* smbus_access read or write markers */ +#define I2C_SMBUS_READ 1 +#define I2C_SMBUS_WRITE 0 + +/* SMBus transaction types (size parameter in the above functions) + Note: these no longer correspond to the (arbitrary) PIIX4 internal codes! */ +#define I2C_SMBUS_QUICK 0 +#define I2C_SMBUS_BYTE 1 +#define I2C_SMBUS_BYTE_DATA 2 +#define I2C_SMBUS_WORD_DATA 3 +#define I2C_SMBUS_PROC_CALL 4 +#define I2C_SMBUS_BLOCK_DATA 5 +#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 +#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */ +#define I2C_SMBUS_I2C_BLOCK_DATA 8 + + +/* ----- commands for the ioctl like i2c_command call: + * note that additional calls are defined in the algorithm and hw + * dependent layers - these can be listed here, or see the + * corresponding header files. + */ + /* -> bit-adapter specific ioctls */ +#define I2C_RETRIES 0x0701 /* number of times a device address */ + /* should be polled when not */ + /* acknowledging */ +#define I2C_TIMEOUT 0x0702 /* set timeout - call with int */ + + +/* this is for i2c-dev.c */ +#define I2C_SLAVE 0x0703 /* Change slave address */ + /* Attn.: Slave address is 7 or 10 bits */ +#define I2C_SLAVE_FORCE 0x0706 /* Change slave address */ + /* Attn.: Slave address is 7 or 10 bits */ + /* This changes the address, even if it */ + /* is already taken! */ +#define I2C_TENBIT 0x0704 /* 0 for 7 bit addrs, != 0 for 10 bit */ + +#define I2C_FUNCS 0x0705 /* Get the adapter functionality */ +#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only)*/ +#define I2C_PEC 0x0708 /* != 0 for SMBus PEC */ + +#define I2C_SMBUS 0x0720 /* SMBus-level access */ + +/* -- i2c.h -- */ + + +/* Note: 10-bit addresses are NOT supported! */ + +/* This is the structure as used in the I2C_SMBUS ioctl call */ +struct i2c_smbus_ioctl_data { + char read_write; + __u8 command; + int size; + union i2c_smbus_data *data; +}; + +/* This is the structure as used in the I2C_RDWR ioctl call */ +struct i2c_rdwr_ioctl_data { + struct i2c_msg *msgs; /* pointers to i2c_msgs */ + int nmsgs; /* number of i2c_msgs */ +}; + + +static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_smbus_ioctl_data args; + + args.read_write = read_write; + args.command = command; + args.size = size; + args.data = data; + return ioctl(file,I2C_SMBUS,&args); +} + + +static inline __s32 i2c_smbus_write_quick(int file, __u8 value) +{ + return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL); +} + +static inline __s32 i2c_smbus_read_byte(int file) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte(int file, __u8 value) +{ + return i2c_smbus_access(file,I2C_SMBUS_WRITE,value, + I2C_SMBUS_BYTE,NULL); +} + +static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BYTE_DATA,&data)) + return -1; + else + return 0x0FF & data.byte; +} + +static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, + __u8 value) +{ + union i2c_smbus_data data; + data.byte = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BYTE_DATA, &data); +} + +static inline __s32 i2c_smbus_read_word_data(int file, __u8 command) +{ + union i2c_smbus_data data; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_WORD_DATA,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + +static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, + __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_WORD_DATA, &data); +} + +static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value) +{ + union i2c_smbus_data data; + data.word = value; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_PROC_CALL,&data)) + return -1; + else + return 0x0FFFF & data.word; +} + + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, + __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + I2C_SMBUS_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, + __u8 length, const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_DATA, &data); +} + +/* Returns the number of read bytes */ +/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you + ask for less than 32 bytes, your code will only work with kernels + 2.6.23 and later. */ +static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + + if (length > 32) + length = 32; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_READ,command, + length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN : + I2C_SMBUS_I2C_BLOCK_DATA,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + +static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command, + __u8 length, + const __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + return i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_I2C_BLOCK_BROKEN, &data); +} + +/* Returns the number of read bytes */ +static inline __s32 i2c_smbus_block_process_call(int file, __u8 command, + __u8 length, __u8 *values) +{ + union i2c_smbus_data data; + int i; + if (length > 32) + length = 32; + for (i = 1; i <= length; i++) + data.block[i] = values[i-1]; + data.block[0] = length; + if (i2c_smbus_access(file,I2C_SMBUS_WRITE,command, + I2C_SMBUS_BLOCK_PROC_CALL,&data)) + return -1; + else { + for (i = 1; i <= data.block[0]; i++) + values[i-1] = data.block[i]; + return data.block[0]; + } +} + + +#endif /* LIB_I2CDEV_H */ diff --git a/src/osmo-bts-sysmo/misc/sob_bts_pa.c b/src/osmo-bts-sysmo/misc/sob_bts_pa.c new file mode 100644 index 00000000..24240884 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sob_bts_pa.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-dev.h" +#include "sx150x.h" + +#define SOB_BTS_NUM_PA 2 + +static int g_pa_gpio_offset; +static int g_i2c_fd; + +int sob_bts_pa_enable(int pa_num, int enable) +{ + int level; + + if (pa_num >= SOB_BTS_NUM_PA) + return -EINVAL; + + if (enable) + level = 0; + else + level = 1; + + return sx150x_gpio_set(g_i2c_fd, g_pa_gpio_offset + pa_num, level); +} + +int sob_bts_pa_init(int adapter_nr) +{ + char filename[PATH_MAX]; + int rc; + + snprintf(filename, sizeof(filename)-1, "/dev/i2c-%d", adapter_nr); + rc = open(filename, O_RDWR); + if (rc < 0) { + fprintf(stderr, "Error opening the device: %d\n", rc); + return rc; + } + + g_i2c_fd = rc; + + rc = ioctl(g_i2c_fd, I2C_SLAVE, SX150x_ADDR_ADDR0); + if (rc < 0) { + fprintf(stderr, "Error setting slave addr: %d\n", rc); + close(g_i2c_fd); + return rc; + } + + /* enable pull-up on GPIO7 */ + sx150x_gpio_pull_up_set(g_i2c_fd, 7, 1); + + if (sx150x_gpio_get(g_i2c_fd, 7) == 0) { + /* daughter board installed: PAs connected to IO2+3 */ + g_pa_gpio_offset = 2; + } else { + /* PAs directly connected to 0+1 */ + g_pa_gpio_offset = 0; + } + + /* set both as output */ + sx150x_gpio_direction_set(g_i2c_fd, g_pa_gpio_offset, SX150x_DIR_OUTPUT); + sx150x_gpio_direction_set(g_i2c_fd, g_pa_gpio_offset+1, SX150x_DIR_OUTPUT); + + /* disable them as default */ + sob_bts_pa_enable(0, 0); + sob_bts_pa_enable(1, 0); + + return 0; +} diff --git a/src/osmo-bts-sysmo/misc/sob_bts_pa.h b/src/osmo-bts-sysmo/misc/sob_bts_pa.h new file mode 100644 index 00000000..3f918dc8 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sob_bts_pa.h @@ -0,0 +1,4 @@ +#pragma once + +int sob_bts_pa_init(int adapter_nr); +int sob_bts_pa_enable(int pa_num, int enable); diff --git a/src/osmo-bts-sysmo/misc/sob_bts_pa_ctrl.c b/src/osmo-bts-sysmo/misc/sob_bts_pa_ctrl.c new file mode 100644 index 00000000..316ba264 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sob_bts_pa_ctrl.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +#include "sob_bts_pa.h" + +static void print_help(const char *cmdname) +{ + printf("%s <0-1> \n", cmdname); +} + +int main(int argc, char **argv) +{ + int rc; + int pa_nr, on; + + if (argc < 3) + goto err_param; + + pa_nr = atoi(argv[1]); + if (pa_nr < 0 || pa_nr > 1) + goto err_param; + + if (!strcmp(argv[2], "on")) + on = 1; + else if (!strcmp(argv[2], "off")) + on = 0; + else + goto err_param; + + rc = sob_bts_pa_init(1); + if (rc < 0) + exit(1); + + printf("%sabling SOB-BTS PA #%u\n", on? "en" : "dis", pa_nr); + rc = sob_bts_pa_enable(pa_nr, on); + if (rc < 0) { + fprintf(stderr, "Error during PA operation\n"); + exit(1); + } + + exit(0); + +err_param: + print_help(argv[0]); + exit(2); +} diff --git a/src/osmo-bts-sysmo/misc/sx150x.c b/src/osmo-bts-sysmo/misc/sx150x.c new file mode 100644 index 00000000..be26d28b --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sx150x.c @@ -0,0 +1,137 @@ +/* sx150x - minimal SX150x I2C GPIO expander driver + * (C) 2015 by sysmocom - s.f.m.c. GmbH, Author: Harald Welte + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* #include */ +#include "i2c-dev.h" + +#include "sx150x.h" + +enum sx150x_reg { + SX150x_REG_DATA = 0x00, + SX150x_REG_DIRECTION = 0x01, + SX150x_REG_PULL_UP = 0x02, + SX150x_REG_PULL_DOWN = 0x03, + /* resered */ + SX150x_REG_IRQ_MASK = 0x05, + SX150x_REG_SENSE_HIGH = 0x06, + SX150x_REG_SENSE_LOW = 0x07, + SX150x_REG_IRQ_SOURCE = 0x08, + SX150x_REG_EVENT_STATUS = 0x09, + /* what about 0x0a - 0x0f? */ + SX150x_REG_PLD_MODE = 0x10, + SX150x_REG_PLD_TABLE0 = 0x11, + SX150x_REG_PLD_TABLE1 = 0x12, + SX150x_REG_PLD_TABLE2 = 0x13, + SX150x_REG_PLD_TABLE3 = 0x13, + SX150x_REG_PLD_TABLE4 = 0x13, + SX150x_REG_ADVANCED = 0xAB, +}; + +int sx150x_gpio_direction_set(int fd, int gpio, enum sx150x_direction dir) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_DIRECTION); + if (rc < 0) + return rc; + + rc &= ~(1 << gpio); + rc |= (dir << gpio); + + return i2c_smbus_write_byte_data(fd, SX150x_REG_DIRECTION, rc); +} + +int sx150x_gpio_direction_get(int fd, int gpio) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_DIRECTION); + if (rc < 0) + return rc; + return (rc & (1 << gpio)); +} + +int sx150x_gpio_pull_up_set(int fd, int gpio, int on) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_PULL_UP); + if (rc < 0) + return rc; + + if (on) + rc |= (1 << gpio); + else + rc &= ~(1 << gpio); + + return i2c_smbus_write_byte_data(fd, SX150x_REG_PULL_UP, rc); +} + +int sx150x_gpio_pull_down_set(int fd, int gpio, int on) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_PULL_DOWN); + if (rc < 0) + return rc; + + if (on) + rc |= (1 << gpio); + else + rc &= ~(1 << gpio); + + return i2c_smbus_write_byte_data(fd, SX150x_REG_PULL_DOWN, rc); +} + +int sx150x_gpio_set(int fd, int gpio, int high) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_DATA); + if (rc < 0) + return rc; + + if (high) + rc |= (1 << gpio); + else + rc &= ~(1 << gpio); + + return i2c_smbus_write_byte_data(fd, SX150x_REG_DATA, rc); +} + +int sx150x_gpio_get(int fd, int gpio) +{ + int rc; + + rc = i2c_smbus_read_byte_data(fd, SX150x_REG_DATA); + if (rc < 0) + return rc; + return (rc & (1 << gpio)); +} diff --git a/src/osmo-bts-sysmo/misc/sx150x.h b/src/osmo-bts-sysmo/misc/sx150x.h new file mode 100644 index 00000000..a3f57774 --- /dev/null +++ b/src/osmo-bts-sysmo/misc/sx150x.h @@ -0,0 +1,19 @@ +#pragma once +#include + +#define SX150x_ADDR_ADDR0 0x20 +#define SX150x_ADDR_ADDR1 0x21 + +enum sx150x_direction { + SX150x_DIR_OUTPUT = 0, + SX150x_DIR_INPUT = 1 +}; + +int sx150x_gpio_pull_up_set(int fd, int gpio, int on); +int sx150x_gpio_pull_down_set(int fd, int gpio, int on); + +int sx150x_gpio_direction_set(int fd, int gpio, enum sx150x_direction dir); +int sx150x_gpio_direction_get(int fd, int gpio); + +int sx150x_gpio_set(int fd, int gpio, int high); +int sx150x_gpio_get(int fd, int gpio); -- cgit v1.2.3