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:
Henry Rovner 2024-08-02 07:24:12 -07:00 committed by Xiang Xiao
parent 41c0fc01b9
commit 923dc37a3b
13 changed files with 1234 additions and 10 deletions

View file

@ -48,7 +48,7 @@ DMA No
EMAC No EMAC No
GPADC Yes GPADC Yes
GPIO Yes GPIO Yes
I2C No I2C Yes
I2S No I2S No
PWM No PWM No
SPI Yes SPI Yes

View file

@ -54,6 +54,8 @@
/* D0 IRQs ******************************************************************/ /* D0 IRQs ******************************************************************/
#define BL808_IRQ_UART3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 4) #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_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_D0_IPC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 38)
#define BL808_IRQ_TIMER1_CH0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 61) #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_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_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_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_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_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_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 */ #endif /* __ARCH_RISCV_INCLUDE_BL808_IRQ_H */

View file

@ -106,6 +106,98 @@ config BL808_GPADC_SCAN_ORD11
endmenu 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 config BL808_UART0
bool "UART 0" bool "UART 0"
default n default n

View file

@ -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_timerisr.c bl808_allocateheap.c
CHIP_CSRCS += bl808_gpio.c bl808_mm_init.c bl808_pgalloc.c bl808_serial.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_gpadc.c bl808_spi.c bl808_timer.c bl808_wdt.c
CHIP_CSRCS += bl808_i2c.c

View file

@ -58,8 +58,8 @@
#define GPIO_MODE_SHIFT (10) /* Bit 10: Port Mode */ #define GPIO_MODE_SHIFT (10) /* Bit 10: Port Mode */
#define GPIO_MODE_MASK (1 << GPIO_MODE_SHIFT) #define GPIO_MODE_MASK (1 << GPIO_MODE_SHIFT)
# define GPIO_INPUT (1 << GPIO_MODE_SHIFT) /* Input Enable */ #define GPIO_INPUT (1 << GPIO_MODE_SHIFT) /* Input Enable */
# define GPIO_OUTPUT (0 << GPIO_MODE_SHIFT) /* Output Enable */ #define GPIO_OUTPUT (0 << GPIO_MODE_SHIFT) /* Output Enable */
/* Input/Output pull-ups/downs: /* Input/Output pull-ups/downs:
* *
@ -116,6 +116,7 @@
#define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) /* SDH */ #define GPIO_FUNC_SDH (0 << GPIO_FUNC_SHIFT) /* SDH */
#define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) /* SPI0 */ #define GPIO_FUNC_SPI0 (1 << GPIO_FUNC_SHIFT) /* SPI0 */
#define GPIO_FUNC_FLASH (2 << GPIO_FUNC_SHIFT) /* Flash */ #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_I2C1 (6 << GPIO_FUNC_SHIFT) /* I2C1 */
#define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) /* UART */ #define GPIO_FUNC_UART (7 << GPIO_FUNC_SHIFT) /* UART */
#define GPIO_FUNC_CAM (9 << GPIO_FUNC_SHIFT) /* CSI */ #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_SWGPIO (11 << GPIO_FUNC_SHIFT) /* Software GPIO */
#define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) /* PWM0 */ #define GPIO_FUNC_PWM0 (16 << GPIO_FUNC_SHIFT) /* PWM0 */
#define GPIO_FUNC_SPI1 (18 << GPIO_FUNC_SHIFT) /* SPI1 */ #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 */ #define GPIO_FUNC_JTAG_D0 (27 << GPIO_FUNC_SHIFT) /* JTAG */
/**************************************************************************** /****************************************************************************

View 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

View 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 */

View file

