Add i2c support for the i.MX8MP

Enable INA219 on the Verdin board
This commit is contained in:
Philippe Leduc 2023-08-28 18:22:54 +02:00 committed by Alan Carvalho de Assis
parent 779741d1d9
commit 98e998b934
12 changed files with 1383 additions and 2 deletions

View File

@ -604,6 +604,7 @@ config ARCH_CHIP_MX8MP
select ARCH_HAVE_MPU
select ARCH_HAVE_FETCHADD
select ARCH_HAVE_RAMFUNCS
select ARCH_HAVE_I2CRESET
select ARM_HAVE_MPU_UNIFIED
select ARMV7M_HAVE_ICACHE
select ARMV7M_HAVE_DCACHE

View File

@ -31,6 +31,59 @@ config MX8MP_UART4
select UART4_SERIALDRIVER
select ARCH_HAVE_SERIAL_TERMIOS
#####################################################################
# I2C Configuration (Master)
#####################################################################
config MX8MP_I2C
bool "I2C Master"
select I2C
---help---
Build in support for I2C master mode.
if MX8MP_I2C
config MX8MP_I2C1
bool "I2C1"
default n
select I2C
config MX8MP_I2C2
bool "I2C2"
default n
select I2C
config MX8MP_I2C3
bool "I2C3"
default n
select I2C
config MX8MP_I2C4
bool "I2C4"
default n
select I2C
config MX8MP_I2C5
bool "I2C5"
default n
select I2C
config MX8MP_I2C6
bool "I2C6"
default n
select I2C
config MX8MP_I2C_DRIVER
bool "I2C character driver"
default n
select I2C_DRIVER
---help---
Build in support for a character driver at /dev/i2c[N] that may be
used to perform I2C bus transfers from applications. The intent of
this driver is to support I2C testing. It is not suitable for use
in any real driver application.
endif # MX8MP_I2C
endmenu
# These "hidden" settings determine whether a peripheral option is available

View File

@ -35,3 +35,7 @@ endif
ifneq ($(CONFIG_SCHED_TICKLESS),y)
CHIP_CSRCS += mx8mp_timerisr.c
endif
ifeq ($(CONFIG_I2C),y)
CHIP_CSRCS += mx8mp_i2c.c
endif

View File

@ -0,0 +1,67 @@
/****************************************************************************
* arch/arm/src/mx8mp/hardware/mx8mp_i2c.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_I2C_H
#define __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_I2C_H
/****************************************************************************
* Included Files
****************************************************************************/
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* I2C Register Offsets *****************************************************/
#define IADR_OFFSET 0x0000
#define IFDR_OFFSET 0x0004
#define I2CR_OFFSET 0x0008
#define I2SR_OFFSET 0x000c
#define I2DR_OFFSET 0x0010
/* I2C Register Bit Definitions *********************************************/
#define IADR_SHIFT 1
#define IADR_MASK (0x7f << IADR_SHIFT)
#define IFDR_SHIFT 0
#define IFDR_MASK (0x3f << IFDR_SHIFT)
#define I2CR_IEN (1 << 7) /* enable */
#define I2CR_IIEN (1 << 6) /* interrupt enable */
#define I2CR_MSTA (1 << 5) /* master/start */
#define I2CR_MTX (1 << 4) /* transmit */
#define I2CR_TXAK (1 << 3) /* ACK/NACK on reception */
#define I2CR_RSTA (1 << 2) /* repeated start */
#define I2SR_ICF (1 << 7) /* transfer in progress */
#define I2SR_IAAS (1 << 6) /* addressed as a slave */
#define I2SR_IBB (1 << 5) /* is busy */
#define I2SR_IAL (1 << 4) /* arbitration lost */
#define I2SR_SRW (1 << 2) /* slave read/write (if in slave mode) */
#define I2SR_IIF (1 << 1) /* interrupt is pending */
#define I2SR_RXAK (1 << 0) /* no ack detected */
/****************************************************************************
* Inline Functions
****************************************************************************/
#endif /* __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_I2C_H */

View File

