risc-v/bl808: Add I2C driver
This change implements a driver with support for all four I2C blocks on the BL808.
This commit is contained in:
parent
41c0fc01b9
commit
923dc37a3b
13 changed files with 1234 additions and 10 deletions
|
@ -48,7 +48,7 @@ DMA No
|
|||
EMAC No
|
||||
GPADC Yes
|
||||
GPIO Yes
|
||||
I2C No
|
||||
I2C Yes
|
||||
I2S No
|
||||
PWM No
|
||||
SPI Yes
|
||||
|
|
|
@ -54,6 +54,8 @@
|
|||
/* D0 IRQs ******************************************************************/
|
||||
|
||||
#define BL808_IRQ_UART3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 4)
|
||||
#define BL808_IRQ_I2C2 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 5)
|
||||
#define BL808_IRQ_I2C3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 6)
|
||||
#define BL808_IRQ_SPI1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 7)
|
||||
#define BL808_IRQ_D0_IPC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 38)
|
||||
#define BL808_IRQ_TIMER1_CH0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 61)
|
||||
|
@ -68,8 +70,10 @@
|
|||
#define BL808_IRQ_UART0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 28)
|
||||
#define BL808_IRQ_UART1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 29)
|
||||
#define BL808_IRQ_UART2 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 30)
|
||||
#define BL808_IRQ_I2C0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 32)
|
||||
#define BL808_IRQ_TIMER0_CH0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 36)
|
||||
#define BL808_IRQ_TIMER0_CH1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 37)
|
||||
#define BL808_IRQ_WDT0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 38)
|
||||
#define BL808_IRQ_I2C1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 39)
|
||||
|
||||
#endif /* __ARCH_RISCV_INCLUDE_BL808_IRQ_H */
|
||||
|
|
|
@ -106,6 +106,98 @@ config BL808_GPADC_SCAN_ORD11
|
|||
|
||||
endmenu
|
||||
|
||||
menuconfig BL808_I2C0
|
||||
bool "I2C 0"
|
||||
default n
|
||||
select I2C
|
||||
select I2C_DRIVER
|
||||
select ARCH_HAVE_I2CRESET
|
||||
|
||||
if BL808_I2C0
|
||||
|
||||
comment "Refer to datasheet for valid pin assignments"
|
||||
|
||||
config BL808_I2C0_SCL
|
||||
int "SCL Pin"
|
||||
default 6
|
||||
range 0 45
|
||||
|
||||
config BL808_I2C0_SDA
|
||||
int "SDA Pin"
|
||||
default 7
|
||||
range 0 45
|
||||
|
||||
endif
|
||||
|
||||
menuconfig BL808_I2C1
|
||||
bool "I2C 1"
|
||||
default n
|
||||
select I2C
|
||||
select I2C_DRIVER
|
||||
select ARCH_HAVE_I2CRESET
|
||||
|
||||
if BL808_I2C1
|
||||
|
||||
comment "Refer to datasheet for valid pin assignments"
|
||||
|
||||
config BL808_I2C1_SCL
|
||||
int "SCL Pin"
|
||||
default 6
|
||||
range 0 45
|
||||
|
||||
config BL808_I2C1_SDA
|
||||
int "SDA Pin"
|
||||
default 7
|
||||
range 0 45
|
||||
|
||||
endif
|
||||
|
||||
menuconfig BL808_I2C2
|
||||
bool "I2C 2"
|
||||
default n
|
||||
select I2C
|
||||
select I2C_DRIVER
|
||||
select ARCH_HAVE_I2CRESET
|
||||
|
||||
if BL808_I2C2
|
||||
|
||||
comment "Refer to datasheet for valid pin assignments"
|
||||
|
||||
config BL808_I2C2_SCL
|
||||
int "SCL Pin"
|
||||
default 6
|
||||
range 0 45
|
||||
|
||||
config BL808_I2C2_SDA
|
||||
int "SDA Pin"
|
||||
default 7
|
||||
range 0 45
|
||||
|
||||
endif
|
||||
|
||||
menuconfig BL808_I2C3
|
||||
bool "I2C 3"
|
||||
default n
|
||||
select I2C
|
||||
select I2C_DRIVER
|
||||
select ARCH_HAVE_I2CRESET
|
||||
|
||||
if BL808_I2C3
|
||||
|
||||
comment "Refer to datasheet for valid pin assignments"
|
||||
|
||||
config BL808_I2C3_SCL
|
||||
int "SCL Pin"
|
||||
default 6
|
||||
range 0 45
|
||||
|
||||
config BL808_I2C3_SDA
|
||||
int "SDA Pin"
|
||||
default 7
|
||||
range 0 45
|
||||
|
||||
endif
|
||||
|
||||
config BL808_UART0
|
||||
bool "UART 0"
|
||||
default n
|
||||
|
|
|
@ -31,3 +31,4 @@ CHIP_CSRCS = bl808_start.c bl808_irq_dispatch.c bl808_irq.c
|
|||
CHIP_CSRCS += bl808_timerisr.c bl808_allocateheap.c
|
||||
CHIP_CSRCS += bl808_gpio.c bl808_mm_init.c bl808_pgalloc.c bl808_serial.c
|
||||
CHIP_CSRCS += bl808_gpadc.c bl808_spi.c bl808_timer.c bl808_wdt.c
|
||||
CHIP_CSRCS += bl808_i2c.c
|
||||
|
|
|
@ -58,8 +58,8 @@
|
|||
|
||||
#define GPIO_MODE_SHIFT (10) /* Bit 10: Port Mode */
|
||||
#define GPIO_MODE_MASK (1 << GPIO_MODE_SHIFT)
|
||||
# define GPIO_INPUT (1 << GPIO_MODE_SHIFT) /* Input Enable */
|
||||
# define GPIO_OUTPUT (0 << GPIO_MODE_SHIFT) /* Output Enable */
|
||||
#define GPIO_INPUT (1 << GPIO_MODE_SHIFT) /* Input Enable */
|
||||
#define GPIO_OUTPUT (0 << GPIO_MODE_SHIFT) /* Output Enable */
|
||||
|
||||
/* Input/Output pull-ups/downs:
|
||||
*
|
||||
|
@ -116,6 +116,7 @@
|
|||
#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) /* SDH */
|
||||
#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) /* SPI0 */
|
||||
#define GPIO_FUNC_FLASH (2 << GPIO_FUNC_SHIFT) /* Flash */
|
||||
#define GPIO_FUNC_I2C0 (5 << GPIO_FUNC_SHIFT) /* I2C0 */
|
||||
#define GPIO_FUNC_I2C1 (6 << GPIO_FUNC_SHIFT) /* I2C1 */
|
||||
#define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) /* UART */
|
||||
#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) /* CSI */
|
||||
|
@ -123,6 +124,8 @@
|
|||
#define GPIO_FUNC_SWGPIO (11 << GPIO_FUNC_SHIFT) /* Software GPIO */
|
||||
#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) /* PWM0 */
|
||||
#define GPIO_FUNC_SPI1 (18 << GPIO_FUNC_SHIFT) /* SPI1 */
|
||||
#define GPIO_FUNC_I2C2 (19 << GPIO_FUNC_SHIFT) /* I2C2 */
|
||||
#define GPIO_FUNC_I2C3 (20 << GPIO_FUNC_SHIFT) /* I2C3 */
|
||||
#define GPIO_FUNC_JTAG_D0 (27 << GPIO_FUNC_SHIFT) /* JTAG */
|
||||
|
||||
/****************************************************************************
|
||||
|
|
848
arch/risc-v/src/bl808/bl808_i2c.c
Normal file
848
arch/risc-v/src/bl808/bl808_i2c.c
Normal file
|
@ -0,0 +1,848 @@
|
|||
/****************************************************************************
|
||||
* arch/risc-v/src/bl808/bl808_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 <nuttx/arch.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include <nuttx/fs/ioctl.h>
|
||||
|
||||
#include "hardware/bl808_i2c.h"
|
||||
#include "hardware/bl808_glb.h"
|
||||
#include "hardware/bl808_mm_glb.h"
|
||||
#include "riscv_internal.h"
|
||||
#include "chip.h"
|
||||
#include "bl808_gpio.h"
|
||||
#include "bl808_i2c.h"
|
||||
|
||||
#if defined(CONFIG_BL808_I2C0) || defined(CONFIG_BL808_I2C1) \
|
||||
|| defined(CONFIG_BL808_I2C2) || defined(CONFIG_BL808_I2C3)
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define XCLK 40000000 // 40 MHz crystal oscillator
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
struct bl808_i2c_s
|
||||
{
|
||||
struct i2c_ops_s *ops;
|
||||
|
||||
uint8_t irq;
|
||||
uint8_t idx;
|
||||
uint8_t scl_pin;
|
||||
uint8_t sda_pin;
|
||||
int refs;
|
||||
mutex_t lock;
|
||||
sem_t sem_isr;
|
||||
|
||||
struct i2c_msg_s *msgs;
|
||||
int error;
|
||||
uint8_t msgidx;
|
||||
uint32_t bytes;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
FAR struct i2c_msg_s *msgs, int count);
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
int bl808_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct i2c_ops_s bl808_i2c_ops =
|
||||
{
|
||||
.transfer = bl808_i2c_transfer,
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
.reset = bl808_i2c_reset
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_BL808_I2C0
|
||||
static struct bl808_i2c_s bl808_i2c0 =
|
||||
{
|
||||
.ops = &bl808_i2c_ops,
|
||||
.irq = BL808_IRQ_I2C0,
|
||||
.idx = 0,
|
||||
.scl_pin = CONFIG_BL808_I2C0_SCL,
|
||||
.sda_pin = CONFIG_BL808_I2C0_SDA,
|
||||
.refs = 0,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.sem_isr = SEM_INITIALIZER(0),
|
||||
.msgs = NULL,
|
||||
.error = OK,
|
||||
.msgidx = 0,
|
||||
.bytes = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C1
|
||||
static struct bl808_i2c_s bl808_i2c1 =
|
||||
{
|
||||
.ops = &bl808_i2c_ops,
|
||||
.irq = BL808_IRQ_I2C1,
|
||||
.idx = 1,
|
||||
.scl_pin = CONFIG_BL808_I2C1_SCL,
|
||||
.sda_pin = CONFIG_BL808_I2C1_SDA,
|
||||
.refs = 0,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.sem_isr = SEM_INITIALIZER(0),
|
||||
.msgs = NULL,
|
||||
.error = OK,
|
||||
.msgidx = 0,
|
||||
.bytes = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C2
|
||||
static struct bl808_i2c_s bl808_i2c2 =
|
||||
{
|
||||
.ops = &bl808_i2c_ops,
|
||||
.irq = BL808_IRQ_I2C2,
|
||||
.idx = 2,
|
||||
.scl_pin = CONFIG_BL808_I2C2_SCL,
|
||||
.sda_pin = CONFIG_BL808_I2C2_SDA,
|
||||
.refs = 0,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.sem_isr = SEM_INITIALIZER(0),
|
||||
.msgs = NULL,
|
||||
.error = OK,
|
||||
.msgidx = 0,
|
||||
.bytes = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C3
|
||||
static struct bl808_i2c_s bl808_i2c3 =
|
||||
{
|
||||
.ops = &bl808_i2c_ops,
|
||||
.irq = BL808_IRQ_I2C3,
|
||||
.idx = 3,
|
||||
.scl_pin = CONFIG_BL808_I2C3_SCL,
|
||||
.sda_pin = CONFIG_BL808_I2C3_SDA,
|
||||
.refs = 0,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.sem_isr = SEM_INITIALIZER(0),
|
||||
.msgs = NULL,
|
||||
.error = OK,
|
||||
.msgidx = 0,
|
||||
.bytes = 0
|
||||
};
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_find_clock_dividers
|
||||
*
|
||||
* Description:
|
||||
* Finds values for the clock divison registers to give the requested
|
||||
* frequency. Tries to keep period values small for better accuracy.
|
||||
* Warns when fails to match freq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* module_div - Return location for I2C module clock divider
|
||||
* period_div - Return location for internal cycle count divider.
|
||||
* freq - Requested frequency
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_find_clock_dividers(uint8_t *module_div,
|
||||
uint8_t *period_div,
|
||||
uint32_t freq)
|
||||
{
|
||||
int best_module_div = 1;
|
||||
int best_period_div = 2;
|
||||
int min_error = abs(XCLK - freq);
|
||||
|
||||
/* This function will try to keep the value that goes into the prd fields
|
||||
* as small as possible because I found through testing that this yields
|
||||
* clocks that are more accurate to the target. Writing 0 to the period
|
||||
* fields causes all transmissions to fail, so start with a divider of 2.
|
||||
*/
|
||||
|
||||
for (int period_iter = 2; period_iter < 256; period_iter++)
|
||||
{
|
||||
int calc_module = ((XCLK / (period_iter * 4)) / freq);
|
||||
if (calc_module > 256) /* Discard non viable values */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (calc_module == 0) /* Avoid division by 0 */
|
||||
{
|
||||
/* All subsequent values of period_iter will result in 0 again */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
int freq_result = (XCLK / (4*period_iter)) / (calc_module);
|
||||
if (freq_result == freq)
|
||||
{
|
||||
best_period_div = period_iter;
|
||||
best_module_div = calc_module;
|
||||
min_error = 0;
|
||||
break;
|
||||
}
|
||||
else if (abs(freq_result - freq) < min_error)
|
||||
{
|
||||
best_module_div = period_iter;
|
||||
best_period_div = calc_module;
|
||||
min_error = abs(freq_result - freq);
|
||||
}
|
||||
}
|
||||
|
||||
if (min_error > 0)
|
||||
{
|
||||
i2cwarn("Couldn't match requested I2C frequency. Requested %d, got %d",
|
||||
freq, XCLK / (4*best_module_div) / (best_period_div));
|
||||
}
|
||||
|
||||
*module_div = best_module_div - 1;
|
||||
*period_div = best_period_div - 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_set_freq
|
||||
*
|
||||
* Description:
|
||||
* Set I2C module frequency to freq.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
* freq - Requested frequency
|
||||
*
|
||||
* Returned Value:
|
||||
* Error status. Always returns OK.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2c_set_freq(struct bl808_i2c_s *priv, uint32_t freq)
|
||||
{
|
||||
uint8_t idx = priv->idx;
|
||||
|
||||
uint8_t module_div;
|
||||
uint8_t period_div;
|
||||
bl808_i2c_find_clock_dividers(&module_div, &period_div, freq);
|
||||
|
||||
/* Now we have our dividers and we can write config registers */
|
||||
|
||||
if ((idx == 0) || (idx == 1))
|
||||
{
|
||||
/* Set clock source to xtal and set module clk division */
|
||||
|
||||
modifyreg32(BL808_GLB_I2C_CFG0, I2C_CFG_CLK_DIV_MASK,
|
||||
I2C_CFG_CLK_EN
|
||||
| I2C_CFG_CLK_XTAL
|
||||
| (module_div << I2C_CFG_CLK_DIV_SHIFT));
|
||||
}
|
||||
else if (idx == 2)
|
||||
{
|
||||
modifyreg32(BL808_MM_GLB_CLK_CTRL_CPU, 0,
|
||||
CLK_CTRL_CPU_I2C_CLK_XTAL);
|
||||
modifyreg32(BL808_MM_GLB_CLK_CTRL_PERI,
|
||||
CLK_CTRL_PERI_I2C0_DIV_MASK,
|
||||
CLK_CTRL_PERI_I2C0_EN
|
||||
| CLK_CTRL_PERI_I2C0_DIV_EN
|
||||
| (module_div << CLK_CTRL_PERI_I2C0_DIV_SHIFT));
|
||||
}
|
||||
else if (idx == 3)
|
||||
{
|
||||
modifyreg32(BL808_MM_GLB_CLK_CTRL_CPU, 0,
|
||||
CLK_CTRL_CPU_I2C_CLK_XTAL);
|
||||
modifyreg32(BL808_MM_GLB_CLK_CTRL_PERI3,
|
||||
CLK_CTRL_PERI_I2C1_DIV_MASK,
|
||||
CLK_CTRL_PERI_I2C1_EN
|
||||
| CLK_CTRL_PERI_I2C1_DIV_EN
|
||||
| (module_div << CLK_CTRL_PERI_I2C1_DIV_SHIFT));
|
||||
}
|
||||
|
||||
modifyreg32(BL808_I2C_PRD_START(idx), 0xffffffff,
|
||||
period_div << I2C_PRD_PH0_SHIFT
|
||||
| period_div << I2C_PRD_PH1_SHIFT
|
||||
| period_div << I2C_PRD_PH2_SHIFT
|
||||
| period_div << I2C_PRD_PH3_SHIFT);
|
||||
modifyreg32(BL808_I2C_PRD_STOP(idx), 0xffffffff,
|
||||
period_div << I2C_PRD_PH0_SHIFT
|
||||
| period_div << I2C_PRD_PH1_SHIFT
|
||||
| period_div << I2C_PRD_PH2_SHIFT
|
||||
| period_div << I2C_PRD_PH3_SHIFT);
|
||||
modifyreg32(BL808_I2C_PRD_DATA(idx), 0xffffffff,
|
||||
period_div << I2C_PRD_PH0_SHIFT
|
||||
| period_div << I2C_PRD_PH1_SHIFT
|
||||
| period_div << I2C_PRD_PH2_SHIFT
|
||||
| period_div << I2C_PRD_PH3_SHIFT);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_write
|
||||
*
|
||||
* Description:
|
||||
* Writes one message into the TX FIFO.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_write(struct bl808_i2c_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgs[priv->msgidx];
|
||||
|
||||
uint8_t count = msg->length - priv->bytes;
|
||||
if (count > 4)
|
||||
{
|
||||
count = 4; /* Only handle 4 bytes at a time */
|
||||
}
|
||||
|
||||
uint32_t regval = 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
uint8_t byte = msg->buffer[priv->bytes + i];
|
||||
regval |= byte << (i * 8);
|
||||
}
|
||||
|
||||
putreg32(regval, BL808_I2C_WDATA(priv->idx));
|
||||
priv->bytes += count;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_read
|
||||
*
|
||||
* Description:
|
||||
* Reads one message from the RX FIFO.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_read(struct bl808_i2c_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgs[priv->msgidx];
|
||||
uint8_t count = msg->length - priv->bytes;
|
||||
uint32_t regval = getreg32(BL808_I2C_RDATA(priv->idx));
|
||||
|
||||
if (count > 4)
|
||||
{
|
||||
count = 4; /* Only handle 4 bytes at a time */
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
msg->buffer[priv->bytes + i] = regval & 0xff;
|
||||
regval = regval >> 8;
|
||||
}
|
||||
|
||||
priv->bytes += count;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_transferbytes
|
||||
*
|
||||
* Description:
|
||||
* Determines a message should be written or read. Disables FIFO
|
||||
* interrupts all bytes are handled.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_transferbytes(struct bl808_i2c_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgs[priv->msgidx];
|
||||
|
||||
if (msg->flags & I2C_M_READ)
|
||||
{
|
||||
if (priv->bytes < msg->length)
|
||||
{
|
||||
bl808_i2c_read(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx), 0,
|
||||
I2C_RX_FIFO_RDY_MASK);
|
||||
modifyreg32(BL808_I2C_FIFO_CONFIG_0(priv->idx), 0,
|
||||
RX_FIFO_CLR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->bytes < msg->length)
|
||||
{
|
||||
bl808_i2c_write(priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx), 0,
|
||||
I2C_TX_FIFO_RDY_MASK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_start_transfer
|
||||
*
|
||||
* Description:
|
||||
* Configures I2C module according to message, enables relevant
|
||||
* interrupts and intitiates the transaction.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_start_transfer(struct bl808_i2c_s *priv)
|
||||
{
|
||||
struct i2c_msg_s *msg = &priv->msgs[priv->msgidx];
|
||||
|
||||
/* Set frequency and slave address */
|
||||
|
||||
bl808_i2c_set_freq(priv, msg->frequency);
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx), I2C_SLV_ADDR_MASK,
|
||||
(msg->addr << I2C_SLV_ADDR_SHIFT));
|
||||
|
||||
modifyreg32(BL808_I2C_FIFO_CONFIG_0(priv->idx), 0,
|
||||
TX_FIFO_CLR | RX_FIFO_CLR);
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
I2C_PKT_LEN_MASK,
|
||||
((msg->length - 1) << I2C_PKT_LEN_SHIFT));
|
||||
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx),
|
||||
I2C_END_MASK | I2C_NAK_MASK
|
||||
| I2C_ARB_MASK
|
||||
| I2C_FIFO_ERROR_MASK, 0);
|
||||
|
||||
/* Unmask relevant interrupts */
|
||||
|
||||
if (msg->flags & I2C_M_READ)
|
||||
{
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx),
|
||||
I2C_RX_FIFO_RDY_MASK, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx),
|
||||
I2C_TX_FIFO_RDY_MASK, 0);
|
||||
}
|
||||
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx), 0,
|
||||
I2C_M_EN);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_transfer_finished
|
||||
*
|
||||
* Description:
|
||||
* Disables I2C and clears FIFOs and interrupts.
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - Private I2C device structure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void bl808_i2c_transfer_finished(struct bl808_i2c_s *priv)
|
||||
{
|
||||
/* Disable i2c */
|
||||
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx), I2C_M_EN, 0);
|
||||
|
||||
/* Clear FIFOs */
|
||||
|
||||
modifyreg32(BL808_I2C_FIFO_CONFIG_0(priv->idx), 0,
|
||||
TX_FIFO_CLR | RX_FIFO_CLR);
|
||||
|
||||
/* Mask all interrupts */
|
||||
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx), 0,
|
||||
I2C_END_MASK | I2C_TX_FIFO_RDY_MASK
|
||||
| I2C_RX_FIFO_RDY_MASK | I2C_NAK_MASK
|
||||
| I2C_ARB_MASK | I2C_FIFO_ERROR_MASK);
|
||||
|
||||
/* Clear interrupts */
|
||||
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx), 0,
|
||||
I2C_END_CLR | I2C_NAK_CLR | I2C_ARB_CLR);
|
||||
|
||||
nxsem_post(&priv->sem_isr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: i2c_interrupt
|
||||
*
|
||||
* Description:
|
||||
* I2C interrupt handler. Handles transfer-related errors, as well as
|
||||
* loading or reading from FIFOs when ready.
|
||||
*
|
||||
* Returned Value:
|
||||
* Error status. Returns -EIO for transfer errors, OK otherwise.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int i2c_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct bl808_i2c_s *priv = (struct bl808_i2c_s *)arg;
|
||||
uint32_t int_status = getreg32(BL808_I2C_INT_STS(priv->idx));
|
||||
|
||||
if (int_status & I2C_ARB_INT)
|
||||
{
|
||||
bl808_i2c_transfer_finished(priv);
|
||||
i2cerr("Bus arbitration error\n");
|
||||
priv->error = -EIO;
|
||||
return -EIO;
|
||||
}
|
||||
else if (int_status & I2C_FIFO_ERROR_INT)
|
||||
{
|
||||
bl808_i2c_transfer_finished(priv);
|
||||
i2cerr("FIFO error");
|
||||
priv->error = -EIO;
|
||||
return -EIO;
|
||||
}
|
||||
else if (int_status & I2C_NAK_INT)
|
||||
{
|
||||
bl808_i2c_transfer_finished(priv);
|
||||
i2cwarn("Transfer not acknowledged\n");
|
||||
priv->error = -EIO;
|
||||
return -EIO;
|
||||
}
|
||||
else if (int_status & I2C_RX_FIFO_RDY_INT)
|
||||
{
|
||||
bl808_i2c_transferbytes(priv);
|
||||
return OK;
|
||||
}
|
||||
else if (int_status & I2C_END_INT)
|
||||
{
|
||||
bl808_i2c_transfer_finished(priv);
|
||||
return OK;
|
||||
}
|
||||
else if (int_status & I2C_TX_FIFO_RDY_INT)
|
||||
{
|
||||
bl808_i2c_transferbytes(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Should not get here */
|
||||
|
||||
i2cerr("Unidentified interrupt\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Driver methods */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_transfer
|
||||
*
|
||||
* Description:
|
||||
* Method accessed by the I2C master driver. Configures hardware for
|
||||
* each message to be transferred, then initiates each transfer.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Public I2C device structure
|
||||
* msgs - Message array to transfer
|
||||
* count - Number of messages to transfer
|
||||
*
|
||||
* Returned Value:
|
||||
* Error status. Returns errors that may propagate from nxmutex_lock()
|
||||
* or -EIO. Otherwise returns OK.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2c_transfer(FAR struct i2c_master_s *dev,
|
||||
struct i2c_msg_s *msgs, int count)
|
||||
{
|
||||
struct bl808_i2c_s *priv = (struct bl808_i2c_s *)dev;
|
||||
int ret;
|
||||
priv->msgs = msgs;
|
||||
priv->error = OK;
|
||||
|
||||
ret = nxmutex_lock(&priv->lock);
|
||||
if (ret < 0)
|
||||
{
|
||||
i2cerr("Lock error\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
I2C_SUB_ADDR_EN, 0);
|
||||
|
||||
for (int idx = 0; idx < count; idx++)
|
||||
{
|
||||
priv->bytes = 0;
|
||||
|
||||
/* Handle message flags */
|
||||
|
||||
if (msgs[idx].flags & I2C_M_READ)
|
||||
{
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
0, I2C_DIR_R);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
I2C_DIR_R, 0);
|
||||
}
|
||||
|
||||
if (msgs[idx].flags & I2C_M_TEN)
|
||||
{
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
0, I2C_10B_ADDR_EN);
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx),
|
||||
I2C_10B_ADDR_EN, 0);
|
||||
}
|
||||
|
||||
if (msgs[idx].flags & I2C_M_NOSTOP)
|
||||
{
|
||||
if (msgs[idx].length > 4)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
modifyreg32(BL808_I2C_CONFIG(priv->idx), I2C_SUB_ADDR_LEN_MASK,
|
||||
(I2C_SUB_ADDR_EN) | ((msgs[idx].length - 1)
|
||||
<< I2C_SUB_ADDR_LEN_SHIFT));
|
||||
|
||||
uint32_t subaddr_regval = 0;
|
||||
for (uint8_t subaddr_idx = 0;
|
||||
subaddr_idx < msgs[idx].length;
|
||||
subaddr_idx++)
|
||||
{
|
||||
subaddr_regval |= msgs[idx].buffer[subaddr_idx]
|
||||
<< (subaddr_idx * 8);
|
||||
}
|
||||
|
||||
putreg32(subaddr_regval, BL808_I2C_SUB_ADDR(priv->idx));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
priv->msgidx = idx;
|
||||
|
||||
bl808_i2c_start_transfer(priv);
|
||||
|
||||
ret = nxsem_wait_uninterruptible(&priv->sem_isr);
|
||||
if (ret < 0)
|
||||
{
|
||||
i2cerr("Transfer error\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* If something went wrong with the transfer (e.g. NAK),
|
||||
* the interrupt will have set priv->error.
|
||||
*/
|
||||
|
||||
ret = priv->error;
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2c_reset
|
||||
*
|
||||
* Description:
|
||||
* Method accessed by the I2C master driver. Calls transfer_finished to
|
||||
* clear FIFOs and interrupts.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Public I2C device structure
|
||||
*
|
||||
* Returned Value:
|
||||
* Error status. Always returns OK.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2c_reset(struct i2c_master_s *dev)
|
||||
{
|
||||
struct bl808_i2c_s *priv = (struct bl808_i2c_s *)dev;
|
||||
bl808_i2c_transfer_finished(priv);
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_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 Parameter:
|
||||
* 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 *bl808_i2cbus_initialize(int port)
|
||||
{
|
||||
struct bl808_i2c_s *priv;
|
||||
gpio_pinattr_t gpio_attr = GPIO_INPUT | GPIO_PULLUP;
|
||||
|
||||
switch (port)
|
||||
{
|
||||
#ifdef CONFIG_BL808_I2C0
|
||||
case 0:
|
||||
priv = &bl808_i2c0;
|
||||
gpio_attr |= GPIO_FUNC_I2C0;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C1
|
||||
case 1:
|
||||
priv = &bl808_i2c1;
|
||||
gpio_attr |= GPIO_FUNC_I2C1;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C2
|
||||
case 2:
|
||||
priv = &bl808_i2c2;
|
||||
gpio_attr |= GPIO_FUNC_I2C2;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C3
|
||||
case 3:
|
||||
priv = &bl808_i2c3;
|
||||
gpio_attr |= GPIO_FUNC_I2C3;
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
i2cerr("Invalid port number\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
priv->refs++;
|
||||
if (priv->refs > 1)
|
||||
{
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return (struct i2c_master_s *)priv;
|
||||
}
|
||||
|
||||
/* Initialize GPIO */
|
||||
|
||||
bl808_configgpio(priv->scl_pin, gpio_attr);
|
||||
bl808_configgpio(priv->sda_pin, gpio_attr);
|
||||
|
||||
/* Enable interrupt */
|
||||
|
||||
int ret = irq_attach(priv->irq, i2c_interrupt, (void *)priv);
|
||||
if (ret == OK)
|
||||
{
|
||||
up_enable_irq(priv->irq);
|
||||
}
|
||||
else
|
||||
{
|
||||
i2cerr("Error attaching ISR\n");
|
||||
}
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
|
||||
return (struct i2c_master_s *)priv;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* De-initialize the selected I2C port.
|
||||
*
|
||||
* Input Parameter:
|
||||
* Device structure as returned by the i2c_i2cbus_initialize()
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, ERROR when internal reference count mismatch or dev
|
||||
* points to invalid hardware device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2cbus_uninitialize(struct i2c_master_s *dev)
|
||||
{
|
||||
struct bl808_i2c_s *priv = (struct bl808_i2c_s *)dev;
|
||||
|
||||
if (priv->refs == 0)
|
||||
{
|
||||
i2cerr("Attempt to deinit bus with no references\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
nxmutex_lock(&priv->lock);
|
||||
priv->refs--;
|
||||
if (priv->refs > 0)
|
||||
{
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
irq_detach(priv->irq);
|
||||
up_disable_irq(priv->irq);
|
||||
modifyreg32(BL808_I2C_INT_STS(priv->idx), 0,
|
||||
I2C_END_MASK
|
||||
| I2C_TX_FIFO_RDY_MASK
|
||||
| I2C_RX_FIFO_RDY_MASK
|
||||
| I2C_NAK_MASK
|
||||
| I2C_ARB_MASK
|
||||
| I2C_FIFO_ERROR_MASK);
|
||||
|
||||
nxmutex_unlock(&priv->lock);
|
||||
return OK;
|
||||
}
|
||||
|
||||
#endif
|
70
arch/risc-v/src/bl808/bl808_i2c.h
Normal file
70
arch/risc-v/src/bl808/bl808_i2c.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/****************************************************************************
|
||||
* arch/risc-v/src/bl808/bl808_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_RISC_V_SRC_BL808_BL808_I2C_H
|
||||
#define __ARCH_RISC_V_SRC_BL808_BL808_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_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 Parameter:
|
||||
* 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 *bl808_i2cbus_initialize(int port);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: bl808_i2cbus_uninitialize
|
||||
*
|
||||
* Description:
|
||||
* De-initialize the selected I2C port, and power down the device.
|
||||
*
|
||||
* Input Parameter:
|
||||
* Device structure as returned by the rp2040_i2cbus_initialize()
|
||||
*
|
||||
* Returned Value:
|
||||
* OK on success, ERROR when internal reference count mismatch or dev
|
||||
* points to invalid hardware device.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int bl808_i2cbus_uninitialize(struct i2c_master_s *dev);
|
||||
|
||||
#endif /* __ARCH_RISC_V_SRC_BL808_BL808_I2C_H */
|
|
@ -44,6 +44,35 @@
|
|||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: m0ic_mask_irq
|
||||
*
|
||||
* Description:
|
||||
* Masks or unmasks an interrupt in the M0 Interrupt Controller.
|
||||
*
|
||||
* Input parameters:
|
||||
* irq - IRQ number to mask or unmask
|
||||
* mask - 0 to unmask (enable), 1 to mask (disable)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void m0ic_mask_irq(int irq, bool mask)
|
||||
{
|
||||
int m0_extirq = irq - RISCV_IRQ_EXT
|
||||
- BL808_M0_IRQ_OFFSET - BL808_IRQ_NUM_BASE;
|
||||
|
||||
if (mask)
|
||||
{
|
||||
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
|
||||
0, 1 << (m0_extirq % 32));
|
||||
}
|
||||
else
|
||||
{
|
||||
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
|
||||
1 << (m0_extirq % 32), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: m0ic_interrupt
|
||||
*
|
||||
|
@ -84,6 +113,15 @@ static int __m0ic_interrupt(int irq, void *context, void *arg)
|
|||
putreg32(status_0, BL808_M0IC_CLEAR(0));
|
||||
putreg32(status_1, BL808_M0IC_CLEAR(1));
|
||||
|
||||
/* M0IC interrupts respond to the rising edge of the
|
||||
* source interrupts. If the source is held high but
|
||||
* the M0IC interrupt is cleared, the interrupt
|
||||
* never happens. So, use masks to refresh the interrupt.
|
||||
*/
|
||||
|
||||
m0ic_mask_irq(irqn, 1);
|
||||
m0ic_mask_irq(irqn, 0);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -192,9 +230,7 @@ void up_disable_irq(int irq)
|
|||
&& extirq <= (BL808_M0_MAX_EXTIRQ
|
||||
+ BL808_M0_IRQ_OFFSET))
|
||||
{
|
||||
int m0_extirq = extirq - BL808_M0_IRQ_OFFSET - BL808_IRQ_NUM_BASE;
|
||||
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
|
||||
0, 1 << (m0_extirq % 32));
|
||||
m0ic_mask_irq(irq, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -242,9 +278,7 @@ void up_enable_irq(int irq)
|
|||
&& extirq <= (BL808_M0_MAX_EXTIRQ
|
||||
+ BL808_M0_IRQ_OFFSET))
|
||||
{
|
||||
int m0_extirq = extirq - BL808_M0_IRQ_OFFSET - BL808_IRQ_NUM_BASE;
|
||||
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
|
||||
1 << (m0_extirq % 32), 0);
|
||||
m0ic_mask_irq(irq, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
|
||||
#define BL808_GLB_UART_CFG1_OFFSET 0x154
|
||||
#define BL808_GLB_UART_CFG2_OFFSET 0x158
|
||||
#define BL808_GLB_I2C_CFG0_OFFSET 0x180
|
||||
#define BL808_GLB_SPI_CFG0_OFFSET 0x1b0
|
||||
#define BL808_GLB_PARM_CFG0_OFFSET 0x510
|
||||
|
||||
|
@ -47,6 +48,7 @@
|
|||
|
||||
#define BL808_GLB_UART_CFG1 (BL808_GLB_BASE + BL808_GLB_UART_CFG1_OFFSET)
|
||||
#define BL808_GLB_UART_CFG2 (BL808_GLB_BASE + BL808_GLB_UART_CFG2_OFFSET)
|
||||
#define BL808_GLB_I2C_CFG0 (BL808_GLB_BASE + BL808_GLB_I2C_CFG0_OFFSET)
|
||||
#define BL808_GLB_SPI_CFG0 (BL808_GLB_BASE + BL808_GLB_SPI_CFG0_OFFSET)
|
||||
#define BL808_GLB_PARM_CFG0 (BL808_GLB_BASE + BL808_GLB_PARM_CFG0_OFFSET)
|
||||
|
||||
|
@ -59,6 +61,13 @@
|
|||
#define UART_CFG_SIG_SEL_SHIFT(n) ((n % 8) * 4)
|
||||
#define UART_CFG_SIG_SEL_MASK(n) (0x0f << UART_CFG_SIG_SEL_SHIFT(n))
|
||||
|
||||
/* I2C_CFG0 *****************************************************************/
|
||||
|
||||
#define I2C_CFG_CLK_DIV_SHIFT 16
|
||||
#define I2C_CFG_CLK_DIV_MASK (0xff << I2C_CFG_CLK_DIV_SHIFT)
|
||||
#define I2C_CFG_CLK_EN (1 << 24)
|
||||
#define I2C_CFG_CLK_XTAL (1 << 25)
|
||||
|
||||
/* SPI_CFG0 *****************************************************************/
|
||||
|
||||
#define SPI_CFG_CLK_DIV_SHIFT 0
|
||||
|
|
117
arch/risc-v/src/bl808/hardware/bl808_i2c.h
Normal file
117
arch/risc-v/src/bl808/hardware/bl808_i2c.h
Normal file
|
@ -0,0 +1,117 @@
|
|||
/****************************************************************************
|
||||
* arch/risc-v/src/bl808/hardware/bl808_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_RISCV_SRC_BL808_HARDWARE_BL808_I2C_H
|
||||
#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_I2C_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include "bl808_memorymap.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define BL808_I2C_BASE(n) (((n) == 0) ? BL808_I2C0_BASE \
|
||||
: ((n) == 1) ? BL808_I2C1_BASE \
|
||||
: ((n) == 2) ? BL808_I2C2_BASE \
|
||||
: BL808_I2C3_BASE)
|
||||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define BL808_I2C_CONFIG_OFFSET 0x00
|
||||
#define BL808_I2C_INT_STS_OFFSET 0x04
|
||||
#define BL808_I2C_SUB_ADDR_OFFSET 0x08
|
||||
#define BL808_I2C_BUSY_OFFSET 0x0c
|
||||
#define BL808_I2C_PRD_START_OFFSET 0x10
|
||||
#define BL808_I2C_PRD_STOP_OFFSET 0x14
|
||||
#define BL808_I2C_PRD_DATA_OFFSET 0x18
|
||||
#define BL808_I2C_FIFO_CONFIG_0_OFFSET 0x80
|
||||
#define BL808_I2C_FIFO_CONFIG_1_OFFSET 0x84
|
||||
#define BL808_I2C_WDATA_OFFSET 0x88
|
||||
#define BL808_I2C_RDATA_OFFSET 0X8c
|
||||
|
||||
/* Register definitions *****************************************************/
|
||||
|
||||
#define BL808_I2C_CONFIG(n) (BL808_I2C_BASE(n) + BL808_I2C_CONFIG_OFFSET)
|
||||
#define BL808_I2C_INT_STS(n) (BL808_I2C_BASE(n) + BL808_I2C_INT_STS_OFFSET)
|
||||
#define BL808_I2C_SUB_ADDR(n) (BL808_I2C_BASE(n) + BL808_I2C_SUB_ADDR_OFFSET)
|
||||
#define BL808_I2C_BUSY(n) (BL808_I2C_BASE(n) + BL808_I2C_BUSY_OFFSET)
|
||||
#define BL808_I2C_PRD_START(n) (BL808_I2C_BASE(n) + BL808_I2C_PRD_START_OFFSET)
|
||||
#define BL808_I2C_PRD_STOP(n) (BL808_I2C_BASE(n) + BL808_I2C_PRD_STOP_OFFSET)
|
||||
#define BL808_I2C_PRD_DATA(n) (BL808_I2C_BASE(n) + BL808_I2C_PRD_DATA_OFFSET)
|
||||
#define BL808_I2C_FIFO_CONFIG_0(n) (BL808_I2C_BASE(n) + BL808_I2C_FIFO_CONFIG_0_OFFSET)
|
||||
#define BL808_I2C_FIFO_CONFIG_1(n) (BL808_I2C_BASE(n) + BL808_I2C_FIFO_CONFIG_1_OFFSET)
|
||||
#define BL808_I2C_WDATA(n) (BL808_I2C_BASE(n) + BL808_I2C_WDATA_OFFSET)
|
||||
#define BL808_I2C_RDATA(n) (BL808_I2C_BASE(n) + BL808_I2C_RDATA_OFFSET)
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
/* I2C_CONFIG */
|
||||
|
||||
#define I2C_M_EN (1 << 0)
|
||||
#define I2C_DIR_R (1 << 1)
|
||||
#define I2C_SUB_ADDR_EN (1 << 4)
|
||||
#define I2C_SUB_ADDR_LEN_SHIFT (5)
|
||||
#define I2C_SUB_ADDR_LEN_MASK (0x3 << I2C_SUB_ADDR_LEN_SHIFT)
|
||||
#define I2C_10B_ADDR_EN (1 << 7)
|
||||
#define I2C_SLV_ADDR_SHIFT (8)
|
||||
#define I2C_SLV_ADDR_MASK (0x3ff << I2C_SLV_ADDR_SHIFT)
|
||||
#define I2C_PKT_LEN_SHIFT (20)
|
||||
#define I2C_PKT_LEN_MASK (0xff << I2C_PKT_LEN_SHIFT)
|
||||
|
||||
/* I2C_INT_STS */
|
||||
|
||||
#define I2C_END_INT (1 << 0)
|
||||
#define I2C_TX_FIFO_RDY_INT (1 << 1)
|
||||
#define I2C_RX_FIFO_RDY_INT (1 << 2)
|
||||
#define I2C_NAK_INT (1 << 3)
|
||||
#define I2C_ARB_INT (1 << 4)
|
||||
#define I2C_FIFO_ERROR_INT (1 << 5)
|
||||
#define I2C_END_MASK (1 << 8)
|
||||
#define I2C_TX_FIFO_RDY_MASK (1 << 9)
|
||||
#define I2C_RX_FIFO_RDY_MASK (1 << 10)
|
||||
#define I2C_NAK_MASK (1 << 11)
|
||||
#define I2C_ARB_MASK (1 << 12)
|
||||
#define I2C_FIFO_ERROR_MASK (1 << 13)
|
||||
#define I2C_END_CLR (1 << 16)
|
||||
#define I2C_NAK_CLR (1 << 19)
|
||||
#define I2C_ARB_CLR (1 << 20)
|
||||
|
||||
/* I2C_PRD_x */
|
||||
|
||||
#define I2C_PRD_PH0_SHIFT (0)
|
||||
#define I2C_PRD_PH0_MASK (0xff << I2C_PRD_PH0_SHIFT)
|
||||
#define I2C_PRD_PH1_SHIFT (8)
|
||||
#define I2C_PRD_PH1_MASK (0xff << I2C_PRD_PH1_SHIFT)
|
||||
#define I2C_PRD_PH2_SHIFT (16)
|
||||
#define I2C_PRD_PH2_MASK (0xff << I2C_PRD_PH2_SHIFT)
|
||||
#define I2C_PRD_PH3_SHIFT (24)
|
||||
#define I2C_PRD_PH3_MASK (0xff << I2C_PRD_PH3_SHIFT)
|
||||
|
||||
/* I2C_FIFO_CONFIG_0 */
|
||||
|
||||
#define TX_FIFO_CLR (1 << 2)
|
||||
#define RX_FIFO_CLR (1 << 3)
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_I2C_H */
|
|
@ -36,10 +36,14 @@
|
|||
#define BL808_UART0_BASE 0x2000a000ul
|
||||
#define BL808_UART1_BASE 0x2000a100ul
|
||||
#define BL808_SPI0_BASE 0x2000a200ul
|
||||
#define BL808_I2C0_BASE 0x2000a300ul
|
||||
#define BL808_TIMER0_BASE 0x2000a500ul
|
||||
#define BL808_I2C1_BASE 0x2000a900ul
|
||||
#define BL808_UART2_BASE 0x2000aa00ul
|
||||
#define BL808_AON_BASE 0x2000f000ul
|
||||
#define BL808_UART3_BASE 0x30002000ul
|
||||
#define BL808_I2C2_BASE 0x30003000ul
|
||||
#define BL808_I2C3_BASE 0x30004000ul
|
||||
#define BL808_MM_GLB_BASE 0x30007000ul
|
||||
#define BL808_SPI1_BASE 0x30008000ul
|
||||
#define BL808_TIMER1_BASE 0x30009000ul
|
||||
|
|
|
@ -36,20 +36,31 @@
|
|||
|
||||
/* Register offsets *********************************************************/
|
||||
|
||||
#define BL808_MM_GLB_CLK_CTRL_CPU_OFFSET 0x00
|
||||
#define BL808_MM_GLB_CLK_CTRL_PERI_OFFSET 0x10
|
||||
#define BL808_MM_GLB_CLK_CTRL_PERI3_OFFSET 0x18
|
||||
|
||||
/* Register definitions *****************************************************/
|
||||
|
||||
#define BL808_MM_GLB_CLK_CTRL_CPU (BL808_MM_GLB_BASE \
|
||||
+ BL808_MM_GLB_CLK_CTRL_CPU_OFFSET)
|
||||
#define BL808_MM_GLB_CLK_CTRL_PERI (BL808_MM_GLB_BASE \
|
||||
+ BL808_MM_GLB_CLK_CTRL_PERI_OFFSET)
|
||||
#define BL808_MM_GLB_CLK_CTRL_PERI3 (BL808_MM_GLB_BASE \
|
||||
+ BL808_MM_GLB_CLK_CTRL_PERI3_OFFSET)
|
||||
|
||||
/* Register bit definitions *************************************************/
|
||||
|
||||
/* CLK_CTRL_CPU */
|
||||
|
||||
#define CLK_CTRL_CPU_I2C_CLK_XTAL (1 << 6)
|
||||
|
||||
/* CLK_CTRL_PERI ************************************************************/
|
||||
|
||||
#define CLK_CTRL_PERI_I2C0_DIV_SHIFT 0
|
||||
#define CLK_CTRL_PERI_I2C0_DIV_MASK (0xff << CLK_CTRL_PERI_I2C0_DIV_SHIFT)
|
||||
#define CLK_CTRL_PERI_I2C0_EN_SHIFT 9
|
||||
#define CLK_CTRL_PERI_I2C0_DIV_EN (1 << 8)
|
||||
#define CLK_CTRL_PERI_I2C0_EN (1 << 9)
|
||||
#define CLK_CTRL_PERI_UART_DIV_EN_SHIFT 16
|
||||
#define CLK_CTRL_PERI_UART_DIV_SHIFT 17
|
||||
#define CLK_CTRL_PERI_UART_DIV_MASK (0x07 << CLK_CTRL_PERI_UART_DIV_SHIFT)
|
||||
|
@ -57,4 +68,11 @@
|
|||
#define CLK_CTRL_PERI_SPI_DIV_SHIFT 24
|
||||
#define CLK_CTRL_PERI_SPI_DIV_MASK (0xff << CLK_CTRL_PERI_SPI_DIV_SHIFT)
|
||||
|
||||
/* CLK_CTRL_PERI3 ***********************************************************/
|
||||
|
||||
#define CLK_CTRL_PERI_I2C1_DIV_SHIFT 0
|
||||
#define CLK_CTRL_PERI_I2C1_DIV_MASK (0xff << CLK_CTRL_PERI_I2C0_DIV_SHIFT)
|
||||
#define CLK_CTRL_PERI_I2C1_DIV_EN (1 << 8)
|
||||
#define CLK_CTRL_PERI_I2C1_EN (1 << 9)
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H */
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
#ifdef CONFIG_USERLED
|
||||
#include <nuttx/leds/userled.h>
|
||||
#endif
|
||||
#if defined(CONFIG_BL808_I2C0) || defined(CONFIG_BL808_I2C1) \
|
||||
|| defined(CONFIG_BL808_I2C2) || defined(CONFIG_BL808_I2C3)
|
||||
#include "bl808_i2c.h"
|
||||
#endif
|
||||
#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
|
||||
#include "bl808_spi.h"
|
||||
#endif
|
||||
|
@ -179,6 +183,26 @@ void board_late_initialize(void)
|
|||
bl808_gpadc_init();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C0
|
||||
struct i2c_master_s *i2c0 = bl808_i2cbus_initialize(0);
|
||||
i2c_register(i2c0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C1
|
||||
struct i2c_master_s *i2c1 = bl808_i2cbus_initialize(1);
|
||||
i2c_register(i2c1, 1);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C2
|
||||
struct i2c_master_s *i2c2 = bl808_i2cbus_initialize(2);
|
||||
i2c_register(i2c2, 2);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_I2C3
|
||||
struct i2c_master_s *i2c3 = bl808_i2cbus_initialize(3);
|
||||
i2c_register(i2c3, 3);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BL808_SPI0
|
||||
struct spi_dev_s *spi0 = bl808_spibus_initialize(0);
|
||||
spi_register(spi0, 0);
|
||||
|
|
Loading…
Reference in a new issue