@ -44,6 +44,35 @@
* Private Functions * 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 * 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_0, BL808_M0IC_CLEAR(0));
putreg32(status_1, BL808_M0IC_CLEAR(1)); 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; return OK;
} }
@ -192,9 +230,7 @@ void up_disable_irq(int irq)
&& extirq <= (BL808_M0_MAX_EXTIRQ && extirq <= (BL808_M0_MAX_EXTIRQ
+ BL808_M0_IRQ_OFFSET)) + BL808_M0_IRQ_OFFSET))
{ {
int m0_extirq = extirq - BL808_M0_IRQ_OFFSET - BL808_IRQ_NUM_BASE; m0ic_mask_irq(irq, 1);
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
0, 1 << (m0_extirq % 32));
} }
else else
{ {
@ -242,9 +278,7 @@ void up_enable_irq(int irq)
&& extirq <= (BL808_M0_MAX_EXTIRQ && extirq <= (BL808_M0_MAX_EXTIRQ
+ BL808_M0_IRQ_OFFSET)) + BL808_M0_IRQ_OFFSET))
{ {
int m0_extirq = extirq - BL808_M0_IRQ_OFFSET - BL808_IRQ_NUM_BASE; m0ic_mask_irq(irq, 0);
modifyreg32(BL808_M0IC_MASK(m0_extirq / 32),
1 << (m0_extirq % 32), 0);
} }
else else
{ {

View file

@ -38,6 +38,7 @@
#define BL808_GLB_UART_CFG1_OFFSET 0x154 #define BL808_GLB_UART_CFG1_OFFSET 0x154
#define BL808_GLB_UART_CFG2_OFFSET 0x158 #define BL808_GLB_UART_CFG2_OFFSET 0x158
#define BL808_GLB_I2C_CFG0_OFFSET 0x180
#define BL808_GLB_SPI_CFG0_OFFSET 0x1b0 #define BL808_GLB_SPI_CFG0_OFFSET 0x1b0
#define BL808_GLB_PARM_CFG0_OFFSET 0x510 #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_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_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_SPI_CFG0 (BL808_GLB_BASE + BL808_GLB_SPI_CFG0_OFFSET)
#define BL808_GLB_PARM_CFG0 (BL808_GLB_BASE + BL808_GLB_PARM_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_SHIFT(n) ((n % 8) * 4)
#define UART_CFG_SIG_SEL_MASK(n) (0x0f << UART_CFG_SIG_SEL_SHIFT(n)) #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 *****************************************************************/ /* SPI_CFG0 *****************************************************************/
#define SPI_CFG_CLK_DIV_SHIFT 0 #define SPI_CFG_CLK_DIV_SHIFT 0

View 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 */

View file

@ -36,10 +36,14 @@
#define BL808_UART0_BASE 0x2000a000ul #define BL808_UART0_BASE 0x2000a000ul
#define BL808_UART1_BASE 0x2000a100ul #define BL808_UART1_BASE 0x2000a100ul
#define BL808_SPI0_BASE 0x2000a200ul #define BL808_SPI0_BASE 0x2000a200ul
#define BL808_I2C0_BASE 0x2000a300ul
#define BL808_TIMER0_BASE 0x2000a500ul #define BL808_TIMER0_BASE 0x2000a500ul
#define BL808_I2C1_BASE 0x2000a900ul
#define BL808_UART2_BASE 0x2000aa00ul #define BL808_UART2_BASE 0x2000aa00ul
#define BL808_AON_BASE 0x2000f000ul #define BL808_AON_BASE 0x2000f000ul
#define BL808_UART3_BASE 0x30002000ul #define BL808_UART3_BASE 0x30002000ul
#define BL808_I2C2_BASE 0x30003000ul
#define BL808_I2C3_BASE 0x30004000ul
#define BL808_MM_GLB_BASE 0x30007000ul #define BL808_MM_GLB_BASE 0x30007000ul
#define BL808_SPI1_BASE 0x30008000ul #define BL808_SPI1_BASE 0x30008000ul
#define BL808_TIMER1_BASE 0x30009000ul #define BL808_TIMER1_BASE 0x30009000ul

View file

@ -36,20 +36,31 @@
/* Register offsets *********************************************************/ /* 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_PERI_OFFSET 0x10
#define BL808_MM_GLB_CLK_CTRL_PERI3_OFFSET 0x18
/* Register definitions *****************************************************/ /* 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 \ #define BL808_MM_GLB_CLK_CTRL_PERI (BL808_MM_GLB_BASE \
+ BL808_MM_GLB_CLK_CTRL_PERI_OFFSET) + 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 *************************************************/ /* Register bit definitions *************************************************/
/* CLK_CTRL_CPU */
#define CLK_CTRL_CPU_I2C_CLK_XTAL (1 << 6)
/* CLK_CTRL_PERI ************************************************************/ /* CLK_CTRL_PERI ************************************************************/
#define CLK_CTRL_PERI_I2C0_DIV_SHIFT 0 #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_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_EN_SHIFT 16
#define CLK_CTRL_PERI_UART_DIV_SHIFT 17 #define CLK_CTRL_PERI_UART_DIV_SHIFT 17
#define CLK_CTRL_PERI_UART_DIV_MASK (0x07 << CLK_CTRL_PERI_UART_DIV_SHIFT) #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_SHIFT 24
#define CLK_CTRL_PERI_SPI_DIV_MASK (0xff << CLK_CTRL_PERI_SPI_DIV_SHIFT) #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 */ #endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MM_GLB_H */

View file

@ -40,6 +40,10 @@
#ifdef CONFIG_USERLED #ifdef CONFIG_USERLED
#include <nuttx/leds/userled.h> #include <nuttx/leds/userled.h>
#endif #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) #if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
#include "bl808_spi.h" #include "bl808_spi.h"
#endif #endif
@ -179,6 +183,26 @@ void board_late_initialize(void)
bl808_gpadc_init(); bl808_gpadc_init();
#endif #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 #ifdef CONFIG_BL808_SPI0
struct spi_dev_s *spi0 = bl808_spibus_initialize(0); struct spi_dev_s *spi0 = bl808_spibus_initialize(0);
spi_register(spi0, 0); spi_register(spi0, 0);