@ -0,0 +1,819 @@
/****************************************************************************
* arch/arm/src/mx8mp/mx8mp_i2c.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/signal.h>
#include "mx8mp_i2c.h"
#include "mx8mp_ccm.h"
#include "hardware/mx8mp_memorymap.h"
#include <debug.h>
#include "arm_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define I2C_STALL_TIMEOUT MSEC2TICK(10) /* 10 ms */
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
struct mx8mp_i2c_s;
static bool is_busy(struct mx8mp_i2c_s *priv);
static void mx8mp_i2c_enable(struct mx8mp_i2c_s *priv);
static void mx8mp_i2c_disable(struct mx8mp_i2c_s *priv);
static int mx8mp_i2c_interrupt(int irq, void *context, void *arg);
static void mx8mp_i2c_reset_bus(struct mx8mp_i2c_s *dev);
/* I2C lower half driver methods */
static int mx8mp_i2c_transfer(struct i2c_master_s *dev,
struct i2c_msg_s *msgs, int count);
static int mx8mp_i2c_reset(struct i2c_master_s *dev);
/****************************************************************************
* Private Types
****************************************************************************/
/* I2C Device Private Data */
struct mx8mp_i2c_s
{
/* Generic I2C device */
struct i2c_master_s dev;
/* Port configuration */
uint32_t base; /* I2C base address */
int clock; /* Peripheral clock as described in hardware/mx8mp_ccm.h */
uint16_t irq; /* IRQ number */
uint32_t frequency; /* Current I2C frequency */
int refs; /* Reference count */
mutex_t lock; /* Only one thread can access at a time */
sem_t wait; /* IRQ wait sync */
};
/* I2C lower half driver operations */
static const struct i2c_ops_s mx8mp_i2c_ops =
{
.transfer = mx8mp_i2c_transfer
#ifdef CONFIG_I2C_RESET
, .reset = mx8mp_i2c_reset
#endif
};
/* I2C device structures */
#ifdef CONFIG_MX8MP_I2C1
static struct mx8mp_i2c_s g_i2c1_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C1,
.clock = I2C1_CLK_ROOT,
.irq = MX8MP_IRQ_I2C1,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
#ifdef CONFIG_MX8MP_I2C2
static struct mx8mp_i2c_s g_i2c2_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C2,
.clock = I2C2_CLK_ROOT,
.irq = MX8MP_IRQ_I2C2,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
#ifdef CONFIG_MX8MP_I2C3
static struct mx8mp_i2c_s g_i2c3_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C3,
.clock = I2C3_CLK_ROOT,
.irq = MX8MP_IRQ_I2C3,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
#ifdef CONFIG_MX8MP_I2C4
static struct mx8mp_i2c_s g_i2c4_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C4,
.clock = I2C4_CLK_ROOT,
.irq = MX8MP_IRQ_I2C4,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
#ifdef CONFIG_MX8MP_I2C5
static struct mx8mp_i2c_s g_i2c5_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C5,
.clock = I2C5_CLK_ROOT,
.irq = MX8MP_IRQ_I2C5,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
#ifdef CONFIG_MX8MP_I2C6
static struct mx8mp_i2c_s g_i2c6_dev =
{
.dev.ops = &mx8mp_i2c_ops,
.base = MX8M_I2C6,
.clock = I2C6_CLK_ROOT,
.irq = MX8MP_IRQ_I2C6,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.wait = SEM_INITIALIZER(0),
};
#endif
/****************************************************************************
* Private Data
****************************************************************************/
static const uint16_t DIVIDERS_MAP[] =
{
30, 32, 36, 42, 48, 52, 60, 72,
80, 88, 104, 128, 144, 160, 192, 240,
288, 320, 384, 480, 576, 640, 768, 960,
1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840,
22, 24, 26, 28, 32, 36, 40, 44,
48, 56, 64, 72, 80, 96, 112, 128,
160, 192, 224, 256, 320, 384, 448, 512,
640, 768, 896, 1024, 1280, 1536, 1792, 2048
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: mx8mp_i2c_init
*
* Description:
* Setup the I2C hardware, ready for operation with defaults
*
****************************************************************************/
static int mx8mp_i2c_init(struct mx8mp_i2c_s *priv)
{
/* enable peripheral */
mx8mp_i2c_enable(priv);
/* Attach Interrupt Handler */
irq_attach(priv->irq, mx8mp_i2c_interrupt, priv);
/* Enable Interrupt Handler */
up_enable_irq(priv->irq);
/* Force a frequency update */
priv->frequency = 0;
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_deinit
*
* Description:
* Shutdown the I2C hardware
*
****************************************************************************/
static int mx8mp_i2c_deinit(struct mx8mp_i2c_s *priv)
{
/* Disable and detach interrupts */
up_disable_irq(priv->irq);
irq_detach(priv->irq);
/* Disable peripheral */
mx8mp_i2c_disable(priv);
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_enable
*
* Description:
* Enable the I2C peripheral
*
****************************************************************************/
static void mx8mp_i2c_enable(struct mx8mp_i2c_s *priv)
{
/* Set slave address here to support it (IFDR) */
putreg16(0, priv->base + I2SR_OFFSET);
modreg16(I2CR_IEN, I2CR_IEN, priv->base + I2CR_OFFSET);
modreg16(I2CR_IIEN, I2CR_IIEN, priv->base + I2CR_OFFSET);
}
/****************************************************************************
* Name: mx8mp_i2c_disable
*
* Description:
* Disable the I2C peripheral
*
****************************************************************************/
static void mx8mp_i2c_disable(struct mx8mp_i2c_s *priv)
{
putreg16(0, priv->base + I2CR_OFFSET);
}
/****************************************************************************
* Name: is_busy
*
* Description:
* Check if the bus is busy (true) or not (false)
*
****************************************************************************/
static bool is_busy(struct mx8mp_i2c_s *priv)
{
return (getreg16(priv->base + I2SR_OFFSET) & I2SR_IBB);
}
/****************************************************************************
* Name: mx8mp_i2c_wait
*
* Description:
* Wait for the IRQ to be triggered.
*
****************************************************************************/
static inline int mx8mp_i2c_wait_irq(struct mx8mp_i2c_s *priv, int usec)
{
return nxsem_tickwait(&priv->wait, USEC2TICK(usec));
}
/****************************************************************************
* Name: mx8mp_i2c_send_start
*
* Description:
* Emit start bit on the bus
*
****************************************************************************/
static int mx8mp_i2c_send_start(struct mx8mp_i2c_s *priv)
{
if (is_busy(priv))
{
return -EBUSY;
}
modreg16(I2CR_MSTA | I2CR_MTX | I2CR_TXAK,
I2CR_MSTA | I2CR_MTX | I2CR_TXAK,
priv->base + I2CR_OFFSET);
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_send_repeat_start
*
* Description:
* Emit repeat start bit on the bus
*
****************************************************************************/
static int mx8mp_i2c_send_repeat_start(struct mx8mp_i2c_s *priv)
{
if (is_busy(priv) && !(getreg16(priv->base + I2SR_OFFSET) & I2CR_MSTA))
{
return -EBUSY;
}
modreg16(I2CR_RSTA, I2CR_RSTA, priv->base + I2CR_OFFSET);
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_send_stop
*
* Description:
* Emit stop bit on the bus
*
****************************************************************************/
static void mx8mp_i2c_send_stop(struct mx8mp_i2c_s *priv)
{
modreg16(0, I2CR_MSTA | I2CR_MTX | I2CR_TXAK, priv->base + I2CR_OFFSET);
}
/****************************************************************************
* Name: mx8mp_i2c_write_byte
*
* Description:
* Write a byte on the bus, checking for arbitration lost and RX ACK.
*
****************************************************************************/
static int mx8mp_i2c_write_byte(struct mx8mp_i2c_s *priv, uint8_t byte)
{
int ret;
uint16_t status;
modreg16(0, I2SR_IIF, priv->base + I2SR_OFFSET);
putreg16(byte, priv->base + I2DR_OFFSET);
ret = mx8mp_i2c_wait_irq(priv, 500);
if (ret < 0)
{
return ret;
}
status = getreg16(priv->base + I2SR_OFFSET);
if (status & I2SR_IAL)
{
/* Arbitration lost */
modreg16(0, I2SR_IAL, priv->base + I2SR_OFFSET);
return -EACCES;
}
if (status & I2SR_RXAK)
{
return -EIO;
}
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_write_bytes
*
* Description:
* Write multiple byte on the bus, handling the STOP logic.
*
****************************************************************************/
static int mx8mp_i2c_write_bytes(struct mx8mp_i2c_s *priv,
const uint8_t *data,
uint32_t size,
bool is_last)
{
uint32_t i;
int ret;
for (i = 0; i < size; ++i)
{
ret = mx8mp_i2c_write_byte(priv, data[i]);
if (ret < 0)
{
return ret;
}
}
if (is_last)
{
mx8mp_i2c_send_stop(priv);
}
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_read_bytes
*
* Description:
* Read multiple bytes on the bus, handling the NACK and STOP logic.
*
****************************************************************************/
int mx8mp_i2c_read_bytes(struct mx8mp_i2c_s *priv,
uint8_t *data,
uint32_t size,
bool is_last)
{
int ret;
uint8_t temp;
uint32_t i;
temp = getreg16(priv->base + I2CR_OFFSET);
temp &= ~(I2CR_MTX | I2CR_TXAK);
if (size == 1)
{
/* NACK on read if one byte */
temp |= I2CR_TXAK;
}
putreg16(temp, priv->base + I2CR_OFFSET);
/* dummy read to start reading */
modreg16(0, I2SR_IIF, priv->base + I2SR_OFFSET);
data[0] = getreg16(priv->base + I2DR_OFFSET);
for (i = 0; i < size; ++i)
{
ret = mx8mp_i2c_wait_irq(priv, 500);
if (ret < 0)
{
return ret;
}
if ((i == (size - 1)) && is_last)
{
mx8mp_i2c_send_stop(priv);
}
else if (i == (size - 2))
{
/* No ACK on last byte */
modreg16(0, I2CR_TXAK, priv->base + I2CR_OFFSET);
}
modreg16(0, I2SR_IIF, priv->base + I2SR_OFFSET);
data[i] = getreg16(priv->base + I2DR_OFFSET);
}
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_set_frequency
*
* Description:
* Set the I2C peripheral clock frequency. Note: the real frequency may be
* lower than the targeted one (but never greater).
*
****************************************************************************/
static void mx8mp_i2c_set_frequency(struct mx8mp_i2c_s *priv,
uint32_t frequency)
{
uint8_t i;
uint8_t divider;
uint32_t old_frequency;
uint32_t clock;
i2cinfo("frequency=%lu\n", frequency);
clock = mx8mp_ccm_get_clock(priv->clock);
DEBUGASSERT(clock > frequency);
if (frequency == priv->frequency)
{
return;
}
divider = 0;
old_frequency = 0;
for (i = 0; i < 0x40; ++i)
{
uint32_t current_frequency = clock / DIVIDERS_MAP[i];
if ((current_frequency <= frequency) &&
(current_frequency > old_frequency))
{
divider = i;
old_frequency = current_frequency;
}
}
putreg16(divider, priv->base + IFDR_OFFSET);
priv->frequency = frequency;
i2cinfo(" real frequency=%lu (%lu / %d)\n",
old_frequency, clock, DIVIDERS_MAP[divider]);
}
/****************************************************************************
* Name: mx8mp_i2c_reset_bus
*
* Description:
* Reset the bus if this one is stall (stuck I2C device(s))
*
****************************************************************************/
static void mx8mp_i2c_reset_bus(struct mx8mp_i2c_s *priv)
{
mx8mp_i2c_disable(priv);
nxsig_usleep(50);
mx8mp_i2c_enable(priv);
nxsig_usleep(50);
}
/****************************************************************************
* Name: mx8mp_i2c_interrupt
*
* Description:
* The I2C common interrupt handler
*
****************************************************************************/
static int mx8mp_i2c_interrupt(int irq, void *context, void *arg)
{
struct mx8mp_i2c_s *priv = (struct mx8mp_i2c_s *)arg;
modreg16(0, I2SR_IIF, priv->base + I2SR_OFFSET);
nxsem_post(&priv->wait);
return 0;
}
/****************************************************************************
* Name: mx8mp_i2c_transfer
*
* Description:
* Perform a sequence of I2C transfers
*
****************************************************************************/
static int mx8mp_i2c_transfer(struct i2c_master_s *dev,
struct i2c_msg_s *msgs, int count)
{
struct mx8mp_i2c_s *priv = (struct mx8mp_i2c_s *)dev;
struct i2c_msg_s *msg;
clock_t deadline;
bool last;
int ret;
int i;
i2cinfo("msgs=%p count=%d\n", msgs, count);
DEBUGASSERT(dev != NULL && msgs != NULL && (unsigned)count <= UINT16_MAX);
/* Get exclusive access to the I2C bus */
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
return ret;
}
/* Configure the I2C frequency. REVISIT: Note that the frequency is set
* only on the first message. This could be extended to support
* different transfer frequencies for each message segment.
*/
mx8mp_i2c_set_frequency(priv, msgs->frequency);
/* Process every message */
if ((I2C_M_NOSTART & msgs->flags) == 0)
{
ret = mx8mp_i2c_send_start(priv);
if (ret < 0)
{
goto error;
}
}
for (i = 0; i < count; ++i)
{
msg = msgs + i;
last = (i == (count - 1));
if ((I2C_M_NOSTART & msg->flags) == 0)
{
if (I2C_M_READ & msg->flags)
{
ret = mx8mp_i2c_write_byte(priv, I2C_READADDR8(msg->addr));
}
else
{
ret = mx8mp_i2c_write_byte(priv, I2C_WRITEADDR8(msg->addr));
}
}
if (ret == 0)
{
if (I2C_M_READ & msg->flags)
{
ret = mx8mp_i2c_read_bytes(priv,
msg->buffer, msg->length, last);
}
else
{
ret = mx8mp_i2c_write_bytes(priv,
msg->buffer, msg->length, last);
}
}
if (ret == -EACCES)
{
/* arbitration lost */
goto error;
}
else if (ret < 0)
{
mx8mp_i2c_send_stop(priv);
goto error;
}
if (!last && ((I2C_M_NOSTART & msg->flags) == 0))
{
ret = mx8mp_i2c_send_repeat_start(priv);
if (ret < 0)
{
goto error;
}
}
}
error:
/* Ensure that the bus is free before leaving */
deadline = clock_systime_ticks() + I2C_STALL_TIMEOUT;
while (is_busy(priv))
{
if (clock_systime_ticks() > deadline)
{
i2cwarn("Bus is stall: try to reset it\n");
mx8mp_i2c_reset_bus(priv);
break;
}
nxsig_usleep(10);
}
/* Release access to I2C bus */
nxmutex_unlock(&priv->lock);
return ret;
}
static int mx8mp_i2c_reset(struct i2c_master_s *dev)
{
struct mx8mp_i2c_s *priv = (struct mx8mp_i2c_s *)dev;
int ret;
/* Our caller must own a ref */
DEBUGASSERT(priv->refs > 0);
/* Lock out other clients */
ret = nxmutex_lock(&priv->lock);
if (ret < 0)
{
return ret;
}
mx8mp_i2c_reset_bus(priv);
/* Release the port for re-use by other clients */
nxmutex_unlock(&priv->lock);
return 0;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mx8mp_i2cbus_initialize
*
* Description:
* Initialise an I2C device
*
****************************************************************************/
struct i2c_master_s *mx8mp_i2cbus_initialize(int port)
{
struct mx8mp_i2c_s *priv;
i2cinfo("port=%d\n", port);
switch (port)
{
#ifdef CONFIG_MX8MP_I2C1
case 1:
priv = &g_i2c1_dev;
break;
#endif
#ifdef CONFIG_MX8MP_I2C2
case 2:
priv = &g_i2c2_dev;
break;
#endif
#ifdef CONFIG_MX8MP_I2C3
case 3:
priv = &g_i2c3_dev;
break;
#endif
#ifdef CONFIG_MX8MP_I2C4
case 4:
priv = &g_i2c4_dev;
break;
#endif
#ifdef CONFIG_MX8MP_I2C5
case 5:
priv = &g_i2c5_dev;
break;
#endif
#ifdef CONFIG_MX8MP_I2C6
case 6:
priv = &g_i2c6_dev;
break;
#endif
default:
i2cerr("ERROR: Unsupported I2C port %d\n", port);
return NULL;
}
nxmutex_lock(&priv->lock);
if (priv->refs++ == 0)
{
mx8mp_i2c_init(priv);
}
nxmutex_unlock(&priv->lock);
return &priv->dev;
}
/****************************************************************************
* Name: mx8mp_i2cbus_uninitialize
*
* Description:
* Uninitialise an I2C device
*
****************************************************************************/
int mx8mp_i2cbus_uninitialize(struct i2c_master_s *dev)
{
struct mx8mp_i2c_s *priv = (struct mx8mp_i2c_s *)dev;
DEBUGASSERT(priv != NULL);
/* Decrement reference count and check for underflow */
if (priv->refs == 0)
{
return -1;
}
nxmutex_lock(&priv->lock);
if (--priv->refs)
{
nxmutex_unlock(&priv->lock);
return 0;
}
/* Disable power and other HW resource (GPIO's) */
mx8mp_i2c_deinit(priv);
nxmutex_unlock(&priv->lock);
return 0;
}

View File

@ -0,0 +1,72 @@
/****************************************************************************
* arch/arm/src/mx8mp/mx8mp_i2c.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM_SRC_MX8MP_MX8MP_I2C_H
#define __ARCH_ARM_SRC_MX8MP_MX8MP_I2C_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/i2c/i2c_master.h>
#include "hardware/mx8mp_i2c.h"
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: mx8mp_i2cbus_initialize
*
* Description:
* Initialize the selected I2C port. And return a unique instance of struct
* struct i2c_master_s. This function may be called to obtain multiple
* instances of the interface, each of which may be set up with a
* different frequency and slave address.
*
* Input Parameters:
* Port number (for hardware that has multiple I2C interfaces)
*
* Returned Value:
* Valid I2C device structure reference on success; a NULL on failure
*
****************************************************************************/
struct i2c_master_s *mx8mp_i2cbus_initialize(int port);
/****************************************************************************
* Name: mx8mp_i2cbus_uninitialize
*
* Description:
* De-initialize the selected I2C port, and power down the device.
*
* Input Parameters:
* Device structure as returned by the lpc43_i2cbus_initialize()
*
* Returned Value:
* OK on success, ERROR when internal reference count mismatch or dev
* points to invalid hardware device.
*
****************************************************************************/
int mx8mp_i2cbus_uninitialize(struct i2c_master_s *dev);
#endif /* __ARCH_ARM_SRC_MX8MP_MX8MP_I2C_H */

View File

@ -23,7 +23,16 @@ include $(TOPDIR)/Make.defs
CSRCS = mx8mp_boot.c mx8mp_bringup.c
ifeq ($(CONFIG_BOARDCTL),y)
CSRCS += mx8mp_appinit.c
CSRCS += mx8mp_appinit.c
endif
ifeq ($(CONFIG_SENSORS_INA219),y)
CSRCS += mx8mp_ina219.c
endif
ifeq ($(CONFIG_MX8MP_I2C_DRIVER),y)
CSRCS += mx8mp_i2cdev.c
endif
include $(TOPDIR)/boards/Board.mk

View File

@ -28,10 +28,16 @@
#include <errno.h>
#include <sys/types.h>
#include "verdin-mx8mp.h"
#ifdef CONFIG_USERLED
# include <nuttx/leds/userled.h>
#endif
#ifdef CONFIG_SENSORS_INA219
# include "mx8mp_ina219.h"
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
@ -58,5 +64,35 @@ int mx8mp_bringup(void)
}
#endif
#ifdef CONFIG_FS_PROCFS
/* Mount the procfs file system */
ret = nx_mount(NULL, "/proc", "procfs", 0, NULL);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed to mount procfs at /proc: %d\n", ret);
}
#endif
#ifdef CONFIG_MX8MP_I2C_DRIVER
/* Initialize I2C buses */
ret = mx8mp_i2cdev_initialize();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: mx8mp_i2cdev_initialize() failed: %d\n", ret);
}
#endif
#ifdef CONFIG_SENSORS_INA219
/* Configure and initialize the INA219 sensor in I2C4 */
ret = board_ina219_initialize(4);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: mx8mp_ina219_initialize() failed: %d\n", ret);
}
#endif
return ret;
}

View File

@ -0,0 +1,147 @@
/****************************************************************************
* boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_i2cdev.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <debug.h>
#include <nuttx/i2c/i2c_master.h>
#include "arm_internal.h"
#include "chip.h"
#include "mx8mp_i2c.h"
#include <arch/board/board.h>
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: board_i2cdev_initialize
*
* Description:
* Initialize and register i2c driver for the specified i2c port
*
****************************************************************************/
int board_i2cdev_initialize(int port)
{
int ret;
struct i2c_master_s *i2c;
i2cinfo("Initializing /dev/i2c%d..\n", port);
/* Initialize i2c device */
i2c = mx8mp_i2cbus_initialize(port);
if (!i2c)
{
i2cerr("ERROR: Failed to initialize i2c%d.\n", port);
return -ENODEV;
}
ret = i2c_register(i2c, port);
if (ret < 0)
{
i2cerr("ERROR: Failed to register i2c%d: %d\n", port, ret);
}
return ret;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: mx8mp_i2cdev_initialize
*
* Description:
* Called to configure all i2c drivers
*
****************************************************************************/
int mx8mp_i2cdev_initialize(void)
{
int ret = 0;
#ifdef CONFIG_MX8MP_I2C1
ret = board_i2cdev_initialize(1);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C1.\n");
return ret;
}
#endif
#ifdef CONFIG_MX8MP_I2C2
ret = board_i2cdev_initialize(2);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C2.\n");
return ret;
}
#endif
#ifdef CONFIG_MX8MP_I2C3
ret = board_i2cdev_initialize(3);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C3.\n");
return ret;
}
#endif
#ifdef CONFIG_MX8MP_I2C4
ret = board_i2cdev_initialize(4);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C4.\n");
return ret;
}
#endif
#ifdef CONFIG_MX8MP_I2C5
ret = board_i2cdev_initialize(5);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C5.\n");
return ret;
}
#endif
#ifdef CONFIG_MX8MP_I2C6
ret = board_i2cdev_initialize(6);
if (ret < 0)
{
syslog(LOG_ERR, "Failed to initialize I2C6.\n");
return ret;
}
#endif
return ret;
}

