s32k1xx:LPI2C Add DMA support
s32k3xx:LPI2C fix RESET so it compiles
This commit is contained in:
parent
34d2cde8a8
commit
da7fe760e8
@ -318,6 +318,7 @@ config ARCH_CHIP_S32K3XX
|
||||
select ARCH_HAVE_MPU
|
||||
select ARCH_HAVE_RAMFUNCS
|
||||
select ARM_HAVE_MPU_UNIFIED
|
||||
select ARCH_HAVE_I2CRESET
|
||||
---help---
|
||||
NPX S32K3XX architectures (ARM Cortex-M7).
|
||||
|
||||
|
@ -1210,6 +1210,58 @@ config S32K3XX_LPSPI5_PINCFG
|
||||
|
||||
endmenu # LPSPI Configuration
|
||||
|
||||
menu "LPI2C Configuration"
|
||||
depends on S32K3XX_LPI2C
|
||||
|
||||
config S32K3XX_LPI2C_DMA
|
||||
bool "I2C DMA Support"
|
||||
default n
|
||||
depends on S32K3XX_LPI2C && S32K3XX_EDMA && !I2C_POLLED
|
||||
---help---
|
||||
This option enables the DMA for I2C transfers.
|
||||
Note: The user can define CONFIG_I2C_DMAPRIO: a custom priority value
|
||||
for the I2C dma streams, else the default priority level is set to
|
||||
medium.
|
||||
|
||||
config S32K3XX_LPI2C_DMA_MAXMSG
|
||||
int "Maximum number messages that will be DMAed"
|
||||
default 8
|
||||
depends on S32K3XX_LPI2C_DMA
|
||||
---help---
|
||||
This option set the mumber of mesg that can be in a transfer.
|
||||
It is used to allocate space for the 16 bit LPI2C commands
|
||||
that will be DMA-ed to the LPI2C device.
|
||||
|
||||
config S32K3XX_LPI2C_DYNTIMEO
|
||||
bool "Use dynamic timeouts"
|
||||
default n
|
||||
depends on S32K3XX_LPI2C
|
||||
|
||||
config S32K3XX_LPI2C_DYNTIMEO_USECPERBYTE
|
||||
int "Timeout Microseconds per Byte"
|
||||
default 500
|
||||
depends on S32K3XX_LPI2C_DYNTIMEO
|
||||
|
||||
config S32K3XX_LPI2C_DYNTIMEO_STARTSTOP
|
||||
int "Timeout for Start/Stop (Milliseconds)"
|
||||
default 1000
|
||||
depends on S32K3XX_LPI2C_DYNTIMEO
|
||||
|
||||
config S32K3XX_LPI2C_TIMEOSEC
|
||||
int "Timeout seconds"
|
||||
default 0
|
||||
depends on S32K3XX_LPI2C
|
||||
|
||||
config S32K3XX_LPI2C_TIMEOMS
|
||||
int "Timeout Milliseconds"
|
||||
default 500
|
||||
depends on S32K3XX_LPI2C && !S32K3XX_LPI2C_DYNTIMEO
|
||||
|
||||
config S32K3XX_LPI2C_TIMEOTICKS
|
||||
int "Timeout for Done and Stop (ticks)"
|
||||
default 500
|
||||
depends on S32K3XX_LPI2C && !S32K3XX_LPI2C_DYNTIMEO
|
||||
|
||||
menu "LPI2C0 Configuration"
|
||||
depends on S32K3XX_LPI2C0
|
||||
|
||||
@ -1217,6 +1269,11 @@ config LPI2C0_BUSYIDLE
|
||||
int "Bus idle timeout period in clock cycles"
|
||||
default 0
|
||||
|
||||
config LPI2C0_DMA
|
||||
bool "Enable DMA for I2C0"
|
||||
default n
|
||||
depends on S32K3XX_LPI2C_DMA
|
||||
|
||||
config LPI2C0_FILTSCL
|
||||
int "I2C master digital glitch filters for SCL input in clock cycles"
|
||||
default 0
|
||||
@ -1234,6 +1291,11 @@ config LPI2C1_BUSYIDLE
|
||||
int "Bus idle timeout period in clock cycles"
|
||||
default 0
|
||||
|
||||
config LPI2C1_DMA
|
||||
bool "Enable DMA for I2C1"
|
||||
default n
|
||||
depends on S32K3XX_LPI2C_DMA
|
||||
|
||||
config LPI2C1_FILTSCL
|
||||
int "I2C master digital glitch filters for SCL input in clock cycles"
|
||||
default 0
|
||||
@ -1243,7 +1305,7 @@ config LPI2C1_FILTSDA
|
||||
default 0
|
||||
|
||||
endmenu # LPI2C1 Configuration
|
||||
|
||||
endmenu # LPI2C Configuration
|
||||
|
||||
menu "LPUART Configuration"
|
||||
depends on S32K3XX_LPUART
|
||||
|
@ -46,8 +46,9 @@
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
|
||||
#include "s32k3xx_edma.h"
|
||||
#include "s32k3xx_pin.h"
|
||||
#include "hardware/s32k3xx_dmamux.h"
|
||||
#include "hardware/s32k3xx_pinmux.h"
|
||||
#include "hardware/s32k3xx_lpi2c.h"
|
||||
#include "s32k3xx_lpi2c.h"
|
||||
@ -117,15 +118,11 @@
|
||||
#define LPI2C_MASTER 1
|
||||
#define LPI2C_SLAVE 2
|
||||
|
||||
#define MKI2C_OUTPUT(p) (((p) & GPIO_PADMUX_MASK) | \
|
||||
IOMUX_OPENDRAIN | IOMUX_DRIVE_33OHM | \
|
||||
IOMUX_SLEW_SLOW | (5 << GPIO_ALT_SHIFT) | \
|
||||
IOMUX_PULL_NONE | GPIO_OUTPUT_ONE)
|
||||
#define MKI2C_OUTPUT(p) (((p) & (_PIN_PORT_MASK | _PIN_MASK)) | \
|
||||
GPIO_OUTPUT | GPIO_OUTPUT_ONE)
|
||||
|
||||
#define MKI2C_INPUT(p) (((p) & GPIO_PADMUX_MASK) | \
|
||||
IOMUX_DRIVE_HIZ | IOMUX_SLEW_SLOW | \
|
||||
IOMUX_CMOS_INPUT | (5 << GPIO_ALT_SHIFT) | \
|
||||
IOMUX_PULL_NONE)
|
||||
#define MKI2C_INPUT(p) (((p) & (_PIN_PORT_MASK | _PIN_MASK)) | \
|
||||
GPIO_INPUT)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
@ -179,6 +176,10 @@ struct s32k3xx_lpi2c_config_s
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
uint32_t irq; /* Event IRQ */
|
||||
#endif
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
uint32_t dma_rxreqsrc; /* DMA mux rx source */
|
||||
uint32_t dma_txreqsrc; /* DMA mux tx source */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* I2C Device Private Data */
|
||||
@ -218,6 +219,11 @@ struct s32k3xx_lpi2c_priv_s
|
||||
struct s32k3xx_trace_s trace[CONFIG_I2C_NTRACE];
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
DMACH_HANDLE rxdma; /* rx DMA handle */
|
||||
DMACH_HANDLE txdma; /* tx DMA handle */
|
||||
uint16_t cmnds[CONFIG_S32K3XX_LPI2C_DMA_MAXMSG]; /* Commands */
|
||||
#endif
|
||||
uint32_t status; /* End of transfer SR2|SR1 status */
|
||||
};
|
||||
|
||||
@ -273,6 +279,13 @@ static int s32k3xx_lpi2c_transfer(struct i2c_master_s *dev,
|
||||
static int s32k3xx_lpi2c_reset(struct i2c_master_s *dev);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static void s32k3xx_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done,
|
||||
int result);
|
||||
static void s32k3xx_txdma_callback(DMACH_HANDLE handle, void *arg, bool done,
|
||||
int result);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@ -322,6 +335,10 @@ static const struct s32k3xx_lpi2c_config_s s32k3xx_lpi2c0_config =
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
.irq = S32K3XX_IRQ_LPI2C0,
|
||||
#endif
|
||||
#ifdef CONFIG_LPI2C0_DMA
|
||||
.dma_rxreqsrc = DMA_REQ_LPI2C0_RX,
|
||||
.dma_txreqsrc = DMA_REQ_LPI2C0_TX,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct s32k3xx_lpi2c_priv_s s32k3xx_lpi2c0_priv =
|
||||
@ -360,6 +377,10 @@ static const struct s32k3xx_lpi2c_config_s s32k3xx_lpi2c1_config =
|
||||
#ifndef CONFIG_I2C_POLLED
|
||||
.irq = S32K3XX_IRQ_LPI2C1,
|
||||
#endif
|
||||
#ifdef CONFIG_LPI2C1_DMA
|
||||
.dma_rxreqsrc = DMA_REQ_LPI2C1_RX,
|
||||
.dma_txreqsrc = DMA_REQ_LPI2C1_TX,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct s32k3xx_lpi2c_priv_s s32k3xx_lpi2c1_priv =
|
||||
@ -476,13 +497,17 @@ s32k3xx_lpi2c_sem_waitdone(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
if (priv->rxdma == NULL && priv->txdma == NULL)
|
||||
{
|
||||
#endif
|
||||
/* Enable Interrupts when master mode */
|
||||
|
||||
if (priv->config->mode == LPI2C_MASTER)
|
||||
{
|
||||
if ((priv->flags & I2C_M_READ) != 0)
|
||||
{
|
||||
regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | LPI2C_MIER_NDIE | \
|
||||
regval = LPI2C_MIER_TDIE | LPI2C_MIER_RDIE | LPI2C_MIER_NDIE |
|
||||
LPI2C_MIER_ALIE | LPI2C_MIER_SDIE;
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MIER_OFFSET, regval);
|
||||
}
|
||||
@ -505,7 +530,10 @@ s32k3xx_lpi2c_sem_waitdone(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
* are currently disabled but will be temporarily re-enabled below when
|
||||
* nxsem_tickwait_uninterruptible() sleeps.
|
||||
*/
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
}
|
||||
|
||||
#endif
|
||||
priv->intstate = INTSTATE_WAITING;
|
||||
do
|
||||
{
|
||||
@ -518,7 +546,6 @@ s32k3xx_lpi2c_sem_waitdone(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
ret = nxsem_tickwait_uninterruptible(&priv->sem_isr,
|
||||
CONFIG_S32K3XX_I2CTIMEOTICKS);
|
||||
#endif
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
/* Break out of the loop on irrecoverable errors. This would
|
||||
@ -610,6 +637,112 @@ s32k3xx_lpi2c_sem_waitdone(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_rxdma_callback
|
||||
*
|
||||
* Description:
|
||||
* This function performs the next I2C operation
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static void s32k3xx_rxdma_callback(DMACH_HANDLE handle, void *arg, bool done,
|
||||
int result)
|
||||
{
|
||||
struct s32k3xx_lpi2c_priv_s *priv = (struct s32k3xx_lpi2c_priv_s *)arg;
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MIER_OFFSET, 0,
|
||||
LPI2C_MIER_SDIE);
|
||||
|
||||
if (result != OK)
|
||||
{
|
||||
priv->status = s32k3xx_lpi2c_getstatus(priv);
|
||||
|
||||
if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0)
|
||||
{
|
||||
i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", priv->status);
|
||||
|
||||
s32k3xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
|
||||
|
||||
/* Clear the TX and RX FIFOs */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MCR_OFFSET, 0,
|
||||
LPI2C_MCR_RTF | LPI2C_MCR_RRF);
|
||||
|
||||
/* Clear the error */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MSR_OFFSET,
|
||||
(priv->status & (LPI2C_MSR_NDF |
|
||||
LPI2C_MSR_ALF |
|
||||
LPI2C_MSR_FEF |
|
||||
LPI2C_MSR_PLTF)));
|
||||
|
||||
if (priv->intstate == INTSTATE_WAITING)
|
||||
{
|
||||
/* inform the thread that transfer is complete
|
||||
* and wake it up
|
||||
*/
|
||||
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_txdma_callback
|
||||
*
|
||||
* Description:
|
||||
* This function performs the next I2C operation
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static void s32k3xx_txdma_callback(DMACH_HANDLE handle, void *arg, bool done,
|
||||
int result)
|
||||
{
|
||||
struct s32k3xx_lpi2c_priv_s *priv = (struct s32k3xx_lpi2c_priv_s *)arg;
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MIER_OFFSET, 0,
|
||||
LPI2C_MIER_SDIE);
|
||||
|
||||
if (result != OK)
|
||||
{
|
||||
priv->status = s32k3xx_lpi2c_getstatus(priv);
|
||||
|
||||
if ((priv->status & LPI2C_MSR_ERROR_MASK) != 0)
|
||||
{
|
||||
i2cerr("ERROR: MSR: status: 0x0%" PRIx32 "\n", priv->status);
|
||||
|
||||
s32k3xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
|
||||
|
||||
/* Clear the TX and RX FIFOs */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MCR_OFFSET, 0,
|
||||
LPI2C_MCR_RTF | LPI2C_MCR_RRF);
|
||||
|
||||
/* Clear the error */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MSR_OFFSET,
|
||||
(priv->status & (LPI2C_MSR_NDF |
|
||||
LPI2C_MSR_ALF |
|
||||
LPI2C_MSR_FEF |
|
||||
LPI2C_MSR_PLTF)));
|
||||
|
||||
if (priv->intstate == INTSTATE_WAITING)
|
||||
{
|
||||
/* inform the thread that transfer is complete
|
||||
* and wake it up
|
||||
*/
|
||||
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_trace*
|
||||
*
|
||||
@ -732,7 +865,7 @@ static void s32k3xx_lpi2c_tracedump(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
* Name: s32k3xx_lpi2c_pckfreq
|
||||
*
|
||||
* Description:
|
||||
* Get the peripheral clock frequency for the LPSPI peripheral
|
||||
* Get the peripheral clock frequency for the LPI2C peripheral
|
||||
*
|
||||
* Input Parameters:
|
||||
* base - The base address of the LPI2C peripheral registers
|
||||
@ -956,6 +1089,20 @@ static inline void s32k3xx_lpi2c_sendstop(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MTDR_OFFSET, LPI2C_MTDR_CMD_STOP);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_getenabledints
|
||||
*
|
||||
* Description:
|
||||
* Get 32-bit status
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t
|
||||
s32k3xx_lpi2c_getenabledints(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
{
|
||||
return s32k3xx_lpi2c_getreg(priv, S32K3XX_LPI2C_MIER_OFFSET);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_getstatus
|
||||
*
|
||||
@ -982,11 +1129,93 @@ static int s32k3xx_lpi2c_isr_process(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
{
|
||||
uint32_t status = s32k3xx_lpi2c_getstatus(priv);
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
uint32_t current_status = status;
|
||||
|
||||
/* Condition the status with only the enabled interrupts */
|
||||
|
||||
status &= s32k3xx_lpi2c_getenabledints(priv);
|
||||
|
||||
if (priv->rxdma != NULL || priv->txdma != NULL)
|
||||
{
|
||||
/* End of packet or Stop */
|
||||
|
||||
if ((status & (LPI2C_MSR_SDF | LPI2C_MSR_EPF)) != 0)
|
||||
{
|
||||
s32k3xx_lpi2c_traceevent(priv, I2CEVENT_STOP, 0);
|
||||
|
||||
/* Acknowledge End of packet or Stop */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MSR_OFFSET, status &
|
||||
(LPI2C_MSR_SDF |
|
||||
LPI2C_MSR_EPF));
|
||||
}
|
||||
|
||||
/* Is there an Error condition */
|
||||
|
||||
if (current_status & LPI2C_MSR_ERROR_MASK)
|
||||
{
|
||||
s32k3xx_lpi2c_traceevent(priv, I2CEVENT_ERROR, 0);
|
||||
|
||||
/* Shutdown DMA */
|
||||
|
||||
if (priv->rxdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->rxdma);
|
||||
}
|
||||
|
||||
if (priv->txdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->txdma);
|
||||
}
|
||||
|
||||
/* Clear the TX and RX FIFOs */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MCR_OFFSET, 0,
|
||||
LPI2C_MCR_RTF | LPI2C_MCR_RRF);
|
||||
|
||||
/* Clear the error */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MSR_OFFSET,
|
||||
(current_status & (LPI2C_MSR_NDF |
|
||||
LPI2C_MSR_ALF |
|
||||
LPI2C_MSR_FEF)));
|
||||
|
||||
/* Return the full error status */
|
||||
|
||||
status = current_status;
|
||||
}
|
||||
|
||||
/* Mark that this transaction stopped */
|
||||
|
||||
priv->msgv = NULL;
|
||||
priv->msgc = 0;
|
||||
priv->dcnt = -1;
|
||||
|
||||
if (priv->intstate == INTSTATE_WAITING)
|
||||
{
|
||||
/* Update Status once at the end */
|
||||
|
||||
priv->status = status;
|
||||
|
||||
/* inform the thread that transfer is complete
|
||||
* and wake it up
|
||||
*/
|
||||
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Check for new trace setup */
|
||||
|
||||
s32k3xx_lpi2c_tracenew(priv, status);
|
||||
|
||||
/* After an error we can get an SDF */
|
||||
/* After an error we can get a STOP Detect Flag */
|
||||
|
||||
if (priv->intstate == INTSTATE_DONE && (status & LPI2C_MSR_SDF) != 0)
|
||||
{
|
||||
@ -1059,9 +1288,9 @@ static int s32k3xx_lpi2c_isr_process(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
{
|
||||
if (priv->msgc > 0 && priv->msgv != NULL)
|
||||
{
|
||||
priv->ptr = priv->msgv->buffer;
|
||||
priv->dcnt = priv->msgv->length;
|
||||
priv->flags = priv->msgv->flags;
|
||||
priv->ptr = priv->msgv->buffer;
|
||||
priv->dcnt = priv->msgv->length;
|
||||
priv->flags = priv->msgv->flags;
|
||||
|
||||
if ((priv->msgv->flags & I2C_M_NOSTART) == 0)
|
||||
{
|
||||
@ -1125,8 +1354,8 @@ static int s32k3xx_lpi2c_isr_process(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
* and wake it up
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->sem_isr);
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
#else
|
||||
priv->status = status;
|
||||
@ -1178,8 +1407,8 @@ static int s32k3xx_lpi2c_isr_process(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
* and wake it up
|
||||
*/
|
||||
|
||||
nxsem_post(&priv->sem_isr);
|
||||
priv->intstate = INTSTATE_DONE;
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
#else
|
||||
priv->status = status;
|
||||
@ -1220,7 +1449,7 @@ static int s32k3xx_lpi2c_init(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
{
|
||||
/* Power-up and configure GPIOs .
|
||||
*
|
||||
* NOTE: Clocking to the LPSPI peripheral must be provided by
|
||||
* NOTE: Clocking to the LPI2C peripheral must be provided by
|
||||
* board-specific logic as part of the clock configuration logic.
|
||||
*/
|
||||
|
||||
@ -1252,7 +1481,7 @@ static int s32k3xx_lpi2c_init(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
/* Set tx and rx watermarks */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MFCR_OFFSET,
|
||||
LPI2C_MFCR_TXWATER(0) | LPI2C_MFCR_RXWATER(0));
|
||||
LPI2C_MFCR_TXWATER(0) | LPI2C_MFCR_RXWATER(0));
|
||||
|
||||
/* Force a frequency update */
|
||||
|
||||
@ -1262,14 +1491,14 @@ static int s32k3xx_lpi2c_init(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
/* Set scl, sda glitch filters and busy idle */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MCFGR2_OFFSET,
|
||||
LPI2C_MCFGR2_BUSIDLE(priv->config->busy_idle) |
|
||||
LPI2C_MCFGR2_FILTSCL_CYCLES(priv->config->filtscl) |
|
||||
LPI2C_MCFGR2_FILTSDA_CYCLES(priv->config->filtsda));
|
||||
LPI2C_MCFGR2_BUSIDLE(priv->config->busy_idle) |
|
||||
LPI2C_MCFGR2_FILTSCL_CYCLES(priv->config->filtscl) |
|
||||
LPI2C_MCFGR2_FILTSDA_CYCLES(priv->config->filtsda));
|
||||
|
||||
/* Set pin low cycles to 0 (disable) */
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MCFGR3_OFFSET,
|
||||
LPI2C_MCFGR3_PINLOW_CYCLES(0));
|
||||
LPI2C_MCFGR3_PINLOW_CYCLES(0));
|
||||
|
||||
/* Attach ISRs */
|
||||
|
||||
@ -1319,6 +1548,223 @@ static int s32k3xx_lpi2c_deinit(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
* Device Driver Operations
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_dma_command_configure
|
||||
*
|
||||
* Description:
|
||||
* Create a command TCD
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static int
|
||||
s32k3xx_lpi2c_dma_command_configure(struct s32k3xx_lpi2c_priv_s
|
||||
*priv, uint16_t *ccmd,
|
||||
uint32_t ncmd)
|
||||
{
|
||||
struct s32k3xx_edma_xfrconfig_s config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.saddr = (uint32_t) ccmd;
|
||||
config.daddr = priv->config->base + S32K3XX_LPI2C_MTDR_OFFSET;
|
||||
config.soff = sizeof(uint16_t);
|
||||
config.doff = 0;
|
||||
config.iter = 1;
|
||||
config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
|
||||
config.ssize = EDMA_16BIT;
|
||||
config.dsize = EDMA_16BIT;
|
||||
config.nbytes = sizeof(uint16_t) * ncmd;
|
||||
|
||||
up_clean_dcache((uintptr_t)config.saddr,
|
||||
(uintptr_t)config.saddr + config.nbytes);
|
||||
|
||||
return s32k3xx_dmach_xfrsetup(priv->txdma, &config);
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_dma_data_configure
|
||||
*
|
||||
* Description:
|
||||
* Create a data TCD
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static int s32k3xx_lpi2c_dma_data_configure(struct s32k3xx_lpi2c_priv_s
|
||||
*priv,
|
||||
struct i2c_msg_s *msg)
|
||||
{
|
||||
DMACH_HANDLE dma;
|
||||
struct s32k3xx_edma_xfrconfig_s config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
||||
config.iter = msg->length;
|
||||
config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
|
||||
config.ssize = EDMA_8BIT;
|
||||
config.dsize = EDMA_8BIT;
|
||||
config.nbytes = sizeof(msg->buffer[0]);
|
||||
|
||||
if (msg->flags & I2C_M_READ)
|
||||
{
|
||||
dma = priv->rxdma;
|
||||
config.saddr = priv->config->base + S32K3XX_LPI2C_MRDR_OFFSET;
|
||||
config.daddr = (uint32_t) msg->buffer;
|
||||
config.soff = 0;
|
||||
config.doff = sizeof(msg->buffer[0]);
|
||||
up_invalidate_dcache((uintptr_t)msg->buffer,
|
||||
(uintptr_t)msg->buffer + msg->length);
|
||||
}
|
||||
else
|
||||
{
|
||||
dma = priv->txdma;
|
||||
config.saddr = (uint32_t) msg->buffer;
|
||||
config.daddr = priv->config->base + S32K3XX_LPI2C_MTDR_OFFSET;
|
||||
config.soff = sizeof(msg->buffer[0]);
|
||||
config.doff = 0;
|
||||
up_clean_dcache((uintptr_t)msg->buffer,
|
||||
(uintptr_t)msg->buffer + msg->length);
|
||||
}
|
||||
|
||||
return s32k3xx_dmach_xfrsetup(dma, &config) ? 0 : msg->length;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_configure_dma_transfer
|
||||
*
|
||||
* Description:
|
||||
* DMA based I2C transfer function
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static int s32k3xx_lpi2c_form_command_list(struct s32k3xx_lpi2c_priv_s
|
||||
*priv, struct i2c_msg_s *msg,
|
||||
int ncmds)
|
||||
{
|
||||
ssize_t length = 0;
|
||||
|
||||
if (priv->flags & I2C_M_NOSTART)
|
||||
{
|
||||
if (priv->flags & I2C_M_READ)
|
||||
{
|
||||
/* No start read operation */
|
||||
|
||||
priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
|
||||
LPI2C_MTDR_DATA(msg->length - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A start based read or write operation */
|
||||
|
||||
/* Create bus address with R/W */
|
||||
|
||||
uint16_t badd = (priv->flags & I2C_M_READ) ? I2C_READADDR8(msg->addr) :
|
||||
I2C_WRITEADDR8(msg->addr);
|
||||
|
||||
priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_START | LPI2C_MTDR_DATA(badd);
|
||||
|
||||
if (badd & I2C_READBIT)
|
||||
{
|
||||
length = msg->length;
|
||||
while (length)
|
||||
{
|
||||
if (length > 256u)
|
||||
{
|
||||
priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
|
||||
LPI2C_MTDR_DATA(256u - 1);
|
||||
length -= 256u;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->cmnds[ncmds++] = LPI2C_MTDR_CMD_RXD |
|
||||
LPI2C_MTDR_DATA(length - 1);
|
||||
length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ncmds;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_dma_transfer
|
||||
*
|
||||
* Description:
|
||||
* DMA based I2C transfer function
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
static int s32k3xx_lpi2c_dma_transfer(struct s32k3xx_lpi2c_priv_s *priv)
|
||||
{
|
||||
int m;
|
||||
int ntotcmds = 0;
|
||||
int ncmds = 0;
|
||||
uint16_t *ccmnd = NULL;
|
||||
|
||||
/* Disable Interrupts */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MIER_OFFSET,
|
||||
LPI2C_MIER_RDIE | LPI2C_MIER_TDIE, 0);
|
||||
|
||||
/* Disable DMA */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MDER_OFFSET, LPI2C_MDER_TDDE |
|
||||
LPI2C_MDER_RDDE, 0);
|
||||
|
||||
/* Turn off auto_stop option */
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MCFGR1_OFFSET, 0,
|
||||
LPI2C_MCFGR1_IGNACK | LPI2C_MCFGR1_AUTOSTOP);
|
||||
|
||||
/* Form chains of tcd to process the messages */
|
||||
|
||||
for (m = 0; m < priv->msgc; m++)
|
||||
{
|
||||
ncmds = 0;
|
||||
priv->flags = priv->msgv[m].flags;
|
||||
|
||||
/* Form a command list */
|
||||
|
||||
ccmnd = &priv->cmnds[ntotcmds];
|
||||
|
||||
ncmds = s32k3xx_lpi2c_form_command_list(priv, &priv->msgv[m],
|
||||
ntotcmds);
|
||||
|
||||
/* Have commands for this message ? */
|
||||
|
||||
if (ncmds != 0)
|
||||
{
|
||||
/* Build up a TCD with the command from this message */
|
||||
|
||||
s32k3xx_lpi2c_dma_command_configure(priv, ccmnd, ncmds - ntotcmds);
|
||||
|
||||
ntotcmds += ncmds;
|
||||
|
||||
DEBUGASSERT(ntotcmds < CONFIG_S32K3XX_LPI2C_DMA_MAXMSG);
|
||||
|
||||
s32k3xx_lpi2c_dma_data_configure(priv, &priv->msgv[m]);
|
||||
}
|
||||
}
|
||||
|
||||
s32k3xx_lpi2c_putreg(priv, S32K3XX_LPI2C_MIER_OFFSET,
|
||||
LPI2C_MIER_NDIE | LPI2C_MIER_ALIE |
|
||||
LPI2C_MIER_PLTIE | LPI2C_MIER_FEIE);
|
||||
|
||||
s32k3xx_dmach_start(priv->rxdma, s32k3xx_rxdma_callback, (void *)priv);
|
||||
s32k3xx_dmach_start(priv->txdma, s32k3xx_txdma_callback, (void *)priv);
|
||||
|
||||
s32k3xx_lpi2c_modifyreg(priv, S32K3XX_LPI2C_MDER_OFFSET, 0,
|
||||
LPI2C_MDER_TDDE | LPI2C_MDER_RDDE);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k3xx_lpi2c_transfer
|
||||
*
|
||||
@ -1376,8 +1822,27 @@ static int s32k3xx_lpi2c_transfer(struct i2c_master_s *dev,
|
||||
* the BUSY flag.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
if (priv->rxdma || priv->txdma)
|
||||
{
|
||||
s32k3xx_lpi2c_dma_transfer(priv);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s32k3xx_lpi2c_sem_waitdone(priv) < 0)
|
||||
{
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
if (priv->rxdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->rxdma);
|
||||
}
|
||||
|
||||
if (priv->txdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->txdma);
|
||||
}
|
||||
|
||||
#endif
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
i2cerr("ERROR: Timed out: MCR: status: 0x%" PRIx32 "\n", priv->status);
|
||||
@ -1486,12 +1951,12 @@ static int s32k3xx_lpi2c_reset(struct i2c_master_s *dev)
|
||||
|
||||
/* Let SDA go high */
|
||||
|
||||
s32k3xx_gpio_write(sda_gpio, 1);
|
||||
s32k3xx_gpiowrite(sda_gpio, 1);
|
||||
|
||||
/* Clock the bus until any slaves currently driving it let it go. */
|
||||
|
||||
clock_count = 0;
|
||||
while (!s32k3xx_gpio_read(sda_gpio))
|
||||
while (!s32k3xx_gpioread(sda_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
@ -1506,7 +1971,7 @@ static int s32k3xx_lpi2c_reset(struct i2c_master_s *dev)
|
||||
*/
|
||||
|
||||
stretch_count = 0;
|
||||
while (!s32k3xx_gpio_read(scl_gpio))
|
||||
while (!s32k3xx_gpioread(scl_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
@ -1520,12 +1985,12 @@ static int s32k3xx_lpi2c_reset(struct i2c_master_s *dev)
|
||||
|
||||
/* Drive SCL low */
|
||||
|
||||
s32k3xx_gpio_write(scl_gpio, 0);
|
||||
s32k3xx_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
|
||||
/* Drive SCL high again */
|
||||
|
||||
s32k3xx_gpio_write(scl_gpio, 1);
|
||||
s32k3xx_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
}
|
||||
|
||||
@ -1533,13 +1998,13 @@ static int s32k3xx_lpi2c_reset(struct i2c_master_s *dev)
|
||||
* state machines.
|
||||
*/
|
||||
|
||||
s32k3xx_gpio_write(sda_gpio, 0);
|
||||
s32k3xx_gpiowrite(sda_gpio, 0);
|
||||
up_udelay(10);
|
||||
s32k3xx_gpio_write(scl_gpio, 0);
|
||||
s32k3xx_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
s32k3xx_gpio_write(scl_gpio, 1);
|
||||
s32k3xx_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
s32k3xx_gpio_write(sda_gpio, 1);
|
||||
s32k3xx_gpiowrite(sda_gpio, 1);
|
||||
up_udelay(10);
|
||||
|
||||
/* Revert the GPIO configuration. */
|
||||
@ -1612,6 +2077,22 @@ struct i2c_master_s *s32k3xx_i2cbus_initialize(int port)
|
||||
if (priv->refs++ == 0)
|
||||
{
|
||||
s32k3xx_lpi2c_init(priv);
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
if (priv->config->dma_txreqsrc != 0)
|
||||
{
|
||||
priv->txdma = s32k3xx_dmach_alloc(priv->config->dma_txreqsrc |
|
||||
DMAMUX_CHCFG_ENBL, 0);
|
||||
DEBUGASSERT(priv->txdma != NULL);
|
||||
}
|
||||
|
||||
if (priv->config->dma_rxreqsrc != 0)
|
||||
{
|
||||
priv->rxdma = s32k3xx_dmach_alloc(priv->config->dma_rxreqsrc |
|
||||
DMAMUX_CHCFG_ENBL, 0);
|
||||
DEBUGASSERT(priv->rxdma != NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
@ -1648,6 +2129,22 @@ int s32k3xx_i2cbus_uninitialize(struct i2c_master_s *dev)
|
||||
|
||||
/* Disable power and other HW resource (GPIO's) */
|
||||
|
||||
#ifdef CONFIG_S32K3XX_LPI2C_DMA
|
||||
if (priv->rxdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->rxdma);
|
||||
s32k3xx_dmach_free(priv->rxdma);
|
||||
priv->rxdma = NULL;
|
||||
}
|
||||
|
||||
if (priv->txdma != NULL)
|
||||
{
|
||||
s32k3xx_dmach_stop(priv->txdma);
|
||||
s32k3xx_dmach_free(priv->txdma);
|
||||
priv->txdma = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
s32k3xx_lpi2c_deinit(priv);
|
||||
nxmutex_unlock(&priv->lock);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user