s32k1xx: FlexIO I2C master driver
This commit is contained in:
parent
ef271b8fe2
commit
622b6d234a
@ -227,6 +227,10 @@ config S32K1XX_FLEXCAN2
|
||||
default n
|
||||
depends on S32K1XX_HAVE_FLEXCAN2
|
||||
|
||||
config S32K1XX_FLEXIO_I2C
|
||||
bool "FlexIO I2C (emulated I2C)"
|
||||
default n
|
||||
|
||||
config S32K1XX_FTM0
|
||||
bool "FTM0"
|
||||
default n
|
||||
|
@ -54,6 +54,10 @@ CHIP_CSRCS += s32k1xx_lpi2c.c
|
||||
CHIP_CSRCS += s32k1xx_lpi2c_slave.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_S32K1XX_FLEXIO_I2C),y)
|
||||
CHIP_CSRCS += s32k1xx_flexio_i2c.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_S32K1XX_LPSPI),y)
|
||||
CHIP_CSRCS += s32k1xx_lpspi.c
|
||||
endif
|
||||
|
757
arch/arm/src/s32k1xx/s32k1xx_flexio_i2c.c
Normal file
757
arch/arm/src/s32k1xx/s32k1xx_flexio_i2c.c
Normal file
@ -0,0 +1,757 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/s32k1xx/s32k1xx_flexio_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/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
#include <arch/irq.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "s32k1xx_edma.h"
|
||||
#include "s32k1xx_pin.h"
|
||||
#include "hardware/s32k1xx_dmamux.h"
|
||||
#include "hardware/s32k1xx_pinmux.h"
|
||||
#include "s32k1xx_flexio_i2c.h"
|
||||
#include "s32k1xx_periphclocks.h"
|
||||
#include "s32k1xx_pin.h"
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
/* At least one I2C peripheral must be enabled */
|
||||
#define CONFIG_S32K1XX_FLEXIO_I2C
|
||||
#ifdef CONFIG_S32K1XX_FLEXIO_I2C
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define I2C_MAX_FREQUENCY 400000
|
||||
#define FLEXIO_TX_IRQ (1 << priv->config->tx_inst)
|
||||
#define FLEXIO_RX_IRQ (1 << priv->config->rx_inst)
|
||||
#define FLEXIO_ADDR_READ(addr) ((addr << 1 ) | 1)
|
||||
#define FLEXIO_ADDR_WRITE(addr) (addr << 1)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
enum s32k1xx_intstate_e
|
||||
{
|
||||
INTSTATE_IDLE = 0, /* No I2C activity */
|
||||
INTSTATE_RECV_DATA,
|
||||
INTSTATE_WRITE_DATA,
|
||||
};
|
||||
|
||||
struct s32k1xx_flexio_i2c_config_s
|
||||
{
|
||||
int tx_inst;
|
||||
int rx_inst;
|
||||
int timer;
|
||||
int two_word_timer;
|
||||
uint32_t flexio_sda_pin;
|
||||
uint32_t flexio_scl_pin;
|
||||
uint32_t sda_pin;
|
||||
uint32_t scl_pin;
|
||||
};
|
||||
|
||||
struct s32k1xx_flexio_i2cdev_s
|
||||
{
|
||||
struct i2c_master_s dev; /* Generic I2C device */
|
||||
unsigned int base; /* Base address of registers */
|
||||
uint16_t irqid; /* IRQ for this device */
|
||||
int8_t port; /* Port number */
|
||||
uint32_t base_freq; /* branch frequency */
|
||||
|
||||
mutex_t lock; /* Only one thread can access at a time */
|
||||
sem_t wait; /* Place to wait for transfer completion */
|
||||
uint32_t frequency; /* Current I2C frequency */
|
||||
int32_t tx_count;
|
||||
int32_t reg_buff_offset;
|
||||
int32_t reg_buff_mod;
|
||||
uint32_t tx_done;
|
||||
|
||||
struct i2c_msg_s *msgs;
|
||||
int total_bytes;
|
||||
|
||||
/* Port configuration */
|
||||
|
||||
const struct s32k1xx_flexio_i2c_config_s *config;
|
||||
|
||||
enum s32k1xx_intstate_e state;
|
||||
|
||||
int error; /* Error status of each transfers */
|
||||
int refs; /* Reference count */
|
||||
};
|
||||
|
||||
static const struct s32k1xx_flexio_i2c_config_s s32k1xx_flexio_i2c0_config =
|
||||
{
|
||||
.tx_inst = 0,
|
||||
.rx_inst = 1,
|
||||
.timer = 1,
|
||||
.two_word_timer = 0,
|
||||
.flexio_sda_pin = FLEXIO_I2C0_SDA,
|
||||
.flexio_scl_pin = FLEXIO_I2C0_SCL,
|
||||
.sda_pin = PIN_FLEXIO_I2C0_SCL,
|
||||
.scl_pin = PIN_FLEXIO_I2C0_SDA,
|
||||
};
|
||||
|
||||
static struct s32k1xx_flexio_i2cdev_s g_i2c0dev =
|
||||
{
|
||||
.port = 0,
|
||||
.base = S32K1XX_FLEXIO_BASE,
|
||||
.irqid = S32K1XX_IRQ_FLEXIO,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.wait = SEM_INITIALIZER(0),
|
||||
.refs = 0,
|
||||
.config = &s32k1xx_flexio_i2c0_config,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void s32k1xx_flexio_i2c_init(struct s32k1xx_flexio_i2cdev_s *priv);
|
||||
static int s32k1xx_flexio_i2c_interrupt(int irq, void *context, void *arg);
|
||||
static void s32k1xx_flexio_i2c_set_freq_and_size(
|
||||
struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t frequency, uint8_t num_bytes);
|
||||
static int s32k1xx_flexio_i2c_transfer(struct i2c_master_s *dev,
|
||||
struct i2c_msg_s *msgs, int count);
|
||||
|
||||
static inline uint32_t flexio_getreg32(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t offset)
|
||||
{
|
||||
return getreg32(priv->base + offset);
|
||||
}
|
||||
|
||||
static inline void flexio_putreg32(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t val, uint32_t offset)
|
||||
{
|
||||
putreg32(val, priv->base + offset);
|
||||
}
|
||||
|
||||
static inline void flexio_modifyreg32(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
unsigned int offset,
|
||||
uint32_t clearbits,
|
||||
uint32_t setbits)
|
||||
{
|
||||
modifyreg32(priv->base + offset, clearbits, setbits);
|
||||
}
|
||||
|
||||
static inline void
|
||||
enable_shifter_status_interrupts(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t mask)
|
||||
{
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_SHIFTSIEN_OFFSET, 0, mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
disable_shifter_status_interrupts(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t mask)
|
||||
{
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_SHIFTSIEN_OFFSET, mask, 0);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
get_shifter_status_flags(struct s32k1xx_flexio_i2cdev_s *priv)
|
||||
{
|
||||
return flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTSTAT_OFFSET);
|
||||
}
|
||||
|
||||
static inline void
|
||||
clear_shifter_status_flags(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t mask)
|
||||
{
|
||||
flexio_putreg32(priv, mask, S32K1XX_FLEXIO_SHIFTSTAT_OFFSET);
|
||||
}
|
||||
|
||||
static inline void
|
||||
enable_timer_status_interrupts(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t mask)
|
||||
{
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_TIMIEN_OFFSET, 0, mask);
|
||||
}
|
||||
|
||||
static inline void
|
||||
disable_timer_status_interrupts(struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t mask)
|
||||
{
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_TIMIEN_OFFSET, mask, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
s32k1xx_flexio_i2c_set_nack(struct s32k1xx_flexio_i2cdev_s *priv)
|
||||
{
|
||||
flexio_putreg32(priv, FLEXIO_SHIFTCFG_INSRC_PIN |
|
||||
FLEXIO_SHIFTCFG_SSTOP_ONE |
|
||||
FLEXIO_SHIFTCFG_SSTART_ZERO,
|
||||
S32K1XX_FLEXIO_SHIFTCFG0_OFFSET + priv->config->tx_inst * 0x4);
|
||||
}
|
||||
|
||||
static inline void
|
||||
s32k1xx_flexio_i2c_set_ack(struct s32k1xx_flexio_i2cdev_s *priv)
|
||||
{
|
||||
flexio_putreg32(priv, FLEXIO_SHIFTCFG_INSRC_PIN |
|
||||
FLEXIO_SHIFTCFG_SSTOP_ZERO |
|
||||
FLEXIO_SHIFTCFG_SSTART_ZERO,
|
||||
S32K1XX_FLEXIO_SHIFTCFG0_OFFSET + priv->config->tx_inst * 0x4);
|
||||
}
|
||||
|
||||
static inline void
|
||||
s32k1xx_flexio_i2c_clear_errors(struct s32k1xx_flexio_i2cdev_s *priv)
|
||||
{
|
||||
flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTBUFBIS0_OFFSET +
|
||||
priv->config->rx_inst * 0x4);
|
||||
flexio_putreg32(priv, FLEXIO_TX_IRQ | FLEXIO_RX_IRQ,
|
||||
S32K1XX_FLEXIO_SHIFTERR_OFFSET);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* I2C device operations
|
||||
****************************************************************************/
|
||||
|
||||
struct i2c_ops_s s32k1xx_flexio_i2c_ops =
|
||||
{
|
||||
.transfer = s32k1xx_flexio_i2c_transfer,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_flexio_i2c_set_freq_and_size
|
||||
*
|
||||
* Description:
|
||||
* Set the frequency for the next transfer
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void s32k1xx_flexio_i2c_set_freq_and_size(
|
||||
struct s32k1xx_flexio_i2cdev_s *priv,
|
||||
uint32_t frequency, uint8_t num_bytes)
|
||||
{
|
||||
int divider = ((priv->base_freq / frequency) / 2) - 1;
|
||||
|
||||
if (divider > 0xff)
|
||||
{
|
||||
divider = 0xff;
|
||||
}
|
||||
|
||||
flexio_putreg32(priv, divider |
|
||||
((((num_bytes + 1) * 9 + 1) * 2 - 1) << 8),
|
||||
S32K1XX_FLEXIO_TIMCMP0_OFFSET +
|
||||
priv->config->two_word_timer * 0x4);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_flexio_i2c_interrupt
|
||||
*
|
||||
* Description:
|
||||
* The I2C Interrupt Handler
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int s32k1xx_flexio_i2c_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct s32k1xx_flexio_i2cdev_s *priv =
|
||||
(struct s32k1xx_flexio_i2cdev_s *)arg;
|
||||
struct i2c_msg_s *msg = priv->msgs;
|
||||
|
||||
if ((priv->state == INTSTATE_IDLE))
|
||||
{
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_RX_IRQ);
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ);
|
||||
}
|
||||
else if ((priv->state == INTSTATE_RECV_DATA))
|
||||
{
|
||||
if (!priv->tx_done && get_shifter_status_flags(priv) & FLEXIO_TX_IRQ)
|
||||
{
|
||||
if (priv->tx_count == msg->length)
|
||||
{
|
||||
/* Send NACK and Stop bit */
|
||||
|
||||
s32k1xx_flexio_i2c_set_nack(priv);
|
||||
flexio_putreg32(priv, 0x00,
|
||||
S32K1XX_FLEXIO_SHIFTBUFBBS0_OFFSET +
|
||||
priv->config->tx_inst * 0x4);
|
||||
priv->tx_count++;
|
||||
}
|
||||
else if (priv->tx_count < msg->length)
|
||||
{
|
||||
flexio_putreg32(priv, 0xff,
|
||||
S32K1XX_FLEXIO_SHIFTBUFBBS0_OFFSET +
|
||||
priv->config->tx_inst * 0x4);
|
||||
priv->tx_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->tx_done = 1;
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_shifter_status_flags(priv) & FLEXIO_RX_IRQ)
|
||||
{
|
||||
if (priv->reg_buff_offset < 0)
|
||||
{
|
||||
flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTBUFBIS0_OFFSET +
|
||||
priv->config->rx_inst * 0x4);
|
||||
|
||||
/* If RX shifter reports an error then stop bit (ACK)
|
||||
* doesn't go low, thus we get a NACK
|
||||
*/
|
||||
|
||||
if (flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTERR_OFFSET) &
|
||||
FLEXIO_RX_IRQ)
|
||||
{
|
||||
priv->error = 1;
|
||||
flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTBUFBIS0_OFFSET +
|
||||
priv->config->rx_inst * 0x4);
|
||||
flexio_putreg32(priv, FLEXIO_RX_IRQ,
|
||||
S32K1XX_FLEXIO_SHIFTERR_OFFSET);
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_RX_IRQ);
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ);
|
||||
priv->state = INTSTATE_IDLE;
|
||||
nxsem_post(&priv->wait);
|
||||
}
|
||||
else if (msg->length > 1)
|
||||
{
|
||||
s32k1xx_flexio_i2c_set_ack(priv);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
msg->buffer[priv->reg_buff_offset] =
|
||||
flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTBUFBIS0_OFFSET +
|
||||
priv->config->rx_inst * 0x4) & 0xff;
|
||||
}
|
||||
|
||||
priv->reg_buff_offset++;
|
||||
if (priv->reg_buff_offset == msg->length)
|
||||
{
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_RX_IRQ);
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ);
|
||||
priv->state = INTSTATE_IDLE;
|
||||
nxsem_post(&priv->wait);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((priv->state == INTSTATE_WRITE_DATA))
|
||||
{
|
||||
if (!priv->tx_done && get_shifter_status_flags(priv) & FLEXIO_TX_IRQ)
|
||||
{
|
||||
flexio_putreg32(priv, msg->buffer[priv->reg_buff_mod++],
|
||||
S32K1XX_FLEXIO_SHIFTBUFBBS0_OFFSET +
|
||||
priv->config->tx_inst * 0x4);
|
||||
priv->tx_count++;
|
||||
|
||||
if (priv->reg_buff_mod % msg->length == 0)
|
||||
{
|
||||
priv->reg_buff_mod = 0;
|
||||
priv->msgs++;
|
||||
}
|
||||
|
||||
if (priv->tx_count == priv->total_bytes)
|
||||
{
|
||||
priv->tx_done = 1;
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ);
|
||||
}
|
||||
}
|
||||
|
||||
if (get_shifter_status_flags(priv) & FLEXIO_RX_IRQ)
|
||||
{
|
||||
flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTBUFBIS0_OFFSET +
|
||||
priv->config->rx_inst * 0x4);
|
||||
|
||||
/* If RX shifter reports an error then stop bit (ACK)
|
||||
* doesn't go low, thus we get a NACK
|
||||
*/
|
||||
|
||||
if (priv->reg_buff_offset == 0 &&
|
||||
(flexio_getreg32(priv, S32K1XX_FLEXIO_SHIFTERR_OFFSET) &
|
||||
FLEXIO_RX_IRQ))
|
||||
{
|
||||
priv->error = 1;
|
||||
}
|
||||
|
||||
priv->reg_buff_offset++;
|
||||
if (priv->reg_buff_offset == priv->total_bytes - 1)
|
||||
{
|
||||
disable_shifter_status_interrupts(priv, FLEXIO_RX_IRQ);
|
||||
priv->state = INTSTATE_IDLE;
|
||||
nxsem_post(&priv->wait);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int set_expiretime(int expire_time, FAR struct timespec *set_time)
|
||||
{
|
||||
struct timespec curr_time;
|
||||
|
||||
/* Get current time. */
|
||||
|
||||
if (clock_gettime(CLOCK_REALTIME, &curr_time) != OK)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
set_time->tv_sec = expire_time / 1000;
|
||||
set_time->tv_nsec =
|
||||
(expire_time - (set_time->tv_sec * 1000)) * 1000 * 1000;
|
||||
|
||||
set_time->tv_sec += curr_time.tv_sec;
|
||||
set_time->tv_nsec += curr_time.tv_nsec;
|
||||
|
||||
/* Check more than 1 sec. */
|
||||
|
||||
if (set_time->tv_nsec >= (1000 * 1000 * 1000))
|
||||
{
|
||||
set_time->tv_sec += 1;
|
||||
set_time->tv_nsec -= (1000 * 1000 * 1000);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static void s32k1xx_flexio_i2c_init(struct s32k1xx_flexio_i2cdev_s *priv)
|
||||
{
|
||||
/* Reset FlexIO peripheral */
|
||||
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_CTRL_OFFSET, 0,
|
||||
FLEXIO_CTRL_SWRST);
|
||||
flexio_putreg32(priv, 0, S32K1XX_FLEXIO_CTRL_OFFSET);
|
||||
|
||||
/* Initialize FlexIO peripheral */
|
||||
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_CTRL_OFFSET,
|
||||
(FLEXIO_CTRL_DOZEN |
|
||||
FLEXIO_CTRL_DBGE |
|
||||
FLEXIO_CTRL_FASTACC |
|
||||
FLEXIO_CTRL_FLEXEN),
|
||||
(FLEXIO_CTRL_DBGE |
|
||||
FLEXIO_CTRL_FLEXEN_DIS));
|
||||
|
||||
/* Start bit enabled (logic 0) and stop bit enabled (logic 1). */
|
||||
|
||||
s32k1xx_flexio_i2c_set_nack(priv);
|
||||
|
||||
/* Transmit mode, output to FXIO pin */
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_SHIFTCTL_TIMSEL(priv->config->timer) |
|
||||
FLEXIO_SHIFTCTL_TIMPOL_PE |
|
||||
FLEXIO_SHIFTCTL_PINCFG_OD |
|
||||
FLEXIO_SHIFTCTL_PINSEL(priv->config->flexio_sda_pin) |
|
||||
FLEXIO_SHIFTCTL_PINPOL_LO |
|
||||
FLEXIO_SHIFTCTL_SMOD_TX,
|
||||
S32K1XX_FLEXIO_SHIFTCTL0_OFFSET + priv->config->tx_inst * 0x4);
|
||||
|
||||
/* Start bit disabled and stop bit enabled
|
||||
* (logic 0) for ACK/NACK detection..
|
||||
*/
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_SHIFTCFG_INSRC_PIN |
|
||||
FLEXIO_SHIFTCFG_SSTOP_ZERO |
|
||||
FLEXIO_SHIFTCFG_SSTART_DIS,
|
||||
S32K1XX_FLEXIO_SHIFTCFG0_OFFSET + priv->config->rx_inst * 0x4);
|
||||
|
||||
/* Configure receive using Timer X on falling edge
|
||||
* of clock with input data on Pin X
|
||||
*/
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_SHIFTCTL_TIMSEL(priv->config->timer) |
|
||||
FLEXIO_SHIFTCTL_TIMPOL_NE |
|
||||
FLEXIO_SHIFTCTL_PINCFG_DIS |
|
||||
FLEXIO_SHIFTCTL_PINSEL(priv->config->flexio_sda_pin) |
|
||||
FLEXIO_SHIFTCTL_SMOD_RX,
|
||||
S32K1XX_FLEXIO_SHIFTCTL0_OFFSET + priv->config->rx_inst * 0x4);
|
||||
|
||||
/* Configure start bit, stop bit, enable on trigger high,
|
||||
* disable on compare, reset if output equals pin.
|
||||
* Initial clock state is logic 0 and is not affected by reset.
|
||||
*/
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_TIMCFG_TSTART_ENA |
|
||||
FLEXIO_TIMCFG_TSTOP_TIMDIS |
|
||||
FLEXIO_TIMCFG_TIMENA_TRGHI |
|
||||
FLEXIO_TIMCFG_TIMDIS_TIMCMP |
|
||||
FLEXIO_TIMCFG_TIMRST_PINOUT |
|
||||
FLEXIO_TIMCFG_TIMOUT_ZERO,
|
||||
S32K1XX_FLEXIO_TIMCFG0_OFFSET + priv->config->two_word_timer * 0x4);
|
||||
|
||||
/* Configure dual 8-bit counter using Pin 1 output enable (SCL open drain),
|
||||
* with Shifter 0 flag as the inverted trigger.
|
||||
*/
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_TIMCTL_TRGSEL_SHIFTER(priv->config->tx_inst) |
|
||||
FLEXIO_TIMCTL_TRGPOL_LO |
|
||||
FLEXIO_TIMCTL_TRGSRC_INT |
|
||||
FLEXIO_TIMCTL_PINCFG_OD |
|
||||
FLEXIO_TIMCTL_PINSEL(priv->config->flexio_scl_pin) |
|
||||
FLEXIO_TIMCTL_TIMOD_8BBAUD,
|
||||
S32K1XX_FLEXIO_TIMCTL0_OFFSET + priv->config->two_word_timer * 0x4);
|
||||
|
||||
/* Configure 8-bit transfer. Set TIMCMP[15:0] = (number of bits x 2) - 1. */
|
||||
|
||||
flexio_putreg32(priv, 0xf, S32K1XX_FLEXIO_TIMCMP0_OFFSET +
|
||||
priv->config->timer * 0x4);
|
||||
|
||||
/* Enable when Timer 0 is enabled, disable when Timer 0 is disabled,
|
||||
* enable start bit and stop bit at end of each word,
|
||||
* decrement on pin input..
|
||||
*/
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_TIMCFG_TSTART_ENA |
|
||||
FLEXIO_TIMCFG_TSTOP_TIMCMP |
|
||||
FLEXIO_TIMCFG_TIMENA_TIMENA |
|
||||
FLEXIO_TIMCFG_TIMDIS_TIMDIS |
|
||||
FLEXIO_TIMCFG_TIMDEC_PINBOTHPIN,
|
||||
S32K1XX_FLEXIO_TIMCFG0_OFFSET + priv->config->timer * 0x4);
|
||||
|
||||
/* Configure 16-bit counter using inverted Pin 1 input (SCL).. */
|
||||
|
||||
flexio_putreg32(priv, FLEXIO_TIMCTL_TRGSEL_SHIFTER(priv->config->tx_inst) |
|
||||
FLEXIO_TIMCTL_TRGPOL_LO |
|
||||
FLEXIO_TIMCTL_TRGSRC_INT |
|
||||
FLEXIO_TIMCTL_PINSEL(priv->config->flexio_scl_pin) |
|
||||
FLEXIO_TIMCTL_PINPOL_LO |
|
||||
FLEXIO_TIMCTL_TIMOD_16BCNT,
|
||||
S32K1XX_FLEXIO_TIMCTL0_OFFSET + priv->config->timer * 0x4);
|
||||
|
||||
flexio_modifyreg32(priv, S32K1XX_FLEXIO_CTRL_OFFSET, 0,
|
||||
FLEXIO_CTRL_FLEXEN);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_flexio_i2cbus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialise an I2C device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct i2c_master_s *s32k1xx_flexio_i2cbus_initialize(int port)
|
||||
{
|
||||
struct s32k1xx_flexio_i2cdev_s *priv;
|
||||
|
||||
if (port == 0)
|
||||
{
|
||||
priv = &g_i2c0dev;
|
||||
priv->dev.ops = &s32k1xx_flexio_i2c_ops;
|
||||
}
|
||||
else
|
||||
{
|
||||
i2cerr("I2C Only support 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
|
||||
/* Test if already initialized or not */
|
||||
|
||||
if (1 < ++priv->refs)
|
||||
{
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return &priv->dev;
|
||||
}
|
||||
|
||||
priv->port = port;
|
||||
priv->frequency = 0;
|
||||
|
||||
s32k1xx_get_pclkfreq(FLEXIO0_CLK, &priv->base_freq);
|
||||
|
||||
/* Configure pins */
|
||||
|
||||
s32k1xx_pinconfig(priv->config->scl_pin);
|
||||
s32k1xx_pinconfig(priv->config->sda_pin);
|
||||
|
||||
s32k1xx_flexio_i2c_init(priv);
|
||||
|
||||
/* Attach Interrupt Handler */
|
||||
|
||||
irq_attach(priv->irqid, s32k1xx_flexio_i2c_interrupt, priv);
|
||||
|
||||
/* Enable Interrupt Handler */
|
||||
|
||||
up_enable_irq(priv->irqid);
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return &priv->dev;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_flexio_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* Uninitialise an I2C device
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s32k1xx_flexio_i2cbus_uninitialize(struct i2c_master_s *dev)
|
||||
{
|
||||
struct s32k1xx_flexio_i2cdev_s *priv =
|
||||
(struct s32k1xx_flexio_i2cdev_s *)dev;
|
||||
|
||||
/* Decrement reference count and check for underflow */
|
||||
|
||||
if (priv->refs == 0)
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
if (--priv->refs)
|
||||
{
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
up_disable_irq(priv->irqid);
|
||||
irq_detach(priv->irqid);
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_flexio_i2c_transfer
|
||||
*
|
||||
* Description:
|
||||
* Perform a sequence of I2C transfers
|
||||
*
|
||||
* TODO: Multiple i2c_msg_s read operations with the same address are not
|
||||
* currently guaranteed.
|
||||
****************************************************************************/
|
||||
|
||||
static int s32k1xx_flexio_i2c_transfer(struct i2c_master_s *dev,
|
||||
struct i2c_msg_s *msgs, int count)
|
||||
{
|
||||
struct s32k1xx_flexio_i2cdev_s *priv =
|
||||
(struct s32k1xx_flexio_i2cdev_s *)dev;
|
||||
int i;
|
||||
int ret = 0;
|
||||
int semval = 0;
|
||||
struct timespec abs_time;
|
||||
|
||||
if (msgs->frequency > I2C_MAX_FREQUENCY)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DEBUGASSERT(dev != NULL);
|
||||
|
||||
/* Get exclusive access to the I2C bus */
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
|
||||
/* Check wait semaphore value. If the value is not 0, the transfer can not
|
||||
* be performed normally.
|
||||
*/
|
||||
|
||||
ret = nxsem_get_value(&priv->wait, &semval);
|
||||
DEBUGASSERT(ret == OK && semval == 0);
|
||||
|
||||
priv->total_bytes = 0;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
priv->total_bytes += msgs[i].length;
|
||||
}
|
||||
|
||||
/* FlexIO driver can only handle transfers of maximum 12 bytes */
|
||||
|
||||
if (priv->total_bytes <= 12)
|
||||
{
|
||||
/* Pass msg descriptor via device context */
|
||||
|
||||
priv->msgs = msgs;
|
||||
priv->error = OK;
|
||||
set_expiretime(50, &abs_time);
|
||||
|
||||
s32k1xx_flexio_i2c_set_freq_and_size(priv, msgs->frequency,
|
||||
priv->total_bytes);
|
||||
s32k1xx_flexio_i2c_set_nack(priv);
|
||||
s32k1xx_flexio_i2c_clear_errors(priv);
|
||||
|
||||
priv->tx_done = 0;
|
||||
priv->tx_count = 0;
|
||||
|
||||
if (msgs->flags & I2C_M_READ)
|
||||
{
|
||||
priv->reg_buff_offset = -1; /* Ignore readback addr */
|
||||
priv->state = INTSTATE_RECV_DATA;
|
||||
flexio_putreg32(priv, FLEXIO_ADDR_READ(msgs->addr),
|
||||
S32K1XX_FLEXIO_SHIFTBUFBBS0_OFFSET +
|
||||
priv->config->tx_inst * 0x4);
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->reg_buff_offset = 0;
|
||||
priv->reg_buff_mod = 0;
|
||||
priv->state = INTSTATE_WRITE_DATA;
|
||||
flexio_putreg32(priv, FLEXIO_ADDR_WRITE(msgs->addr),
|
||||
S32K1XX_FLEXIO_SHIFTBUFBBS0_OFFSET +
|
||||
priv->config->tx_inst * 0x4);
|
||||
}
|
||||
|
||||
enable_shifter_status_interrupts(priv, FLEXIO_TX_IRQ | FLEXIO_RX_IRQ);
|
||||
nxsem_timedwait_uninterruptible(&priv->wait, &abs_time);
|
||||
|
||||
if (priv->error != OK)
|
||||
{
|
||||
ret = priv->error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FlexIO driver can only handle transfers of maximum 12 bytes */
|
||||
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_S32K1XX_FLEXIO_I2C */
|
74
arch/arm/src/s32k1xx/s32k1xx_flexio_i2c.h
Normal file
74
arch/arm/src/s32k1xx/s32k1xx_flexio_i2c.h
Normal file
@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
* arch/arm/src/s32k1xx/s32k1xx_flexio_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_S32K1XX_S32K1XX_FLEXIO_I2C_H
|
||||
#define __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXIO_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
#include "chip.h"
|
||||
#include "hardware/s32k1xx_flexio.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_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 *s32k1xx_flexio_i2cbus_initialize(int port);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: s32k1xx_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* De-initialize the selected I2C port, and power down the device.
|
||||
*
|
||||
* Input Parameters:
|
||||
* Device structure as returned by the s32k1xx_i2cbus_initialize()
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, ERROR when internal reference count mismatch or dev
|
||||
* points to invalid hardware device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int s32k1xx_flexio_i2cbus_uninitialize(struct i2c_master_s *dev);
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_S32K1XX_S32K1XX_FLEXIO_I2C_H */
|
Loading…
Reference in New Issue
Block a user