View File

@ -0,0 +1,85 @@
/****************************************************************************
* boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_ina219.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <syslog.h>
#include <debug.h>
#include <stdio.h>
#include <nuttx/spi/spi.h>
#include <nuttx/sensors/ina219.h>
#include "mx8mp_i2c.h"
#include "mx8mp_ina219.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: board_ina219_initialize
*
* Description:
* Initialize and register the INA219 voltage/current sensor.
*
* Input parameters:
* devno - The device number, used to build the device path as /dev/inaN
* busno - The I2C bus number
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int board_ina219_initialize(int busno)
{
struct i2c_master_s *i2c;
int ret;
sninfo("Initializing INA219!\n");
/* Initialize I2C */
i2c = mx8mp_i2cbus_initialize(busno);
if (!i2c)
{
return -ENODEV;
}
/* Then register the sensor */
ret = ina219_register("/dev/ina219", i2c, 0x40, 10000, 0x00);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Error registering INA219\n");
}
return ret;
}

View File

@ -0,0 +1,78 @@
/****************************************************************************
* boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_ina219.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __BOARDS_ARM_MX8MP_MX8MP_VERDIN_INCLUDE_BOARD_H
#define __BOARDS_ARM_MX8MP_MX8MP_VERDIN_INCLUDE_BOARD_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Inline Functions
****************************************************************************/
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: board_ina219_initialize
*
* Description:
* Initialize and register the INA219 voltage/current sensor.
*
* Input parameters:
* busno - The I2C bus number
*
* Returned Value:
* Zero (OK) on success; a negated errno value on failure.
*
****************************************************************************/
int board_ina219_initialize(int busno);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __BOARDS_ARM_MX8MP_MX8MP_VERDIN_INCLUDE_BOARD_H */

View File

@ -46,7 +46,7 @@
****************************************************************************/
/****************************************************************************
* Name: xmc4_bringup
* Name: mx8mp_bringup
*
* Description:
* Bring up board features
@ -55,5 +55,15 @@
int mx8mp_bringup(void);
/****************************************************************************
* Name: mx8mp_i2cdev_initialize
*
* Description:
* Called to configure all i2c
*
****************************************************************************/
int mx8mp_i2cdev_initialize(void);
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_MX8MP_MX8MP_VERDIN_SRC_VERDIN_MX8MP_H */