diff --git a/Documentation/platforms/risc-v/bl808/index.rst b/Documentation/platforms/risc-v/bl808/index.rst index dfb9b3c981..97c97aef9b 100644 --- a/Documentation/platforms/risc-v/bl808/index.rst +++ b/Documentation/platforms/risc-v/bl808/index.rst @@ -48,7 +48,7 @@ DMA No EMAC No GPADC Yes GPIO Yes -I2C No +I2C Yes I2S No PWM No SPI Yes diff --git a/arch/risc-v/include/bl808/irq.h b/arch/risc-v/include/bl808/irq.h index 3c0dbbdb84..16af49b973 100644 --- a/arch/risc-v/include/bl808/irq.h +++ b/arch/risc-v/include/bl808/irq.h @@ -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 */ diff --git a/arch/risc-v/src/bl808/Kconfig b/arch/risc-v/src/bl808/Kconfig index d23cb0e060..dcf06528e5 100644 --- a/arch/risc-v/src/bl808/Kconfig +++ b/arch/risc-v/src/bl808/Kconfig @@ -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 diff --git a/arch/risc-v/src/bl808/Make.defs b/arch/risc-v/src/bl808/Make.defs index d81c3781c9..8f42b6d084 100644 --- a/arch/risc-v/src/bl808/Make.defs +++ b/arch/risc-v/src/bl808/Make.defs @@ -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 diff --git a/arch/risc-v/src/bl808/bl808_gpio.h b/arch/risc-v/src/bl808/bl808_gpio.h index eab60845cd..f3e618076e 100644 --- a/arch/risc-v/src/bl808/bl808_gpio.h +++ b/arch/risc-v/src/bl808/bl808_gpio.h @@ -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 */ /**************************************************************************** diff --git a/arch/risc-v/src/bl808/bl808_i2c.c b/arch/risc-v/src/bl808/bl808_i2c.c new file mode 100644 index 0000000000..1b7feaef7d --- /dev/null +++ b/arch/risc-v/src/bl808/bl808_i2c.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 diff --git a/arch/risc-v/src/bl808/bl808_i2c.h b/arch/risc-v/src/bl808/bl808_i2c.h new file mode 100644 index 0000000000..3315f80e93 --- /dev/null +++ b/arch/risc-v/src/bl808/bl808_i2c.h @@ -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 + +/**************************************************************************** + * 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 */ diff --git a/arch/risc-v/src/bl808/bl808_irq.c b/arch/risc-v/src/bl808/bl808_irq.c index af32ea6c18..2d9a775548 100644 --- a/arch/risc-v/src/bl808/bl808_irq.c +++ b/arch/risc-v/src/bl808/bl808_irq.c @@ -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 { diff --git a/arch/risc-v/src/bl808/hardware/bl808_glb.h b/arch/risc-v/src/bl808/hardware/bl808_glb.h index 2808bb8744..69eb7bfd96 100644 --- a/arch/risc-v/src/bl808/hardware/bl808_glb.h +++ b/arch/risc-v/src/bl808/hardware/bl808_glb.h @@ -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 diff --git a/arch/risc-v/src/bl808/hardware/bl808_i2c.h b/arch/risc-v/src/bl808/hardware/bl808_i2c.h new file mode 100644 index 0000000000..619f74d874 --- /dev/null +++ b/arch/risc-v/src/bl808/hardware/bl808_i2c.h @@ -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 +#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 */ diff --git a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h index c3bc204493..ed46e7931e 100644 --- a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h +++ b/arch/risc-v/src/bl808/hardware/bl808_memorymap.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 diff --git a/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h index 226b44cc7a..604d095129 100644 --- a/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h +++ b/arch/risc-v/src/bl808/hardware/bl808_mm_glb.h @@ -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 */ diff --git a/boards/risc-v/bl808/ox64/src/bl808_appinit.c b/boards/risc-v/bl808/ox64/src/bl808_appinit.c index 0f99a265cf..db444784d5 100644 --- a/boards/risc-v/bl808/ox64/src/bl808_appinit.c +++ b/boards/risc-v/bl808/ox64/src/bl808_appinit.c @@ -40,6 +40,10 @@ #ifdef CONFIG_USERLED #include #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);