icjx: add support for multiple pin read/write

This commit implements functions icjx_multireadpin and icjx_multiwritepin.
These functions can be used for multiple pin access (read/write) if
CONFIG_IOEXPANDER_MULTIPIN is selected. This access is generally
faster than one by one pin and may simplify user application.

Changes to general functions icjx_read and icjx_write were also required
to provide support for multiple data send/receive.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2024-03-19 14:22:52 +01:00 committed by Xiang Xiao
parent e622e95d5b
commit 7c7e163e23

View File

@ -45,7 +45,8 @@
#define ICJX_NOP 0x00 #define ICJX_NOP 0x00
#define ICJX_RNW 0x01 #define ICJX_RNW 0x01
#define ICJX_NOB 0x0f #define ICJX_NOB1 0x0f
#define ICJX_NOB2 0x1e
#define ICJX_CONTROL 0x59 #define ICJX_CONTROL 0x59
/**************************************************************************** /****************************************************************************
@ -77,9 +78,9 @@ static void icjx_deselect(FAR struct spi_dev_s *spi,
/* Read/Write helpers */ /* Read/Write helpers */
static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg, static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg,
uint8_t *data); uint16_t *data, int nob);
static int icjx_write(FAR struct icjx_dev_s *priv, uint8_t reg, static int icjx_write(FAR struct icjx_dev_s *priv, uint8_t reg,
uint8_t data); uint16_t data, int nob);
/* I/O Expander Methods */ /* I/O Expander Methods */
@ -93,8 +94,8 @@ static int icjx_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin,
FAR bool *value); FAR bool *value);
#ifdef CONFIG_IOEXPANDER_MULTIPIN #ifdef CONFIG_IOEXPANDER_MULTIPIN
static int icjx_multiwritepin(FAR struct ioexpander_dev_s *dev, static int icjx_multiwritepin(FAR struct ioexpander_dev_s *dev,
FAR const uint8_t *pins, FAR bool *values, FAR const uint8_t *pins,
int count); FAR const bool *values, int count);
static int icjx_multireadpin(FAR struct ioexpander_dev_s *dev, static int icjx_multireadpin(FAR struct ioexpander_dev_s *dev,
FAR const uint8_t *pins, FAR bool *values, FAR const uint8_t *pins, FAR bool *values,
int count); int count);
@ -207,16 +208,17 @@ static void icjx_deselect(FAR struct spi_dev_s *spi,
* *
****************************************************************************/ ****************************************************************************/
static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg, uint8_t *data) static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg,
uint16_t *data, int nob)
{ {
uint8_t startaddr; uint8_t startaddr;
uint8_t tx_buffer[5]; uint8_t tx_buffer[6];
uint8_t rx_buffer[5]; uint8_t rx_buffer[6];
startaddr = (priv->config->addr << 6) | (reg << 1) | ICJX_RNW; startaddr = (priv->config->addr << 6) | (reg << 1) | ICJX_RNW;
tx_buffer[0] = startaddr; tx_buffer[0] = startaddr;
tx_buffer[1] = ICJX_NOP; tx_buffer[1] = ICJX_NOP;
tx_buffer[2] = ICJX_NOB; tx_buffer[2] = nob;
icjx_select(priv->spi, priv->config, 8); icjx_select(priv->spi, priv->config, 8);
SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, 3); SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, 3);
@ -224,8 +226,21 @@ static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg, uint8_t *data)
*data = rx_buffer[2]; *data = rx_buffer[2];
if (priv->config->verification) if (priv->config->verification)
{
if (nob == ICJX_NOB2)
{ {
tx_buffer[0] = rx_buffer[2]; tx_buffer[0] = rx_buffer[2];
SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, 1);
*data |= rx_buffer[0] << 8;
tx_buffer[0] = rx_buffer[0];
startaddr = (priv->config->addr << 6) |
((reg + 1) << 1) | ICJX_RNW;
}
else
{
tx_buffer[0] = rx_buffer[2];
}
tx_buffer[1] = ICJX_CONTROL; tx_buffer[1] = ICJX_CONTROL;
SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, 2); SPI_EXCHANGE(priv->spi, tx_buffer, rx_buffer, 2);
} }
@ -268,24 +283,34 @@ static int icjx_read(FAR struct icjx_dev_s *priv, uint8_t reg, uint8_t *data)
* *
****************************************************************************/ ****************************************************************************/
static int icjx_write(FAR struct icjx_dev_s *priv, uint8_t reg, uint8_t data) static int icjx_write(FAR struct icjx_dev_s *priv, uint8_t reg,
uint16_t data, int nob)
{ {
uint8_t startaddr; uint8_t startaddr;
uint8_t bytes_to_exchange; uint8_t bytes_to_exchange;
uint8_t tx_buffer[5]; uint8_t tx_buffer[6];
uint8_t rx_buffer[5]; uint8_t rx_buffer[6];
int ver_idx;
int data_len;
bytes_to_exchange = 3; data_len = 1;
ver_idx = 2;
bytes_to_exchange = 0;
startaddr = (priv->config->addr << 6) | (reg << 1); startaddr = (priv->config->addr << 6) | (reg << 1);
tx_buffer[0] = startaddr; tx_buffer[bytes_to_exchange++] = startaddr;
tx_buffer[1] = ICJX_NOB; tx_buffer[bytes_to_exchange++] = nob;
tx_buffer[2] = data; tx_buffer[bytes_to_exchange++] = data & 0xff;
if (nob == ICJX_NOB2)
{
data_len = 2;
tx_buffer[bytes_to_exchange++] = (data >> 8) & 0xff;
}
if (priv->config->verification) if (priv->config->verification)
{ {
tx_buffer[3] = startaddr; tx_buffer[bytes_to_exchange++] = (priv->config->addr << 6) |
tx_buffer[4] = ICJX_CONTROL; ((reg + (data_len - 1)) << 1);
bytes_to_exchange = 5; tx_buffer[bytes_to_exchange++] = ICJX_CONTROL;
} }
icjx_select(priv->spi, priv->config, 8); icjx_select(priv->spi, priv->config, 8);
@ -294,23 +319,26 @@ static int icjx_write(FAR struct icjx_dev_s *priv, uint8_t reg, uint8_t data)
if (priv->config->verification) if (priv->config->verification)
{ {
if (rx_buffer[2] != ICJX_NOB) if (rx_buffer[ver_idx++] != nob)
{ {
gpioerr("ERROR: Start address verification error for register" gpioerr("ERROR: Start address verification error for register"
"0x%x!\n", reg); "0x%x!\n", reg);
return -EIO; return -EIO;
} }
if (rx_buffer[3] != data) for (int i = 0; i < data_len; i++)
{
if (rx_buffer[ver_idx++] != ((data >> (i * 8)) & 0xff))
{ {
gpioerr("ERROR: Data verification error for register 0x%x!\n", gpioerr("ERROR: Data verification error for register 0x%x!\n",
reg); reg);
return -EIO; return -EIO;
} }
}
if (rx_buffer[4] != ICJX_CONTROL) if (rx_buffer[ver_idx++] != ICJX_CONTROL)
{ {
gpioerr("ERROR: Data verification error for register 0x%x!\n", gpioerr("ERROR: Control verification error for register 0x%x!\n",
reg); reg);
return -EIO; return -EIO;
} }
@ -341,7 +369,7 @@ static int icjx_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
{ {
FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev; FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev;
uint8_t outpins; uint8_t outpins;
uint8_t out_set; uint16_t out_set;
uint8_t regaddr; uint8_t regaddr;
int ret; int ret;
@ -379,7 +407,7 @@ static int icjx_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
outpins = (priv->outpins >> 8) & 0xff; outpins = (priv->outpins >> 8) & 0xff;
} }
ret = icjx_read(priv, regaddr, &out_set); ret = icjx_read(priv, regaddr, &out_set, ICJX_NOB1);
if (ret < 0) if (ret < 0)
{ {
nxmutex_unlock(&priv->lock); nxmutex_unlock(&priv->lock);
@ -406,7 +434,7 @@ static int icjx_direction(FAR struct ioexpander_dev_s *dev, uint8_t pin,
out_set &= ~ICJX_CTRL_WORD_2_NIOH; out_set &= ~ICJX_CTRL_WORD_2_NIOH;
} }
ret = icjx_write(priv, regaddr, out_set); ret = icjx_write(priv, regaddr, out_set, ICJX_NOB1);
nxmutex_unlock(&priv->lock); nxmutex_unlock(&priv->lock);
return ret; return ret;
@ -517,7 +545,7 @@ static int icjx_writepin(FAR struct ioexpander_dev_s *dev, uint8_t pin,
outstate = (priv->outstate >> 8) & 0xff; outstate = (priv->outstate >> 8) & 0xff;
} }
ret = icjx_write(priv, regaddr, outstate); ret = icjx_write(priv, regaddr, outstate, ICJX_NOB1);
nxmutex_unlock(&priv->lock); nxmutex_unlock(&priv->lock);
return ret; return ret;
@ -547,7 +575,7 @@ static int icjx_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin,
{ {
FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev; FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev;
uint8_t regaddr; uint8_t regaddr;
uint8_t data; uint16_t data;
int ret; int ret;
if (pin > 16) if (pin > 16)
@ -578,7 +606,7 @@ static int icjx_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin,
regaddr = pin < 8 ? ICJX_INPUT_A : ICJX_INPUT_B; regaddr = pin < 8 ? ICJX_INPUT_A : ICJX_INPUT_B;
ret = icjx_read(priv, regaddr, &data); ret = icjx_read(priv, regaddr, &data, ICJX_NOB1);
nxmutex_unlock(&priv->lock); nxmutex_unlock(&priv->lock);
if (ret != OK) if (ret != OK)
{ {
@ -610,12 +638,58 @@ static int icjx_readpin(FAR struct ioexpander_dev_s *dev, uint8_t pin,
#ifdef CONFIG_IOEXPANDER_MULTIPIN #ifdef CONFIG_IOEXPANDER_MULTIPIN
static int icjx_multiwritepin(FAR struct ioexpander_dev_s *dev, static int icjx_multiwritepin(FAR struct ioexpander_dev_s *dev,
FAR const uint8_t *pins, FAR const uint8_t *pins,
FAR bool *values, int count) FAR const bool *values, int count)
{ {
gpiowarn("WARNING: iC-JX does not have implemented support for" FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev;
"multiple pin write operation!\n"); int ret;
int pin;
int value;
return -ENOTSUP; if (count >= 16)
{
return -ENXIO;
}
DEBUGASSERT(priv != NULL && priv->config != NULL);
/* Get exclusive access to the I/O Expander */
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
return ret;
}
for (int i = 0; i < count; i++)
{
pin = pins[i];
value = values[i];
gpioinfo("Expander id=%02x, pin=%u\n", priv->config->id, pin);
if ((priv->outpins & (1 << pin)) == 0)
{
gpioerr("ERROR: pin%u is an input\n", pin);
nxmutex_unlock(&priv->lock);
return -EINVAL;
}
/* Set/clear a bit in outstate. */
if (value)
{
priv->outstate |= (1 << pin);
}
else
{
priv->outstate &= ~(1 << pin);
}
}
ret = icjx_write(priv, ICJX_OUTPUT_A, priv->outstate, ICJX_NOB2);
nxmutex_unlock(&priv->lock);
return ret;
} }
/**************************************************************************** /****************************************************************************
@ -640,10 +714,51 @@ static int icjx_multireadpin(FAR struct ioexpander_dev_s *dev,
FAR const uint8_t *pins, FAR bool *values, FAR const uint8_t *pins, FAR bool *values,
int count) int count)
{ {
gpiowarn("WARNING: iC-JX does not have implemented support for" FAR struct icjx_dev_s *priv = (FAR struct icjx_dev_s *)dev;
"multiple pin read operation!\n"); uint16_t data;
int pin;
int ret;
return -ENOTSUP; if (count > 16)
{
return -ENXIO;
}
DEBUGASSERT(priv != NULL && priv->config != NULL && values != NULL);
/* Get exclusive access to the I/O Expander */
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
return ret;
}
for (int i = 0; i < count; i++)
{
pin = pins[i];
gpioinfo("Expander id=%02x, pin=%u\n", priv->config->id, pin);
if ((priv->outpins & (1 << pin)) != 0)
{
values[i] = (priv->outstate & (1 << pin)) != 0;
}
}
ret = icjx_read(priv, ICJX_INPUT_A, &data, ICJX_NOB2);
nxmutex_unlock(&priv->lock);
if (ret != OK)
{
return ret;
}
for (int i = 0; i < count; i++)
{
values[i] = (data >> (pins[i] & 0xf)) & 1;
}
return OK;
} }
#endif /* CONFIG_IOEXPANDER_MULTIPIN */ #endif /* CONFIG_IOEXPANDER_MULTIPIN */
@ -706,14 +821,14 @@ FAR struct ioexpander_dev_s *icjx_initialize(FAR struct spi_dev_s *spi,
regval = (config->current_src << 4) | config->current_src; regval = (config->current_src << 4) | config->current_src;
ret = icjx_write(priv, ICJX_CTRL_WORD_2_A, regval); ret = icjx_write(priv, ICJX_CTRL_WORD_2_A, regval, ICJX_NOB1);
if (ret < 0) if (ret < 0)
{ {
gpioerr("ERROR: Could write to ICJX_CTRL_WORD_2_A: %d!\n", ret); gpioerr("ERROR: Could write to ICJX_CTRL_WORD_2_A: %d!\n", ret);
goto err; goto err;
} }
ret = icjx_write(priv, ICJX_CTRL_WORD_2_B, regval); ret = icjx_write(priv, ICJX_CTRL_WORD_2_B, regval, ICJX_NOB1);
if (ret < 0) if (ret < 0)
{ {
gpioerr("ERROR: Could write to ICJX_CTRL_WORD_2_B: %d!\n", ret); gpioerr("ERROR: Could write to ICJX_CTRL_WORD_2_B: %d!\n", ret);
@ -723,14 +838,14 @@ FAR struct ioexpander_dev_s *icjx_initialize(FAR struct spi_dev_s *spi,
/* Bypass filters as those are not yet supported. */ /* Bypass filters as those are not yet supported. */
regval = ICJX_CTRL_WORD_1_BYP0 | ICJX_CTRL_WORD_1_BYP1; regval = ICJX_CTRL_WORD_1_BYP0 | ICJX_CTRL_WORD_1_BYP1;
ret = icjx_write(priv, ICJX_CTRL_WORD_1_A, regval); ret = icjx_write(priv, ICJX_CTRL_WORD_1_A, regval, ICJX_NOB1);
if (ret < 0) if (ret < 0)
{ {
gpioerr("ERROR: Could write to ICJX_CTRL_WORD_1_A: %d!\n", ret); gpioerr("ERROR: Could write to ICJX_CTRL_WORD_1_A: %d!\n", ret);
goto err; goto err;
} }
ret = icjx_write(priv, ICJX_CTRL_WORD_1_B, regval); ret = icjx_write(priv, ICJX_CTRL_WORD_1_B, regval, ICJX_NOB1);
if (ret < 0) if (ret < 0)
{ {
gpioerr("ERROR: Could write to ICJX_CTRL_WORD_1_B: %d!\n", ret); gpioerr("ERROR: Could write to ICJX_CTRL_WORD_1_B: %d!\n", ret);