diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/include b/Software/BSP/e907_rtos/rtos-hal/hal/include deleted file mode 120000 index f5030fe8..00000000 --- a/Software/BSP/e907_rtos/rtos-hal/hal/include +++ /dev/null @@ -1 +0,0 @@ -../include \ No newline at end of file diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/source/Makefile index b7d01eed..ccf237b0 100644 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/Makefile +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/Makefile @@ -1,9 +1,11 @@ obj-$(CONFIG_DRIVERS_CCMU) += ccmu/ obj-$(CONFIG_DRIVERS_UART) += uart/ obj-$(CONFIG_DRIVERS_RTC) += rtc/ +obj-$(CONFIG_DRIVERS_SPI) += spi/ obj-$(CONFIG_DRIVERS_GPIO) += gpio/ obj-$(CONFIG_DRIVERS_DMA) += dma/ obj-$(CONFIG_DRIVERS_TWI) += twi/ obj-$(CONFIG_DRIVERS_PWM) += pwm/ +obj-$(CONFIG_DRIVERS_GPADC) += gpadc/ obj-$(CONFIG_DRIVERS_MSGBOX) += msgbox/ -obj-y += common/ \ No newline at end of file +obj-y += common/ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/common_ccmu.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/common_ccmu.h index ad118b13..265a6284 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/common_ccmu.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/common_ccmu.h @@ -81,6 +81,7 @@ typedef enum #if defined(CONFIG_DRIVERS_SUNXI_CLK) #define HAL_SUNXI_CCU (0) +#define HAL_SUNXI_FIXED_CCU (1) #include "sunxi/clk.h" typedef hal_clk_id_t hal_clk_t; diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/clk.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/clk.c index f991c902..650e0a94 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/clk.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/clk.c @@ -523,10 +523,11 @@ hal_clk_status_t sunxi_clk_get_rate(hal_clk_id_t clk, u32 *rate) hal_clk_status_t sunxi_clk_set_rate(hal_clk_id_t clk, u32 rate) { - u32 i, parent_rate; + u32 i; clk_core_pt pclk = NULL; clk_periph_pt periph_clk = NULL; clk_factor_pt factor_clk = NULL; + clk_core_pt parent_clk_core = NULL; hal_clk_status_t ret = HAL_CLK_STATUS_ERROR_CLK_NOT_FOUND; CCMU_TRACE(); @@ -550,8 +551,10 @@ hal_clk_status_t sunxi_clk_set_rate(hal_clk_id_t clk, u32 rate) { return HAL_CLK_STATUS_OK; } - parent_rate = periph_clk->clk_core.parent_rate; - ret = sunxi_clk_periph_set_rate(periph_clk, rate); + parent_clk_core = clk_get_core(periph_clk->clk_core.current_parent); + periph_clk->clk_core.parent_rate = parent_clk_core->clk_rate; + + ret = sunxi_clk_periph_set_rate(periph_clk, rate); if (ret == HAL_CLK_STATUS_OK) { periph_clk->clk_core.clk_rate = rate; diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/platform_clk.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/platform_clk.h index 4c092917..ffeba4b9 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/platform_clk.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/platform_clk.h @@ -70,6 +70,11 @@ enum HAL_CLK_PLL_AUDIOX2, HAL_CLK_PLL_AUDIOX4, HAL_CLK_PLL_DDRDIV4, + HAL_HOSC_DIV32, + HAL_HOSC_DIV16, + HAL_HOSC_DIV8, + HAL_HOSC_DIV4, + HAL_HOSC_DIV2, HAL_CLK_PLL_NPUX2, HAL_CLK_PLL_NPU, HAL_CLK_HOSCD2, @@ -359,6 +364,7 @@ enum HAL_CLK_PLL_CVE, HAL_CLK_PLL_ISE, HAL_CLK_PLL_CSI, + HAL_CLK_PLL_CSIX4, /* PERIPH MODULE CLOCK 1024~2047 diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.c index 0142a9e1..568160ac 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.c @@ -547,6 +547,7 @@ PLLVIDEO0(98, 1, 1188000000U), /* PLL_CSI(n, d1, freq) F_N8X8_D1V1X1 */ struct sunxi_clk_factor_freq factor_pllcsix4_tbl[] = { PLLCSI(98, 1, 1188000000U), +PLLCSI(98, 0, 2376000000U), }; /* PLLAUDIO(n, p, d1, d2, freq) F_N8X8_P16X6_D1V1X1_D2V0X1 */ @@ -591,11 +592,17 @@ SUNXI_CLK_FIXED_FACTOR(pll_npu, HAL_CLK_PLL_NPU, HAL_CLK_PLL_NPUX4, HAL_CLK_FACT SUNXI_CLK_FIXED_FACTOR(hoscd2, HAL_CLK_HOSCD2, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 2); SUNXI_CLK_FIXED_FACTOR(osc48md4, HAL_CLK_OSC48MD4, HAL_CLK_SRC_OSC48M, HAL_CLK_FACTOR, 1, 4); SUNXI_CLK_FIXED_FACTOR(sdramd4, HAL_CLK_SDRAMD4, HAL_CLK_PERIPH_SDRAM, HAL_CLK_FACTOR, 1, 4); +SUNXI_CLK_FIXED_FACTOR(hosc_div32, HAL_HOSC_DIV32, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 32); +SUNXI_CLK_FIXED_FACTOR(hosc_div16, HAL_HOSC_DIV16, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 16); +SUNXI_CLK_FIXED_FACTOR(hosc_div8, HAL_HOSC_DIV8, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 8); +SUNXI_CLK_FIXED_FACTOR(hosc_div4, HAL_HOSC_DIV4, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 4); +SUNXI_CLK_FIXED_FACTOR(hosc_div2, HAL_HOSC_DIV2, HAL_CLK_SRC_HOSC, HAL_CLK_FACTOR, 1, 2); + /* name, ns nw ks kw ms mw ps pw d1s d1w d2s d2w {frac out mode} en-s sdmss sdmsw sdmpat sdmval mux_in-s out_en-s*/ SUNXI_CLK_FACTORS_CONFIG(pll_cpu, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, 0, 0, 0, 23, 27); SUNXI_CLK_FACTORS_CONFIG(pll_ddr0, 8, 8, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 31, 24, 1, CLK_PLL_DDRPAT, 0xd1303333, 23, 27); -SUNXI_CLK_FACTORS_CONFIG(pll_periph0x2, 8, 8, 0, 0, 1, 1, 0, 0, 16, 3, 0, 0, 0, 0, 0, 31, 24, 1, CLK_PLL_PERI0PAT0, 0xd1303333, 23, 27); +SUNXI_CLK_FACTORS_CONFIG(pll_periph0x2, 8, 8, 0, 0, 1, 1, 0, 0, 16, 3, 0, 0, 0, 0, 0, 31, 24, 0, CLK_PLL_PERI0PAT0, 0xd1303333, 23, 27); SUNXI_CLK_FACTORS_CONFIG(pll_periph0800m, 8, 8, 0, 0, 1, 1, 0, 0, 20, 3, 0, 0, 0, 0, 0, 31, 24, 1, CLK_PLL_PERI0PAT0, 0xd1303333, 23, 27); SUNXI_CLK_FACTORS_CONFIG(pll_periph0480m, 8, 8, 0, 0, 1, 1, 0, 0, 2, 3, 0, 0, 0, 0, 0, 31, 24, 1, CLK_PLL_PERI0PAT0, 0xd1303333, 23, 27); SUNXI_CLK_FACTORS_CONFIG(pll_video0x4, 8, 8, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 31, 24, 1, CLK_PLL_VIDEO0PAT0, 0xd1303333, 23, 27); @@ -662,6 +669,7 @@ hal_clk_id_t fanout12m_parents[] = {HAL_CLK_HOSCD2}; hal_clk_id_t fanout24m_parents[] = {HAL_CLK_SRC_HOSC}; hal_clk_id_t fanout27m_parents[] = {HAL_CLK_PLL_AUDIO, HAL_CLK_PLL_CSI, HAL_CLK_PLL_PERI0300M}; hal_clk_id_t fanout_pclk_parents[] = {HAL_CLK_BUS_APB0}; +hal_clk_id_t gpadc_parents[] = {HAL_HOSC_DIV32, HAL_HOSC_DIV16, HAL_HOSC_DIV8, HAL_HOSC_DIV4, HAL_HOSC_DIV2, HAL_CLK_SRC_HOSC}; hal_clk_id_t fanout012_parents[] = {HAL_CLK_SRC_LOSC_OUT, HAL_CLK_PERIPH_FANOUT_12M, HAL_CLK_PERIPH_FANOUT_16M, HAL_CLK_PERIPH_FANOUT_24M, HAL_CLK_PERIPH_FANOUT_25M, HAL_CLK_PERIPH_FANOUT_27M, HAL_CLK_PERIPH_FANOUT_PCLK}; hal_clk_id_t ahbmod_parents[] = {HAL_CLK_BUS_AHB}; @@ -726,7 +734,7 @@ SUNXI_CLK_PERIPH_CONFIG(spi3, CLK_SPI3_CFG, 24, 3, SUNXI_CLK_PERIPH_CONFIG(spif, CLK_SPIF_CFG, 24, 3, CLK_SPIF_CFG, 0, 4, 8, 2, 0, CLK_SPI3_CFG, CLK_SPI_GATE, CLK_SPI_GATE, 0, 31, 20, 4, 0, NULL, 0); SUNXI_CLK_PERIPH_CONFIG(gmac_25m, 0, 0, 0, 0, 0, 0, 0, 0, 0, CLK_GMAC25M_CFG, 0, CLK_GMAC25M_CFG, 0, 31, 0, 30, 0, NULL, 0); SUNXI_CLK_PERIPH_CONFIG(gmac, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CLK_GMAC_GATE, CLK_GMAC_GATE, 0, 0, 16, 0, 0, NULL, 0); -SUNXI_CLK_PERIPH_CONFIG(gpadc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CLK_GPADC_GATE, CLK_GPADC_GATE, 0, 0, 16, 0, 0, NULL, 0); +SUNXI_CLK_PERIPH_CONFIG(gpadc, CLK_GPADC_SEL, 22, 3, 0, 0, 0, 0, 0, 0, 0, CLK_GPADC_GATE, CLK_GPADC_GATE, 0, 0, 16, 0, 0, NULL, 0); SUNXI_CLK_PERIPH_CONFIG(ths, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, CLK_THS_GATE, CLK_THS_GATE, 0, 0, 16, 0, 0, NULL, 0); SUNXI_CLK_PERIPH_CONFIG(pll_audiox4, 0, 0, 0, CLK_PLL_PRE_CFG, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0); SUNXI_CLK_PERIPH_CONFIG(pll_audio, 0, 0, 0, CLK_PLL_PRE_CFG, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, 0); @@ -809,7 +817,7 @@ SUNXI_CLK_PERIPH(spi3, HAL_CLK_PERIPH_SPI3, spi_parents); SUNXI_CLK_PERIPH(spif, HAL_CLK_PERIPH_SPIF, spi_parents); SUNXI_CLK_PERIPH(gmac_25m, HAL_CLK_PERIPH_GMAC_25M, gmac_25m_parents); SUNXI_CLK_PERIPH(gmac, HAL_CLK_PERIPH_GMAC, ahbmod_parents); -SUNXI_CLK_PERIPH(gpadc, HAL_CLK_PERIPH_GPADC, apb0mod_parents); +SUNXI_CLK_PERIPH(gpadc, HAL_CLK_PERIPH_GPADC, gpadc_parents); SUNXI_CLK_PERIPH(ths, HAL_CLK_PERIPH_THS, apb0mod_parents); /* * Strictly speaking, the pll_audiox4 and pll_audio are not pll clocks, although they are called pll @@ -1149,7 +1157,7 @@ static int calc_rate_pll_csix4(u32 parent_rate, { u64 tmp_rate = (parent_rate ? parent_rate : 24000000); tmp_rate = tmp_rate * (factor->factorn + 1); - do_div(tmp_rate, 4 * (factor->factord1 + 1)); + do_div(tmp_rate, (factor->factord1 + 1)); return (u32)tmp_rate; } diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.h index 2290919a..e42ec44b 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/ccmu/sunxi/sun8iw21p1/clk_sun8iw21.h @@ -46,7 +46,7 @@ #define SUNXI_CLK_FACTOR_PERIPH0800M_MAX_FREQ (1200000000U) #define SUNXI_CLK_FACTOR_PERIPH0480M_MAX_FREQ (1200000000U) #define SUNXI_CLK_FACTOR_VIDEO0X4_MAX_FREQ (1188000000U) -#define SUNXI_CLK_FACTOR_CSIX4_MAX_FREQ (1188000000U) +#define SUNXI_CLK_FACTOR_CSIX4_MAX_FREQ (2376000000U) #define SUNXI_CLK_FACTOR_AUDIO_MAX_FREQ (288000000U) #define SUNXI_CLK_FACTOR_NPUX4_MAX_FREQ (1188000000U) @@ -162,6 +162,7 @@ #define CLK_E907_CFG (volatile uint32_t *)(CCU_REG_BASE + 0x0D00) #define CLK_RISCV_GATE (volatile uint32_t *)(CCU_REG_BASE + 0x0D0C) #define CLK_PLL_PRE_CFG (volatile uint32_t *)(CCU_REG_BASE + 0x0E00) +#define CLK_GPADC_SEL (volatile uint32_t *)(CCU_REG_BASE + 0x0F04) #define CLK_FANOUT_GATE (volatile uint32_t *)(CCU_REG_BASE + 0x0F30) #define CLK_FANOUT27M_CFG (volatile uint32_t *)(CCU_REG_BASE + 0x0F34) #define CLK_FANOUTPCLK_CFG (volatile uint32_t *)(CCU_REG_BASE + 0x0F38) diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Kconfig b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Kconfig new file mode 100644 index 00000000..9f7ba1f9 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Kconfig @@ -0,0 +1,12 @@ +menu "GPADC Devices" + +config DRIVERS_GPADC + bool "enable gpadc driver" + default y + +config HAL_TEST_GPADC + bool "enable gpadc hal APIs test command" + depends on DRIVERS_GPADC + default n + +endmenu diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Makefile new file mode 100644 index 00000000..1f12a8d3 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/Makefile @@ -0,0 +1 @@ +obj-y += hal_gpadc.o diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/common_gpadc.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/common_gpadc.h new file mode 100644 index 00000000..ec3c6a74 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/common_gpadc.h @@ -0,0 +1,255 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __COMMON_GPADC_I_H__ +#define __COMMON_GPADC_I_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* GPADC register offset */ +#define GP_SR_REG (0x00) /* Sample Rate config register */ +#define GP_CTRL_REG (0x04) /* control register */ +#define GP_CS_EN_REG (0x08) /* compare and select enable register */ +#define GP_FIFO_INTC_REG (0x0c) /* FIFO interrupt config register */ +#define GP_FIFO_INTS_REG (0x10) /* FIFO interrupt status register */ +#define GP_FIFO_DATA_REG (0X14) /* FIFO data register */ +#define GP_CB_DATA_REG (0X18) /* calibration data register */ +#define GP_DATAL_INTC_REG (0x20) +#define GP_DATAH_INTC_REG (0x24) +#define GP_DATA_INTC_REG (0x28) +#define GP_DATAL_INTS_REG (0x30) +#define GP_DATAH_INTS_REG (0x34) +#define GP_DATA_INTS_REG (0x38) +#define GP_CH0_CMP_DATA_REG (0x40) /* channal 0 compare data register */ +#define GP_CH1_CMP_DATA_REG (0x44) /* channal 1 compare data register */ +#define GP_CH2_CMP_DATA_REG (0x48) /* channal 2 compare data register */ +#define GP_CH3_CMP_DATA_REG (0x4c) /* channal 3 compare data register */ +#define GP_CH4_CMP_DATA_REG (0x50) /* channal 4 compare data register */ +#define GP_CH5_CMP_DATA_REG (0x54) /* channal 5 compare data register */ +#define GP_CH6_CMP_DATA_REG (0x58) /* channal 6 compare data register */ +#define GP_CH7_CMP_DATA_REG (0x5c) /* channal 7 compare data register */ +#define GP_CH8_CMP_DATA_REG (0x60) /* channal 8 compare data register */ +#define GP_CH9_CMP_DATA_REG (0x64) /* channal 9 compare data register */ +#define GP_CHA_CMP_DATA_REG (0x68) /* channal 10 compare data register */ +#define GP_CHB_CMP_DATA_REG (0x6c) /* channal 11 compare data register */ +#define GP_CHC_CMP_DATA_REG (0x70) /* channal 12 compare data register */ +#define GP_CHD_CMP_DATA_REG (0x74) /* channal 13 compare data register */ +#define GP_CHE_CMP_DATA_REG (0x78) /* channal 14 compare data register */ +#define GP_CH0_DATA_REG (0x80) /* channal 0 data register */ +#define GP_CH1_DATA_REG (0x84) /* channal 1 data register */ +#define GP_CH2_DATA_REG (0x88) /* channal 2 data register */ +#define GP_CH3_DATA_REG (0x8c) /* channal 3 data register */ +#define GP_CH4_DATA_REG (0x90) /* channal 4 data register */ +#define GP_CH5_DATA_REG (0x94) /* channal 5 data register */ +#define GP_CH6_DATA_REG (0x98) /* channal 6 data register */ +#define GP_CH7_DATA_REG (0x9c) /* channal 7 data register */ +#define GP_CH8_DATA_REG (0xa0) /* channal 8 data register */ +#define GP_CH9_DATA_REG (0xa4) /* channal 9 data register */ +#define GP_CHA_DATA_REG (0xa8) /* channal 10 data register */ +#define GP_CHB_DATA_REG (0xac) /* channal 11 data register */ +#define GP_CHC_DATA_REG (0xb0) /* channal 12 data register */ +#define GP_CHD_DATA_REG (0xb4) /* channal 13 data register */ +#define GP_CHE_DATA_REG (0xb8) /* channal 14 data register */ + +/* + * GP_SR_REG default value: 0x01df_002f 50KHZ + * sample_rate = clk_in/(n+1) = 24MHZ/(0x1df + 1) = 50KHZ + */ +#define GP_SR_CON (0xffff << 16) + +/* GP_CTRL_REG default value:0x0000_0000 */ +#define GP_FIRST_CONCERT_DLY (0xff<<24) /* delay time of the first time */ +#define GP_CALI_EN (1 << 17) /* enable calibration */ +#define GP_ADC_EN (1 << 16) /* GPADC function enable */ +#define GP_LP_TEMPSENTS (1 << 7) +#define GP_EN_TEMPSENS (1 << 6) +#define GP_VBAT_DET_EN (1 << 5) +#define GP_LP_EN (1 << 4) +#define GP_VREF_MODE_SEL (7 << 1) +#define GP_ADC_LDO_EN (1 << 0) + +/* + * 00:single conversion mode + * 01:single-cycle conversion mode + * 10:continuous mode, 11:burst mode + */ +#define GP_MODE_SELECT (3 << 18) + +/* 0:disable, 1:enable */ +#define GP_CH7_CMP_EN (1 << 23) +#define GP_CH6_CMP_EN (1 << 22) +#define GP_CH5_CMP_EN (1 << 21) +#define GP_CH4_CMP_EN (1 << 20) +#define GP_CH3_CMP_EN (1 << 19) +#define GP_CH2_CMP_EN (1 << 18) +#define GP_CH1_CMP_EN (1 << 17) +#define GP_CH0_CMP_EN (1 << 16) +#define GP_CH7_SELECT (1 << 7) +#define GP_CH6_SELECT (1 << 6) +#define GP_CH5_SELECT (1 << 5) +#define GP_CH4_SELECT (1 << 4) +#define GP_CH3_SELECT (1 << 3) +#define GP_CH2_SELECT (1 << 2) +#define GP_CH1_SELECT (1 << 1) +#define GP_CH0_SELECT (1 << 0) + +/* + * GP_FIFO_INTC_REG default value: 0x0000_0f00 + * 0:disable, 1:enable + */ +#define FIFO_OVER_IRQ_EN (1 << 17) /* fifo over run irq enable */ +#define FIFO_DATA_IRQ_EN (1 << 16) /* fifo data irq enable */ + +/* write 1 to flush TX FIFO, self clear to 0 */ +#define FIFO_FLUSH (1 << 4) + +/* + * GP_FIFO_INTS_REG default value: 0x0000_0000 + * 0:no pending irq, 1: over pending, need write 1 to clear flag + */ +#define FIFO_OVER_PEND (1 << 17) /* fifo over pending flag */ +#define FIFO_DATA_PEND (1 << 16) /* fifo data pending flag */ +#define FIFO_CNT (0x3f << 8) /* the data count in fifo */ + +/* GP_FIFO_DATA_REG default value: 0x0000_0000 */ +#define GP_FIFO_DATA (0xfff << 0) /* GPADC data in fifo */ + +/* GP_CB_DATA_REG default value: 0x0000_0000 */ +#define GP_CB_DATA (0xfff << 0) /* GPADC calibration data */ + +/* GP_INTC_REG default value: 0x0000_0000 */ +#define GP_CH7_LOW_IRQ_EN (1 << 7) /* 0:disable, 1:enable */ +#define GP_CH6_LOW_IRQ_EN (1 << 6) +#define GP_CH5_LOW_IRQ_EN (1 << 5) +#define GP_CH4_LOW_IRQ_EN (1 << 4) +#define GP_CH3_LOW_IRQ_EN (1 << 3) +#define GP_CH2_LOW_IRQ_EN (1 << 2) +#define GP_CH1_LOW_IRQ_EN (1 << 1) +#define GP_CH0_LOW_IRQ_EN (1 << 0) +#define GP_CH7_HIG_IRQ_EN (1 << 7) +#define GP_CH6_HIG_IRQ_EN (1 << 6) +#define GP_CH5_HIG_IRQ_EN (1 << 5) +#define GP_CH4_HIG_IRQ_EN (1 << 4) +#define GP_CH3_HIG_IRQ_EN (1 << 3) +#define GP_CH2_HIG_IRQ_EN (1 << 2) +#define GP_CH1_HIG_IRQ_EN (1 << 1) +#define GP_CH0_HIG_IRQ_EN (1 << 0) +#define GP_CH7_DATA_IRQ_EN (1 << 7) +#define GP_CH6_DATA_IRQ_EN (1 << 6) +#define GP_CH5_DATA_IRQ_EN (1 << 5) +#define GP_CH4_DATA_IRQ_EN (1 << 4) +#define GP_CH3_DATA_IRQ_EN (1 << 3) +#define GP_CH2_DATA_IRQ_EN (1 << 2) +#define GP_CH1_DATA_IRQ_EN (1 << 1) +#define GP_CH0_DATA_IRQ_EN (1 << 0) + +/* GP_INTS_REG default value: 0x0000_0000 */ +#define GP_CH7_LOW (1 << 7) /* 0:no pending, 1:pending */ +#define GP_CH6_LOW (1 << 6) +#define GP_CH5_LOW (1 << 5) +#define GP_CH4_LOW (1 << 4) +#define GP_CH3_LOW (1 << 3) +#define GP_CH2_LOW (1 << 2) +#define GP_CH1_LOW (1 << 1) +#define GP_CH0_LOW (1 << 0) +#define GP_CH7_HIG (1 << 7) +#define GP_CH6_HIG (1 << 6) +#define GP_CH5_HIG (1 << 5) +#define GP_CH4_HIG (1 << 4) +#define GP_CH3_HIG (1 << 3) +#define GP_CH2_HIG (1 << 2) +#define GP_CH1_HIG (1 << 1) +#define GP_CH0_HIG (1 << 0) +#define GP_CH7_DATA (1 << 7) +#define GP_CH6_DATA (1 << 6) +#define GP_CH5_DATA (1 << 5) +#define GP_CH4_DATA (1 << 4) +#define GP_CH3_DATA (1 << 3) +#define GP_CH2_DATA (1 << 2) +#define GP_CH1_DATA (1 << 1) +#define GP_CH0_DATA (1 << 0) + +/* GP_CH0_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH0_CMP_HIG_DATA (0xfff << 16) +#define GP_CH0_CMP_LOW_DATA (0xfff << 0) +/* GP_CH1_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH1_CMP_HIG_DATA (0xfff << 16) +#define GP_CH1_CMP_LOW_DATA (0xfff << 0) +/* GP_CH2_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH2_CMP_HIG_DATA (0xfff << 16) +#define GP_CH2_CMP_LOW_DATA (0xfff << 0) +/* GP_CH3_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH3_CMP_HIG_DATA (0xfff << 16) +#define GP_CH3_CMP_LOW_DATA (0xfff << 0) +/* GP_CH4_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH4_CMP_HIG_DATA (0xfff << 16) +#define GP_CH4_CMP_LOW_DATA (0xfff << 0) +/* GP_CH5_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH5_CMP_HIG_DATA (0xfff << 16) +#define GP_CH5_CMP_LOW_DATA (0xfff << 0) +/* GP_CH6_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH6_CMP_HIG_DATA (0xfff << 16) +#define GP_CH6_CMP_LOW_DATA (0xfff << 0) +/* GP_CH7_CMP_DATA_REG default value 0x0bff_0400 */ +#define GP_CH7_CMP_HIG_DATA (0xfff << 16) +#define GP_CH7_CMP_LOW_DATA (0xfff << 0) + +/* GP_CH0_DATA_REG default value:0x0000_0000 */ +#define GP_CH_DATA_MASK (0xfff << 0) /*data mask */ + +#define CHANNEL_0_SELECT (0x01 << 0) +#define CHANNEL_1_SELECT (0x01 << 1) +#define CHANNEL_2_SELECT (0x01 << 2) +#define CHANNEL_3_SELECT (0x01 << 3) +#define CHANNEL_4_SELECT (0x01 << 4) +#define CHANNEL_5_SELECT (0x01 << 5) +#define CHANNEL_6_SELECT (0x01 << 6) +#define CHANNEL_7_SELECT (0x01 << 7) +#define CHANNEL_8_SELECT (0x01 << 8) +#define CHANNEL_A_SELECT (0x01 << 9) +#define CHANNEL_B_SELECT (0x01 << 0xa) +#define CHANNEL_C_SELECT (0x01 << 0xb) +#define CHANNEL_D_SELECT (0x01 << 0xc) +#define CHANNEL_E_SELECT (0x01 << 0xd) +#if defined(CONFIG_ARCH_SUN20IW2) +#define CHANNEL_MAX_NUM 16 +#define CHANNEL_NUM 16 +#else +#define CHANNEL_MAX_NUM 8 +#define CHANNEL_NUM 4 +#endif +#ifdef __cplusplus +} +#endif +#endif /* __COMMON_GPADC_I_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/hal_gpadc.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/hal_gpadc.c new file mode 100644 index 00000000..f67e9d17 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/hal_gpadc.c @@ -0,0 +1,749 @@ +/* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. + + * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in + * the the People's Republic of China and other countries. + * All Allwinner Technology Co.,Ltd. trademarks are used with permission. + + * DISCLAIMER + * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. + * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) + * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN + * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. + * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS + * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. + * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY. + + + * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT + * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING + * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE + * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#ifdef CONFIG_COMPONENTS_PM +#include +#endif + +hal_gpadc_t hal_gpadc; + +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) +static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc) +{ + hal_clk_type_t clk_type = HAL_SUNXI_CCU; + hal_clk_id_t gpadc_clk_id = gpadc->bus_clk; + + hal_reset_type_t reset_type = HAL_SUNXI_RESET; + hal_reset_id_t gpadc_reset_id = gpadc->rst_clk; + + gpadc->reset = hal_reset_control_get(reset_type, gpadc_reset_id); + if (hal_reset_control_reset(gpadc->reset)) + { + GPADC_ERR("gpadc reset deassert failed!\n"); + return GPADC_ERROR; + } + + gpadc->mbus_clk = hal_clock_get(clk_type, gpadc_clk_id); + if (hal_clock_enable(gpadc->mbus_clk)) + { + GPADC_ERR("gpadc clk enable failed!\n"); + return GPADC_ERROR; + } + + return GPADC_OK; +} +#elif defined(CONFIG_ARCH_SUN20IW2) +static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc) +{ + hal_clk_type_t clk_type = HAL_SUNXI_AON_CCU; + hal_clk_id_t gpadc_clk_id = gpadc->bus_clk; + + hal_clk_id_t gpadc_clk_id1 = CLK_GPADC_CTRL; + + hal_reset_type_t reset_type = HAL_SUNXI_AON_RESET; + hal_reset_id_t gpadc_reset_id = gpadc->rst_clk; + + gpadc->reset = hal_reset_control_get(reset_type, gpadc_reset_id); + if (hal_reset_control_reset(gpadc->reset)) + { + GPADC_ERR("gpadc reset deassert failed!\n"); + return GPADC_ERROR; + } + + gpadc->mbus_clk = hal_clock_get(clk_type, gpadc_clk_id); + if (hal_clock_enable(gpadc->mbus_clk)) + { + GPADC_ERR("gpadc clk enable failed!\n"); + return GPADC_ERROR; + } + + gpadc->mbus_clk1 = hal_clock_get(clk_type, gpadc_clk_id1); + if (hal_clock_enable(gpadc->mbus_clk1)) + { + GPADC_ERR("gpadc clk1 enable failed!\n"); + return GPADC_ERROR; + } + + return GPADC_OK; +} +#elif defined(CONFIG_ARCH_SUN20IW3) +static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc) +{ + hal_clk_type_t clk_type = HAL_SUNXI_CCU; + hal_clk_id_t gpadc_clk_id = HAL_CLK_PERIPH_GPADC; + + gpadc->mclk = hal_clock_get(clk_type, gpadc_clk_id); + if(hal_clock_enable(gpadc->mclk)) + { + GPADC_ERR("gpadc clk enable failed!\n"); + return GPADC_ERROR; + } + + return GPADC_OK; +} +#else +static hal_gpadc_status_t hal_gpadc_clk_init(hal_gpadc_t *gpadc) +{ +#if !defined(CONFIG_ARCH_SUN8IW18P1) + if (hal_clk_set_parent(gpadc->mclk, gpadc->pclk)) + { + GPADC_ERR("[gpadc] clk set parent failed!"); + return GPADC_ERROR; + } +#endif + if (hal_clock_enable(gpadc->mclk)) + { + GPADC_ERR("[gpadc] clk enable mclk failed!"); + return GPADC_ERROR; + } + + return GPADC_OK; +} +#endif + +static void hal_gpadc_clk_exit(hal_gpadc_t *gpadc) +{ + hal_disable_irq(gpadc->irq_num); +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) + hal_clock_disable(gpadc->mbus_clk); + hal_reset_control_assert(gpadc->reset); +#elif defined(CONFIG_ARCH_SUN20IW2) + hal_clock_disable(gpadc->mbus_clk); + hal_clock_disable(gpadc->mbus_clk1); + hal_reset_control_assert(gpadc->reset); +#else + hal_clock_disable(gpadc->mclk); +#endif +} + +static int gpadc_channel_check_valid(hal_gpadc_channel_t channal) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + +#if defined(CONFIG_ARCH_SUN20IW2) + if (channal == 12) + return 0; +#endif + + return channal < gpadc->channel_num ? 0 : -1 ; +} + +static void gpadc_channel_select(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + reg_val |= (0x01 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + +} + +static void gpadc_channel_deselect(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + reg_val &= ~(0x01 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + +} + +static void gpadc_compare_select(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + reg_val |= (GP_CH0_CMP_EN << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CS_EN_REG); + +} + +static void gpadc_compare_deselect(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CTRL_REG); + reg_val &= ~(GP_CH0_CMP_EN << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CTRL_REG); + +} + +static void gpadc_channel_enable_lowirq(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG); + reg_val |= (0x01 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG); +} + +static void gpadc_channel_disable_lowirq(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG); + reg_val &= ~(0x01 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAL_INTC_REG); +} + +static void gpadc_channel_compare_lowdata(hal_gpadc_channel_t channal, + uint32_t low_uv) +{ + uint32_t reg_val = 0, low = 0, unit = 0; + hal_gpadc_t *gpadc = &hal_gpadc; + + /* analog voltage range 0~1.8v, 12bits sample rate, unit=1.8v/(2^12) */ + unit = VOL_RANGE / 4096; /* 12bits sample rate */ + low = low_uv / unit; + if (low > VOL_VALUE_MASK) + { + low = VOL_VALUE_MASK; + } + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal); + reg_val &= ~VOL_VALUE_MASK; + reg_val |= (low & VOL_VALUE_MASK); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal); + +} + +static void gpadc_channel_enable_highirq(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG); + reg_val |= (1 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG); + +} + +void gpadc_key_enable_highirq(hal_gpadc_channel_t channal) +{ + gpadc_channel_enable_highirq(channal); +} + +static void gpadc_channel_disable_highirq(hal_gpadc_channel_t channal) +{ + uint32_t reg_val; + hal_gpadc_t *gpadc = &hal_gpadc; + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG); + reg_val &= ~(1 << channal); + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_DATAH_INTC_REG); + +} + +void gpadc_key_disable_highirq(hal_gpadc_channel_t channal) +{ + gpadc_channel_disable_highirq(channal); +} + +static void gpadc_channel_compare_highdata(hal_gpadc_channel_t channal, + uint32_t hig_uv) +{ + uint32_t reg_val = 0, hig_val = 0, unit_val = 0; + hal_gpadc_t *gpadc = &hal_gpadc; + + /* anolog voltage range 0~1.8v, 12bits sample rate, unit=1.8v/(2^12) */ + unit_val = VOL_RANGE / 4096; /* 12bits sample rate */ + hig_val = hig_uv / unit_val; + + if (hig_val > VOL_VALUE_MASK) + { + hig_val = VOL_VALUE_MASK; + } + + reg_val = readl((unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal); + reg_val &= ~(VOL_VALUE_MASK << 16); + reg_val |= (hig_val & VOL_VALUE_MASK) << 16; + writel(reg_val, (unsigned long)(gpadc->reg_base) + GP_CH0_CMP_DATA_REG + 4 * channal); + +} + +/* clk_in: source clock, round_clk: sample rate */ +static void gpadc_sample_rate_set(uint32_t reg_base, uint32_t clk_in, + uint32_t round_clk) +{ + uint32_t div, reg_val; + if (round_clk > clk_in) + { + GPADC_ERR("invalid round clk!"); + } + div = clk_in / round_clk - 1 ; + reg_val = readl((unsigned long)(reg_base) + GP_SR_REG); + reg_val &= ~GP_SR_CON; + reg_val |= (div << 16); + writel(reg_val, (unsigned long)(reg_base) + GP_SR_REG); +} + +static void gpadc_calibration_enable(uint32_t reg_base) +{ + uint32_t reg_val; + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val |= GP_CALI_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +static void gpadc_mode_select(uint32_t reg_base, + enum gp_select_mode mode) +{ + uint32_t reg_val; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val &= ~GP_MODE_SELECT; + reg_val |= (mode << 18); + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +#if defined(CONFIG_ARCH_SUN20IW2) +static void gpadc_datairq_enable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_FIFO_INTC_REG); + reg_val |= FIFO_DATA_IRQ_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_FIFO_INTC_REG); +} + +static void gpadc_datairq_disable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_FIFO_INTC_REG); + reg_val &= ~FIFO_DATA_IRQ_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_FIFO_INTC_REG); +} + +static void gpadc_vbat_det_enable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val |= GP_VBAT_DET_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +static void gpadc_vbat_det_disable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val &= ~GP_VBAT_DET_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +static void gpadc_vref_mode_select(uint32_t reg_base, u32 flag) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val &= ~GP_VREF_MODE_SEL; + reg_val |= flag << 1; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +/* enable gpadc ldo function, true:enable, false:disable */ +static void gpadc_ldo_enable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val |= GP_ADC_LDO_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +static void gpadc_ldo_disable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val &= ~GP_ADC_LDO_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} +#endif /* CONFIG_ARCH_SUN20IW2 */ + +/* enable gpadc function, true:enable, false:disable */ +static void gpadc_enable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val |= GP_ADC_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +/* enable gpadc function, true:enable, false:disable */ +static void gpadc_disable(uint32_t reg_base) +{ + uint32_t reg_val = 0; + + reg_val = readl((unsigned long)(reg_base) + GP_CTRL_REG); + reg_val &= ~GP_ADC_EN; + writel(reg_val, (unsigned long)(reg_base) + GP_CTRL_REG); +} + +static uint32_t gpadc_read_channel_irq_enable(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATA_INTC_REG); +} + +static uint32_t gpadc_read_channel_lowirq_enable(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATAL_INTC_REG); +} + +static uint32_t gpadc_read_channel_highirq_enable(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATAH_INTC_REG); +} + +static uint32_t gpadc_channel_irq_status(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATA_INTS_REG); +} + +static void gpadc_channel_clear_irq(uint32_t reg_base, uint32_t flags) +{ + writel(flags, (unsigned long)(reg_base) + GP_DATA_INTS_REG); +} + +static uint32_t gpadc_channel_lowirq_status(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATAL_INTS_REG); +} + +static void gpadc_channel_clear_lowirq(uint32_t reg_base, uint32_t flags) +{ + writel(flags, (unsigned long)(reg_base) + GP_DATAL_INTS_REG); +} + +static uint32_t gpadc_channel_highirq_status(uint32_t reg_base) +{ + return readl((unsigned long)(reg_base) + GP_DATAH_INTS_REG); +} + +static void gpadc_channel_clear_highirq(uint32_t reg_base, uint32_t flags) +{ + writel(flags, (unsigned long)(reg_base) + GP_DATAH_INTS_REG); +} + +static int gpadc_read_data(uint32_t reg_base, hal_gpadc_channel_t channal) +{ + return readl((unsigned long)(reg_base) + GP_CH0_DATA_REG + 4 * channal) & GP_CH_DATA_MASK; +} + +uint32_t gpadc_read_channel_data(hal_gpadc_channel_t channel) +{ + int data; + uint32_t vol_data; + hal_gpadc_t *gpadc = &hal_gpadc; + + data = gpadc_read_data(gpadc->reg_base, channel); + data = ((VOL_RANGE / 4096) * data); + vol_data = data / 1000; + GPADC_INFO("channel %d vol data: %u\n", channel, vol_data); + + return vol_data; +} + +int hal_gpadc_callback(uint32_t data_type, uint32_t data) +{ + GPADC_INFO("gpadc interrupt, data_type is %u", data_type); + return 0; +} + +static hal_irqreturn_t gpadc_handler(void *dev) +{ + hal_gpadc_t *gpadc = (hal_gpadc_t *)dev; + + uint32_t reg_val, reg_low, reg_high; + uint32_t reg_enable, reg_enable_low, reg_enable_high; + uint32_t i, data = 0; + + reg_enable = gpadc_read_channel_irq_enable(gpadc->reg_base); + reg_enable_low = gpadc_read_channel_lowirq_enable(gpadc->reg_base); + reg_enable_high = gpadc_read_channel_highirq_enable(gpadc->reg_base); + + reg_val = gpadc_channel_irq_status(gpadc->reg_base); + gpadc_channel_clear_irq(gpadc->reg_base, reg_val); + reg_low = gpadc_channel_lowirq_status(gpadc->reg_base); + gpadc_channel_clear_lowirq(gpadc->reg_base, reg_val); + reg_high = gpadc_channel_highirq_status(gpadc->reg_base); + gpadc_channel_clear_highirq(gpadc->reg_base, reg_val); + + for (i = 0; i < gpadc->channel_num; i++) + { + if (reg_low & (1 << i) & reg_enable_low) + { + data = gpadc_read_data(gpadc->reg_base, i); + //gpadc_channel_enable_highirq(i); + + if (gpadc->callback[i]) + { + gpadc->callback[i](GPADC_DOWN, data); + } + } + + if (reg_high & (1 << i) & reg_enable_high) + { + //gpadc_channel_disable_highirq(i); + gpadc->callback[i](GPADC_UP, data); + } + } + + return 0; +} + +hal_gpadc_status_t hal_gpadc_register_callback(hal_gpadc_channel_t channal, + gpadc_callback_t user_callback) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + + if (gpadc_channel_check_valid(channal)) + { + return GPADC_CHANNEL_ERROR; + } + + if (user_callback == NULL) + { + return GPADC_ERROR; + } + + gpadc->callback[channal] = user_callback; + + return GPADC_OK; +} + +hal_gpadc_status_t hal_gpadc_channel_init(hal_gpadc_channel_t channal) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + + if (gpadc_channel_check_valid(channal)) + { + return GPADC_CHANNEL_ERROR; + } + + gpadc_channel_select(channal); + gpadc_compare_select(channal); + gpadc_channel_enable_lowirq(channal); + gpadc_channel_compare_lowdata(channal, COMPARE_LOWDATA); + gpadc_channel_compare_highdata(channal, COMPARE_HIGDATA); + hal_msleep(4); + return GPADC_OK; +} + +hal_gpadc_status_t hal_gpadc_channel_exit(hal_gpadc_channel_t channal) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + + if (gpadc_channel_check_valid(channal)) + { + return GPADC_CHANNEL_ERROR; + } + + gpadc_channel_deselect(channal); + gpadc_compare_deselect(channal); + gpadc_channel_disable_lowirq(channal); + + return GPADC_OK; +} + +static int hal_gpadc_setup(hal_gpadc_t *gpadc) +{ + uint8_t i; + + gpadc->reg_base = GPADC_BASE; + gpadc->channel_num = CHANNEL_NUM; + gpadc->irq_num = SUNXI_GPADC_IRQ; + gpadc->sample_rate = DEFAULT_SR; +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) + gpadc->bus_clk = CLK_BUS_GPADC; + gpadc->rst_clk = RST_BUS_GPADC; +#elif defined(CONFIG_ARCH_SUN20IW2) + gpadc->bus_clk = CLK_GPADC; + gpadc->rst_clk = RST_GPADC; +#else + gpadc->pclk = HAL_CLK_SRC_HOSC24M; + gpadc->mclk = HAL_CLK_PERIPH_GPADC; +#endif + gpadc->mode = GP_CONTINUOUS_MODE; + + for (i = 0; i < gpadc->channel_num; i++) + { + gpadc->callback[i] = hal_gpadc_callback; + } + + if (hal_request_irq(gpadc->irq_num, gpadc_handler, "gpadc", gpadc) < 0) + { + return GPADC_IRQ_ERROR; + } + + return GPADC_OK; +}; + +static int hal_gpadc_hw_init(hal_gpadc_t *gpadc) +{ +#if defined(CONFIG_ARCH_SUN20IW2) + unsigned long rate; +#endif + + if (hal_gpadc_clk_init(gpadc)) + { + GPADC_ERR("gpadc init clk error"); + return GPADC_CLK_ERROR; + } + + GPADC_INFO("gpadc set sample rate"); +#if defined(CONFIG_ARCH_SUN20IW2) + rate = hal_clk_get_rate(gpadc->mbus_clk1); + gpadc_sample_rate_set(gpadc->reg_base, rate, gpadc->sample_rate); +#else + gpadc_sample_rate_set(gpadc->reg_base, OSC_24MHZ, gpadc->sample_rate); +#endif + GPADC_INFO("gpadc enable calibration"); + gpadc_calibration_enable(gpadc->reg_base); + gpadc_mode_select(gpadc->reg_base, gpadc->mode); + +#if defined(CONFIG_ARCH_SUN20IW2) + gpadc_vbat_det_enable(gpadc->reg_base); + gpadc_vref_mode_select(gpadc->reg_base, 0x1); + gpadc_ldo_enable(gpadc->reg_base); + usleep(100); +#endif + + gpadc_enable(gpadc->reg_base); + + hal_enable_irq(gpadc->irq_num); + + return GPADC_OK; +} + +static void hal_gpadc_hw_exit(hal_gpadc_t *gpadc) +{ + hal_disable_irq(gpadc->irq_num); + gpadc_disable(gpadc->reg_base); + hal_gpadc_clk_exit(gpadc); +} + +#ifdef CONFIG_COMPONENTS_PM +static inline void hal_gpadc_save_regs(hal_gpadc_t *gpadc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hal_gpadc_regs_offset); i++) + gpadc->regs_backup[i] = readl((unsigned long)(gpadc->reg_base) + hal_gpadc_regs_offset[i]); +} + +static inline void hal_gpadc_restore_regs(hal_gpadc_t *gpadc) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hal_gpadc_regs_offset); i++) + writel(gpadc->regs_backup[i], (unsigned long)(gpadc->reg_base) + hal_gpadc_regs_offset[i]); +} + +static int hal_gpadc_resume(struct pm_device *dev, suspend_mode_t mode) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + + hal_gpadc_hw_init(gpadc); + hal_gpadc_restore_regs(gpadc); + GPADC_INFO("hal gpadc resume\n"); + return 0; +} + +static int hal_gpadc_suspend(struct pm_device *dev, suspend_mode_t mode) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + + hal_gpadc_save_regs(gpadc); + hal_gpadc_hw_exit(gpadc); + GPADC_INFO("hal gpadc suspend\n"); + return 0; +} + +struct pm_devops pm_gpadc_ops = { + .suspend = hal_gpadc_suspend, + .resume = hal_gpadc_resume, +}; + +struct pm_device pm_gpadc = { + .name = "sunxi_gpadc", + .ops = &pm_gpadc_ops, +}; +#endif + +int hal_gpadc_init(void) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + int err; + + err = hal_gpadc_setup(gpadc); + if (err) + { + GPADC_ERR("gpadc setup failed\n"); + return GPADC_ERROR; + } + + err = hal_gpadc_hw_init(gpadc); + if (err) + { + GPADC_ERR("gpadc init hw failed\n"); + return GPADC_ERROR; + } + +#ifdef CONFIG_COMPONENTS_PM + pm_devops_register(&pm_gpadc); +#endif + return GPADC_OK; +} + +hal_gpadc_status_t hal_gpadc_deinit(void) +{ + hal_gpadc_t *gpadc = &hal_gpadc; + +#ifdef CONFIG_COMPONENTS_PM + pm_devops_unregister(&pm_gpadc); +#endif + + hal_gpadc_hw_exit(gpadc); + + return GPADC_OK; +} diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform/gpadc_sun20iw3.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform/gpadc_sun20iw3.h new file mode 100644 index 00000000..5577c60d --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform/gpadc_sun20iw3.h @@ -0,0 +1,49 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY��S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS��SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY��S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __GPADC_SUN20IW3_H__ +#define __GPADC_SUN20IW3_H__ + +#define SUNXI_GPADC_IRQ 73 +#define GPADC_BASE 0x02009000 +#define OSC_24MHZ (24000000UL) +#define MAX_SR (100000UL) +#define MIN_SR (400UL) +#define DEFAULT_SR (1000UL) + +/* voltage range 0~1.8v, unit is uv */ +#define VOL_RANGE (1800000UL) +#define VOL_VALUE_MASK (0xfff) +#define COMPARE_LOWDATA 1800000UL +#define COMPARE_HIGDATA 0 + +#endif /* __GPADC_SUN20IW3_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform_gpadc.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform_gpadc.h new file mode 100644 index 00000000..f6634c8d --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpadc/platform_gpadc.h @@ -0,0 +1,56 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __PLATFORM_GPADC_H__ +#define __PLATFORM_GPADC_H__ + +#if defined(CONFIG_ARCH_SUN8IW18P1) +#include "platform/gpadc_sun8iw18.h" +#endif + +#if defined(CONFIG_ARCH_SUN8IW19) +#include "platform/gpadc_sun8iw19.h" +#endif + +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) +#include "platform/gpadc_sun20iw1.h" +#endif + +#if defined(CONFIG_ARCH_SUN20IW2) +#include "platform/gpadc_sun20iw2.h" +#endif + +#if defined(CONFIG_ARCH_SUN20IW3) +#include "platform/gpadc_sun20iw3.h" +#endif + +#endif /* __PLATFORM_GPADC_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/gpio.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/gpio.h index 7d5152e7..7e3793b9 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/gpio.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/gpio.h @@ -34,6 +34,9 @@ #define __GPIO_I_H__ #include "hal_interrupt.h" +#ifdef CONFIG_COMPONENTS_PM +#include +#endif #ifdef __cplusplus extern "C" { @@ -225,8 +228,14 @@ struct gpio_pm_reg_cache #endif const struct gpio_desc **gpio_get_platform_desc(void); +#ifdef CONFIG_STANDBY int hal_gpio_suspend(void); int hal_gpio_resume(void); +#endif +#ifdef CONFIG_COMPONENTS_PM +static int hal_gpio_suspend(struct pm_device *dev, suspend_mode_t mode); +static int hal_gpio_resume(struct pm_device *dev, suspend_mode_t mode); +#endif int hal_gpio_r_irq_disable(uint32_t irq); int hal_gpio_r_irq_enable(uint32_t irq); int hal_gpio_r_all_irq_disable(void); diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/hal_gpio.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/hal_gpio.c index ff2ae5e9..410d0b91 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/hal_gpio.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/gpio/hal_gpio.c @@ -1,34 +1,34 @@ /* -* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. -* -* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in -* the the People's Republic of China and other countries. -* All Allwinner Technology Co.,Ltd. trademarks are used with permission. -* -* DISCLAIMER -* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. -* IF YOU NEED TO INTEGRATE THIRD PARTY��S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) -* IN ALLWINNERS��SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN -* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. -* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS -* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. -* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY��S TECHNOLOGY. -* -* -* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT -* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, -* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING -* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE -* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) -* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -* OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. + * + * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in + * the the People's Republic of China and other countries. + * All Allwinner Technology Co.,Ltd. trademarks are used with permission. + * + * DISCLAIMER + * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. + * IF YOU NEED TO INTEGRATE THIRD PARTY'S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) + * IN ALLWINNERS'SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN + * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. + * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS + * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. + * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY��S TECHNOLOGY. + * + * + * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT + * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING + * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE + * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include #include /* #include */ @@ -39,6 +39,12 @@ #include "gpio.h" #include #include +#ifdef CONFIG_COMPONENTS_PM +#include +#endif +#ifdef CONFIG_AMP_SHARE_IRQ +#include +#endif static const struct gpio_desc **g_gpio_desc = NULL; @@ -51,18 +57,18 @@ static const struct gpio_desc **g_gpio_desc = NULL; static inline pin_config_param_t pinconf_to_config_param(unsigned long config) { - return (pin_config_param_t)(config & 0xffUL); + return (pin_config_param_t)(config & 0xffUL); } static inline gpio_pin_t pinconf_to_config_argument(unsigned long config) { - return (uint32_t)((config >> 8) & 0xffffffUL); + return (uint32_t)((config >> 8) & 0xffffffUL); } static inline uint64_t pinconf_to_config_packed(pin_config_param_t param, - unsigned long argument) + unsigned long argument) { - return GPIO_CFG_PACK(param, argument); + return GPIO_CFG_PACK(param, argument); } /* @@ -84,810 +90,851 @@ static inline uint64_t pinconf_to_config_packed(pin_config_param_t param, */ static inline uint32_t gpio_mux_reg(gpio_pin_t pin) { - pin %= BANK_BOUNDARY; - uint32_t bank = pin / PINS_PER_BANK; - uint32_t offset = bank * BANK_MEM_SIZE; - offset += MUX_REGS_OFFSET; - offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04; - return round_down(offset, 4); + pin %= BANK_BOUNDARY; + uint32_t bank = pin / PINS_PER_BANK; + uint32_t offset = bank * BANK_MEM_SIZE; + offset += MUX_REGS_OFFSET; + offset += pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04; + return round_down(offset, 4); } static inline uint32_t gpio_mux_offset(gpio_pin_t pin) { - gpio_pin_t pin_num = pin % MUX_PINS_PER_REG; - return pin_num * MUX_PINS_BITS; + gpio_pin_t pin_num = pin % MUX_PINS_PER_REG; + return pin_num * MUX_PINS_BITS; } static inline uint32_t gpio_data_reg(gpio_pin_t pin) { - pin %= BANK_BOUNDARY; - uint32_t bank = pin / PINS_PER_BANK; - uint32_t offset = bank * BANK_MEM_SIZE; - offset += DATA_REGS_OFFSET; - offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04; - return round_down(offset, 4); + pin %= BANK_BOUNDARY; + uint32_t bank = pin / PINS_PER_BANK; + uint32_t offset = bank * BANK_MEM_SIZE; + offset += DATA_REGS_OFFSET; + offset += pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04; + return round_down(offset, 4); } static inline uint32_t gpio_data_offset(gpio_pin_t pin) { - gpio_pin_t pin_num = pin % DATA_PINS_PER_REG; - return pin_num * DATA_PINS_BITS; + gpio_pin_t pin_num = pin % DATA_PINS_PER_REG; + return pin_num * DATA_PINS_BITS; } static inline uint32_t gpio_dlevel_reg(gpio_pin_t pin) { - pin %= BANK_BOUNDARY; - uint32_t bank = pin / PINS_PER_BANK; - uint32_t offset = bank * BANK_MEM_SIZE; - offset += DLEVEL_REGS_OFFSET; - offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04; - return round_down(offset, 4); + pin %= BANK_BOUNDARY; + uint32_t bank = pin / PINS_PER_BANK; + uint32_t offset = bank * BANK_MEM_SIZE; + offset += DLEVEL_REGS_OFFSET; + offset += pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04; + return round_down(offset, 4); } static inline uint32_t gpio_dlevel_offset(gpio_pin_t pin) { - gpio_pin_t pin_num = pin % DLEVEL_PINS_PER_REG; - return pin_num * DLEVEL_PINS_BITS; + gpio_pin_t pin_num = pin % DLEVEL_PINS_PER_REG; + return pin_num * DLEVEL_PINS_BITS; } static inline uint32_t gpio_pull_reg(gpio_pin_t pin) { - pin %= BANK_BOUNDARY; - uint32_t bank = pin / PINS_PER_BANK; - uint32_t offset = bank * BANK_MEM_SIZE; - offset += PULL_REGS_OFFSET; - offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04; - return round_down(offset, 4); + pin %= BANK_BOUNDARY; + uint32_t bank = pin / PINS_PER_BANK; + uint32_t offset = bank * BANK_MEM_SIZE; + offset += PULL_REGS_OFFSET; + offset += pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04; + return round_down(offset, 4); } static inline uint32_t gpio_pull_offset(gpio_pin_t pin) { - gpio_pin_t pin_num = pin % PULL_PINS_PER_REG; - return pin_num * PULL_PINS_BITS; + gpio_pin_t pin_num = pin % PULL_PINS_PER_REG; + return pin_num * PULL_PINS_BITS; } static inline uint32_t gpio_irq_ctrl_reg_from_bank(u8 bank, unsigned bank_base) { - return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE; + return IRQ_CTRL_REG + (bank_base + bank) * IRQ_MEM_SIZE; } static inline uint32_t gpio_irq_ctrl_reg(uint32_t irq, unsigned bank_base) { - uint32_t bank = irq / IRQ_PER_BANK; - return gpio_irq_ctrl_reg_from_bank(bank, bank_base); + uint32_t bank = irq / IRQ_PER_BANK; + return gpio_irq_ctrl_reg_from_bank(bank, bank_base); } static inline uint32_t gpio_irq_ctrl_offset(uint32_t irq) { - uint32_t offset = irq % IRQ_CTRL_IRQ_PER_REG; - return offset * IRQ_CTRL_IRQ_BITS; + uint32_t offset = irq % IRQ_CTRL_IRQ_PER_REG; + return offset * IRQ_CTRL_IRQ_BITS; } static inline uint32_t gpio_get_pin_base_from_bank(u8 bank, unsigned bank_base) { - return (bank_base + bank) * IRQ_MEM_SIZE; + return (bank_base + bank) * IRQ_MEM_SIZE; } static inline uint32_t gpio_irq_status_reg_from_bank(u8 bank, unsigned bank_base) { - return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE; + return IRQ_STATUS_REG + (bank_base + bank) * IRQ_MEM_SIZE; } static inline uint32_t gpio_irq_status_reg(uint32_t irq, unsigned bank_base) { - uint32_t bank = irq / IRQ_PER_BANK; - return gpio_irq_status_reg_from_bank(bank, bank_base); + uint32_t bank = irq / IRQ_PER_BANK; + return gpio_irq_status_reg_from_bank(bank, bank_base); } static inline uint32_t gpio_irq_debounce_from_bank(u8 bank, unsigned bank_base) { - return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE; + return IRQ_DEBOUNCE_REG + (bank_base + bank) * IRQ_MEM_SIZE; } static inline uint32_t gpio_irq_debounce_reg(uint32_t irq, unsigned bank_base) { - uint32_t bank = irq / IRQ_PER_BANK; - return gpio_irq_debounce_from_bank(bank, bank_base); + uint32_t bank = irq / IRQ_PER_BANK; + return gpio_irq_debounce_from_bank(bank, bank_base); } static inline uint32_t gpio_irq_status_offset(uint32_t irq) { - uint32_t index = irq % IRQ_STATUS_IRQ_PER_REG; - return index * IRQ_STATUS_IRQ_BITS; + uint32_t index = irq % IRQ_STATUS_IRQ_PER_REG; + return index * IRQ_STATUS_IRQ_BITS; } static inline uint32_t gpio_irq_cfg_reg(uint32_t irq, unsigned bank_base) { - uint32_t bank = irq / IRQ_PER_BANK; - uint32_t reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04; + uint32_t bank = irq / IRQ_PER_BANK; + uint32_t reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04; - return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg; + return IRQ_CFG_REG + (bank_base + bank) * IRQ_MEM_SIZE + reg; } static inline uint32_t gpio_irq_cfg_offset(uint32_t irq) { - uint32_t index = irq % IRQ_CFG_IRQ_PER_REG; - return index * IRQ_CFG_IRQ_BITS; + uint32_t index = irq % IRQ_CFG_IRQ_PER_REG; + return index * IRQ_CFG_IRQ_BITS; } static int gpio_pconf_reg(gpio_pin_t pin, pin_config_param_t param, - uint32_t *offset, uint32_t *shift, uint32_t *mask) + uint32_t *offset, uint32_t *shift, uint32_t *mask) { - switch (param) - { - case GPIO_TYPE_DRV: - *offset = gpio_dlevel_reg(pin); - *shift = gpio_dlevel_offset(pin); - *mask = DLEVEL_PINS_MASK; - break; - - case GPIO_TYPE_PUD: - *offset = gpio_pull_reg(pin); - *shift = gpio_pull_offset(pin); - *mask = PULL_PINS_MASK; - break; - - case GPIO_TYPE_DAT: - *offset = gpio_data_reg(pin); - *shift = gpio_data_offset(pin); - *mask = DATA_PINS_MASK; - break; - - case GPIO_TYPE_FUNC: - *offset = gpio_mux_reg(pin); - *shift = gpio_mux_offset(pin); - *mask = MUX_PINS_MASK; - break; - - default: - GPIO_ERR("Invalid mux type"); - return -1; - } - return 0; + switch (param) + { + case GPIO_TYPE_DRV: + *offset = gpio_dlevel_reg(pin); + *shift = gpio_dlevel_offset(pin); + *mask = DLEVEL_PINS_MASK; + break; + + case GPIO_TYPE_PUD: + *offset = gpio_pull_reg(pin); + *shift = gpio_pull_offset(pin); + *mask = PULL_PINS_MASK; + break; + + case GPIO_TYPE_DAT: + *offset = gpio_data_reg(pin); + *shift = gpio_data_offset(pin); + *mask = DATA_PINS_MASK; + break; + + case GPIO_TYPE_FUNC: + *offset = gpio_mux_reg(pin); + *shift = gpio_mux_offset(pin); + *mask = MUX_PINS_MASK; + break; + + default: + GPIO_ERR("Invalid mux type"); + return -1; + } + return 0; } static uint32_t count_gpio_bank_mask(void) { - uint32_t max_bank = (uint32_t)GPIO_MAX_BANK; - uint32_t mask = 0; - do - { - mask |= 1 << (max_bank / PINS_PER_BANK); - max_bank -= PINS_PER_BANK; - if (max_bank == 0) - { - mask |= 1; - } - } while (max_bank); - return mask; + uint32_t max_bank = (uint32_t)GPIO_MAX_BANK; + uint32_t mask = 0; + do + { + mask |= 1 << (max_bank / PINS_PER_BANK); + max_bank -= PINS_PER_BANK; + if (max_bank == 0) + { + mask |= 1; + } + } while (max_bank); + return mask; } static struct gpio_desc *pin_to_gpio_desc(gpio_pin_t pin) { - if (pin < BANK_BOUNDARY) /* CPUX domain */ - { - return (struct gpio_desc *)g_gpio_desc[0]; - } - else /* CPUS domain */ - { - return (struct gpio_desc *)g_gpio_desc[1]; - } - return NULL; + if (pin < BANK_BOUNDARY) /* CPUX domain */ + { + return (struct gpio_desc *)g_gpio_desc[0]; + } + else /* CPUS domain */ + { + return (struct gpio_desc *)g_gpio_desc[1]; + } + return NULL; } static struct gpio_desc *irq_to_gpio_desc(uint32_t irq) { - int i, j; - struct gpio_desc *gpio_desc; - for (i = 0; g_gpio_desc[i] != NULL; i++) - { - gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; - for (j = 0; j < gpio_desc->irq_arry_size; j++) - { - if (gpio_desc->irq[j] == irq) - { - return gpio_desc; - } - } - } - GPIO_ERR("gpio to irq error!"); - return NULL; + int i, j; + struct gpio_desc *gpio_desc; + for (i = 0; g_gpio_desc[i] != NULL; i++) + { + gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; + for (j = 0; j < gpio_desc->irq_arry_size; j++) + { + if (gpio_desc->irq[j] == irq) + { + return gpio_desc; + } + } + } + GPIO_ERR("gpio to irq error!"); + return NULL; } static struct gpio_desc *virq_to_gpio_desc(uint32_t irq) { - int i, j; - struct gpio_desc *gpio_desc; - for (i = 0; g_gpio_desc[i] != NULL; i++) - { - gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; - for (j = 0; j < gpio_desc->irq_banks * IRQ_PER_BANK; j++) - { - if (gpio_desc->irq_desc[j].virq == irq) - { - return gpio_desc; - } - } - } - GPIO_ERR("gpio to virq error!"); - return NULL; + int i, j; + struct gpio_desc *gpio_desc; + for (i = 0; g_gpio_desc[i] != NULL; i++) + { + gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; + for (j = 0; j < gpio_desc->irq_banks * IRQ_PER_BANK; j++) + { + if (gpio_desc->irq_desc[j].virq == irq) + { + return gpio_desc; + } + } + } + GPIO_ERR("gpio to virq error!"); + return NULL; } static void gpio_irq_ack(struct gpio_desc *gpio_desc, int i) { - struct gpio_irq_desc *dirq = &gpio_desc->irq_desc[i]; - uint32_t hw_irq = dirq->virq - gpio_desc->virq_offset - GPIO_IRQ_START; - unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; - uint32_t reg = gpio_irq_status_reg(hw_irq, bank_base); - uint32_t status_idx = gpio_irq_status_offset(hw_irq); - - /* clear the pending */ - hal_writel(1 << status_idx, gpio_desc->membase + reg); + struct gpio_irq_desc *dirq = &gpio_desc->irq_desc[i]; + uint32_t hw_irq = dirq->virq - gpio_desc->virq_offset - GPIO_IRQ_START; + unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; + uint32_t reg = gpio_irq_status_reg(hw_irq, bank_base); + uint32_t status_idx = gpio_irq_status_offset(hw_irq); + + /* clear the pending */ + hal_writel(1 << status_idx, gpio_desc->membase + reg); } static hal_irqreturn_t bad_gpio_irq_handle(void *data) { - GPIO_INFO("No irq registered handler for this calling !!"); - return 0; + GPIO_INFO("No irq registered handler for this calling !!"); + return 0; } static void gpio_irq_set_type(struct gpio_desc *gpio_desc, int irq_num, unsigned long type) { - struct gpio_irq_desc *dirq = &gpio_desc->irq_desc[irq_num]; - uint32_t hw_irq = dirq->virq - gpio_desc->virq_offset - GPIO_IRQ_START; - unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; - uint32_t reg = gpio_irq_cfg_reg(hw_irq, bank_base); - uint32_t index = gpio_irq_cfg_offset(hw_irq); - uint32_t mode, regval; - - switch (type) - { - case IRQ_TYPE_EDGE_RISING: - mode = IRQ_EDGE_RISING; - break; - case IRQ_TYPE_EDGE_FALLING: - mode = IRQ_EDGE_FALLING; - break; - case IRQ_TYPE_EDGE_BOTH: - mode = IRQ_EDGE_BOTH; - break; - case IRQ_TYPE_LEVEL_HIGH: - mode = IRQ_LEVEL_HIGH; - break; - case IRQ_TYPE_LEVEL_LOW: - mode = IRQ_LEVEL_LOW; - break; - default: - mode = IRQ_EDGE_RISING; - } - /*should use spin lock protect here*/ - regval = hal_readl(gpio_desc->membase + reg); - regval &= ~(IRQ_CFG_IRQ_MASK << index); - hal_writel(regval | (mode << index), gpio_desc->membase + reg); - - //regval = hal_readl(gpio_desc->membase + reg); - //GPIO_ERR("gpio_desc->membase + reg: 0x%x\n", regval); + struct gpio_irq_desc *dirq = &gpio_desc->irq_desc[irq_num]; + uint32_t hw_irq = dirq->virq - gpio_desc->virq_offset - GPIO_IRQ_START; + unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; + uint32_t reg = gpio_irq_cfg_reg(hw_irq, bank_base); + uint32_t index = gpio_irq_cfg_offset(hw_irq); + uint32_t mode, regval; + + switch (type) + { + case IRQ_TYPE_EDGE_RISING: + mode = IRQ_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + mode = IRQ_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + mode = IRQ_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + mode = IRQ_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + mode = IRQ_LEVEL_LOW; + break; + default: + mode = IRQ_EDGE_RISING; + } + /*should use spin lock protect here*/ + regval = hal_readl(gpio_desc->membase + reg); + regval &= ~(IRQ_CFG_IRQ_MASK << index); + hal_writel(regval | (mode << index), gpio_desc->membase + reg); + + //regval = hal_readl(gpio_desc->membase + reg); + //GPIO_ERR("gpio_desc->membase + reg: 0x%x\n", regval); } static hal_irqreturn_t gpio_irq_handle(void *data) { - uint32_t hwirq = *((uint32_t *)data); - uint32_t bank, reg, val, base_bank; - struct gpio_desc *gpio_desc = irq_to_gpio_desc(hwirq); - - if (gpio_desc == NULL) - { - return 0; - } - - for (bank = 0; bank < gpio_desc->irq_banks; bank ++) - { - if (hwirq == gpio_desc->irq[bank]) - { - break; - } - } - - if (bank == gpio_desc->irq_banks) - { - return 0; - } - - base_bank = gpio_desc->irq_bank_base[bank]; - reg = gpio_irq_status_reg_from_bank(bank, base_bank); - val = hal_readl(gpio_desc->membase + reg); - GPIO_INFO("hwirq = %ld, gpio_desc address is 0x%lx.", hwirq, gpio_desc->membase); - GPIO_INFO("base_bank is %ld, hwirq is %ld, val is %ld.", base_bank, hwirq, val); - if (val) - { - uint32_t irqoffset; - uint32_t irq_pin; - int i; - for (irqoffset = 0; irqoffset < IRQ_PER_BANK; irqoffset++) - { - if ((1 << irqoffset) & val) - { - break; - } - } - - if (irqoffset >= IRQ_PER_BANK) - { - GPIO_INFO("return"); - return 0; - } - irq_pin = ((base_bank + bank) * IRQ_PER_BANK) + irqoffset + gpio_desc->virq_offset; - - for (i = 0; i < gpio_desc->irq_desc_size; i++) - { - if (irq_pin == gpio_desc->irq_desc[i].pin) - { - break; - } - } - if (i >= gpio_desc->irq_desc_size) - { - return 0; - } - gpio_desc->irq_desc[i].handle_irq(gpio_desc->irq_desc[i].data); - gpio_irq_ack(gpio_desc, i); - } - return 0; + uint32_t hwirq = *((uint32_t *)data); + uint32_t bank, reg, val, base_bank; + struct gpio_desc *gpio_desc = irq_to_gpio_desc(hwirq); + + if (gpio_desc == NULL) + { + return 0; + } + + for (bank = 0; bank < gpio_desc->irq_banks; bank ++) + { + if (hwirq == gpio_desc->irq[bank]) + { + break; + } + } + + if (bank == gpio_desc->irq_banks) + { + return 0; + } + + base_bank = gpio_desc->irq_bank_base[bank]; + reg = gpio_irq_status_reg_from_bank(bank, base_bank); +#ifdef CONFIG_AMP_SHARE_IRQ + uint32_t banks_mask = sunxi_get_banks_mask(gpio_desc->irq[bank]); + val = hal_readl(gpio_desc->membase + reg) & banks_mask; +#else + val = hal_readl(gpio_desc->membase + reg); +#endif + GPIO_INFO("hwirq = %ld, gpio_desc address is 0x%lx.", hwirq, gpio_desc->membase); + GPIO_INFO("base_bank is %ld, hwirq is %ld, val is %ld.", base_bank, hwirq, val); + if (val) + { + uint32_t irqoffset; + uint32_t irq_pin; + int i; + for (irqoffset = 0; irqoffset < IRQ_PER_BANK; irqoffset++) + { + if ((1 << irqoffset) & val) + { + break; + } + } + + if (irqoffset >= IRQ_PER_BANK) + { + GPIO_INFO("return"); + return 0; + } + irq_pin = ((base_bank + bank) * IRQ_PER_BANK) + irqoffset + gpio_desc->virq_offset; + + for (i = 0; i < gpio_desc->irq_desc_size; i++) + { + if (irq_pin == gpio_desc->irq_desc[i].pin) + { + break; + } + } + if (i >= gpio_desc->irq_desc_size) + { + return 0; + } + gpio_desc->irq_desc[i].handle_irq(gpio_desc->irq_desc[i].data); + gpio_irq_ack(gpio_desc, i); + } + return 0; } bool hal_gpio_check_valid(gpio_pin_t pin) { - uint32_t bank = pin / PINS_PER_BANK; - uint32_t mask = count_gpio_bank_mask(); - if (!((1 << bank) & mask)) - { - return false; - } - return true; + uint32_t bank = pin / PINS_PER_BANK; + uint32_t mask = count_gpio_bank_mask(); + if (!((1 << bank) & mask)) + { + return false; + } + return true; } static int gpio_conf_set(gpio_pin_t pin, unsigned long *gpio_config) { - struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); - if (gpio_desc == NULL) - { - GPIO_ERR("gpio_desc is not inited"); - return -1; - } - unsigned long config = (unsigned long)gpio_config; - uint32_t offset, shift, mask, reg; - uint32_t arg; - pin_config_param_t param; - int ret; - - param = pinconf_to_config_param(config); - arg = pinconf_to_config_argument(config); - - ret = gpio_pconf_reg(pin, param, &offset, &shift, &mask); - if (ret < 0) - { - GPIO_ERR("can't get reg for pin %u", pin); - return -1; - } - /* fix me: shuold we keep spin_lock to protect here?*/ - reg = hal_readl(gpio_desc->membase + offset); - reg &= ~(mask << shift); - hal_writel(reg | arg << shift, gpio_desc->membase + offset); - return 0; + struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); + if (gpio_desc == NULL) + { + GPIO_ERR("gpio_desc is not inited"); + return -1; + } + unsigned long config = (unsigned long)gpio_config; + uint32_t offset, shift, mask, reg; + uint32_t arg; + pin_config_param_t param; + int ret; + + param = pinconf_to_config_param(config); + arg = pinconf_to_config_argument(config); + + ret = gpio_pconf_reg(pin, param, &offset, &shift, &mask); + if (ret < 0) + { + GPIO_ERR("can't get reg for pin %u", pin); + return -1; + } + /* fix me: shuold we keep spin_lock to protect here?*/ + reg = hal_readl(gpio_desc->membase + offset); + reg &= ~(mask << shift); + hal_writel(reg | arg << shift, gpio_desc->membase + offset); + return 0; } static int gpio_conf_get(gpio_pin_t pin, unsigned long *gpio_config) { - struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); - if (gpio_desc == NULL) - { - GPIO_ERR("gpio_desc is not inited"); - return -1; - } - uint32_t offset, shift, mask; - uint32_t arg, val; - pin_config_param_t param = pinconf_to_config_param(*gpio_config); - int ret = 0; - - ret = gpio_pconf_reg(pin, param, &offset, &shift, &mask); - if (ret < 0) - { - GPIO_ERR("can't get reg for pin %u", pin); - return -1; - } - - val = (hal_readl(gpio_desc->membase + offset) >> shift) & mask; - switch (param) - { - case GPIO_TYPE_DRV: - case GPIO_TYPE_DAT: - case GPIO_TYPE_PUD: - case GPIO_TYPE_FUNC: - arg = val; - break; - default: - ret = -1; - GPIO_ERR("Invalid mux type"); - return -1; - } - if (!ret) - { - *gpio_config = pinconf_to_config_packed(param, arg); - } - return ret; + struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); + if (gpio_desc == NULL) + { + GPIO_ERR("gpio_desc is not inited"); + return -1; + } + uint32_t offset, shift, mask; + uint32_t arg, val; + pin_config_param_t param = pinconf_to_config_param(*gpio_config); + int ret = 0; + + ret = gpio_pconf_reg(pin, param, &offset, &shift, &mask); + if (ret < 0) + { + GPIO_ERR("can't get reg for pin %u", pin); + return -1; + } + + val = (hal_readl(gpio_desc->membase + offset) >> shift) & mask; + switch (param) + { + case GPIO_TYPE_DRV: + case GPIO_TYPE_DAT: + case GPIO_TYPE_PUD: + case GPIO_TYPE_FUNC: + arg = val; + break; + default: + ret = -1; + GPIO_ERR("Invalid mux type"); + return -1; + } + if (!ret) + { + *gpio_config = pinconf_to_config_packed(param, arg); + } + return ret; } int hal_gpio_get_data(gpio_pin_t pin, gpio_data_t *data) { - unsigned long config; - int ret = 0; - - if (NULL == data) - { - ret = -1; - GPIO_ERR("Invalid parameter!"); - return ret; - } - - config = GPIO_CFG_PACK(GPIO_TYPE_DAT, 0xffffff); - ret = gpio_conf_get(pin, &config); - if (ret < 0) - { - GPIO_ERR("get conf error!"); - return ret; - } - - *data = GPIO_CFG_UNPACK_VALUE(config); - - return ret; + unsigned long config; + int ret = 0; + + if (NULL == data) + { + ret = -1; + GPIO_ERR("Invalid parameter!"); + return ret; + } + + config = GPIO_CFG_PACK(GPIO_TYPE_DAT, 0xffffff); + ret = gpio_conf_get(pin, &config); + if (ret < 0) + { + GPIO_ERR("get conf error!"); + return ret; + } + + *data = GPIO_CFG_UNPACK_VALUE(config); + + return ret; } int hal_gpio_set_data(gpio_pin_t pin, gpio_data_t data) { - unsigned long config; - int ret = 0; - - config = GPIO_CFG_PACK(GPIO_TYPE_DAT, data); - ret = gpio_conf_set(pin, (unsigned long *)config); - if (ret < 0) - { - GPIO_ERR("set conf error!"); - return ret; - } - return ret; + unsigned long config; + int ret = 0; + + config = GPIO_CFG_PACK(GPIO_TYPE_DAT, data); + ret = gpio_conf_set(pin, (unsigned long *)config); + if (ret < 0) + { + GPIO_ERR("set conf error!"); + return ret; + } + return ret; } int hal_gpio_set_direction(gpio_pin_t pin, gpio_direction_t direction) { - unsigned long config; - int ret = 0; - - config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, direction); - ret = gpio_conf_set(pin, (unsigned long *)config); - if (ret < 0) - { - GPIO_ERR("set conf error!"); - return ret; - } - return ret; + unsigned long config; + int ret = 0; + + config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, direction); + ret = gpio_conf_set(pin, (unsigned long *)config); + if (ret < 0) + { + GPIO_ERR("set conf error!"); + return ret; + } + return ret; } int hal_gpio_get_direction(gpio_pin_t pin, gpio_direction_t *direction) { - unsigned long config; - int ret = 0; - - if (NULL == direction) - { - ret = -1; - GPIO_ERR("Invalid parameter!"); - return ret; - } - config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, 0xffffff); - ret = gpio_conf_get(pin, &config); - if (ret < 0) - { - GPIO_ERR("get conf error!"); - return ret; - } - - *direction = GPIO_CFG_UNPACK_VALUE(config); - - return ret; + unsigned long config; + int ret = 0; + + if (NULL == direction) + { + ret = -1; + GPIO_ERR("Invalid parameter!"); + return ret; + } + config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, 0xffffff); + ret = gpio_conf_get(pin, &config); + if (ret < 0) + { + GPIO_ERR("get conf error!"); + return ret; + } + + *direction = GPIO_CFG_UNPACK_VALUE(config); + + return ret; } int hal_gpio_set_pull(gpio_pin_t pin, gpio_pull_status_t pull) { - unsigned long config; - int ret = 0; - - config = GPIO_CFG_PACK(GPIO_TYPE_PUD, pull); - ret = gpio_conf_set(pin, (unsigned long *)config); - if (ret < 0) - { - GPIO_ERR("set conf error!"); - return ret; - } - return ret; + unsigned long config; + int ret = 0; + + config = GPIO_CFG_PACK(GPIO_TYPE_PUD, pull); + ret = gpio_conf_set(pin, (unsigned long *)config); + if (ret < 0) + { + GPIO_ERR("set conf error!"); + return ret; + } + return ret; } int hal_gpio_get_pull(gpio_pin_t pin, gpio_pull_status_t *pull) { - unsigned long config; - int ret = 0; - - if (NULL == pull) - { - ret = -1; - GPIO_ERR("Invalid parameter!"); - return ret; - } - config = GPIO_CFG_PACK(GPIO_TYPE_PUD, 0xffffff); - ret = gpio_conf_get(pin, &config); - if (ret < 0) - { - GPIO_ERR("get conf error!"); - return ret; - } - - *pull = GPIO_CFG_UNPACK_VALUE(config); - - return ret; + unsigned long config; + int ret = 0; + + if (NULL == pull) + { + ret = -1; + GPIO_ERR("Invalid parameter!"); + return ret; + } + config = GPIO_CFG_PACK(GPIO_TYPE_PUD, 0xffffff); + ret = gpio_conf_get(pin, &config); + if (ret < 0) + { + GPIO_ERR("get conf error!"); + return ret; + } + + *pull = GPIO_CFG_UNPACK_VALUE(config); + + return ret; } int hal_gpio_set_driving_level(gpio_pin_t pin, gpio_driving_level_t level) { - unsigned long config; - int ret = 0; - - config = GPIO_CFG_PACK(GPIO_TYPE_DRV, level); - ret = gpio_conf_set(pin, (unsigned long *)config); - if (ret < 0) - { - GPIO_ERR("set conf error!"); - return ret; - } - return ret; + unsigned long config; + int ret = 0; + + config = GPIO_CFG_PACK(GPIO_TYPE_DRV, level); + ret = gpio_conf_set(pin, (unsigned long *)config); + if (ret < 0) + { + GPIO_ERR("set conf error!"); + return ret; + } + return ret; } int hal_gpio_get_driving_level(gpio_pin_t pin, gpio_driving_level_t *level) { - unsigned long config; - int ret = 0; - - if (NULL == level) - { - ret = -1; - GPIO_ERR("Invalid parameter!"); - return ret; - } - config = GPIO_CFG_PACK(GPIO_TYPE_DRV, 0xffffff); - ret = gpio_conf_get(pin, &config); - if (ret < 0) - { - GPIO_ERR("get conf error!"); - return ret; - } - - *level = GPIO_CFG_UNPACK_VALUE(config); - - return ret; + unsigned long config; + int ret = 0; + + if (NULL == level) + { + ret = -1; + GPIO_ERR("Invalid parameter!"); + return ret; + } + config = GPIO_CFG_PACK(GPIO_TYPE_DRV, 0xffffff); + ret = gpio_conf_get(pin, &config); + if (ret < 0) + { + GPIO_ERR("get conf error!"); + return ret; + } + + *level = GPIO_CFG_UNPACK_VALUE(config); + + return ret; } int hal_gpio_pinmux_set_function(gpio_pin_t pin, gpio_muxsel_t function_index) { - unsigned long config; - int ret = 0; - - config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, function_index); - ret = gpio_conf_set(pin, (unsigned long *)config); - if (ret < 0) - { - GPIO_ERR("set pin mux error!"); - return ret; - } - return ret; + unsigned long config; + int ret = 0; + + config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, function_index); + ret = gpio_conf_set(pin, (unsigned long *)config); + if (ret < 0) + { + GPIO_ERR("set pin mux error!"); + return ret; + } + return ret; } int hal_gpio_pinmux_get_function(gpio_pin_t pin, gpio_muxsel_t *function_index) { - unsigned long config; - int ret = 0; - - if (NULL == function_index) - { - ret = -1; - GPIO_ERR("Invalid parameter!"); - return ret; - } - config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, 0xffffff); - ret = gpio_conf_get(pin, &config); - if (ret < 0) - { - GPIO_ERR("get conf error!"); - return ret; - } - - *function_index = GPIO_CFG_UNPACK_VALUE(config); - - return ret; + unsigned long config; + int ret = 0; + + if (NULL == function_index) + { + ret = -1; + GPIO_ERR("Invalid parameter!"); + return ret; + } + config = GPIO_CFG_PACK(GPIO_TYPE_FUNC, 0xffffff); + ret = gpio_conf_get(pin, &config); + if (ret < 0) + { + GPIO_ERR("get conf error!"); + return ret; + } + + *function_index = GPIO_CFG_UNPACK_VALUE(config); + + return ret; +} + +/* + * 1.8 -> 3.3: + * 1. Increase withstand + * 2. Increase power voltage + * 3.3 -> 1.8: + * 1. Decrease power voltage + * 2. Decrease withstand + */ +static void hal_gpio_power_switch_pf(struct gpio_desc *gpio_desc, u32 tar_vol, u32 pow_sel) +{ + u32 cur_vol; + + cur_vol = hal_readl(gpio_desc->membase + POWER_VOL_SEL) & BIT(0); + tar_vol &= BIT(0); + + if (cur_vol < tar_vol) { + hal_writel(pow_sel, gpio_desc->membase + POWER_MODE_SEL); + hal_writel(tar_vol, gpio_desc->membase + POWER_VOL_SEL); + } else if (cur_vol > tar_vol) { + hal_writel(tar_vol, gpio_desc->membase + POWER_VOL_SEL); + hal_writel(pow_sel, gpio_desc->membase + POWER_MODE_SEL); + } else { + hal_writel(pow_sel, gpio_desc->membase + POWER_MODE_SEL); + } } int hal_gpio_sel_vol_mode(gpio_pin_t pin, gpio_power_mode_t pm_sel) { - uint32_t bank, temp; - struct gpio_desc *gpio_desc; - - gpio_desc = pin_to_gpio_desc(pin); - - if (gpio_desc == NULL) - { - return -1; - } - - bank = (pin - gpio_desc->pin_base) / PINS_PER_BANK; - temp = hal_readl(gpio_desc->membase + POWER_MODE_SEL); - temp |= (pm_sel << bank); - hal_writel(temp, gpio_desc->membase + POWER_MODE_SEL); - - if (bank == 5) - { - temp = hal_readl(gpio_desc->membase + POWER_VOL_SEL); - temp &= ~(1 >> 0); - temp |= (!pm_sel); - hal_writel(temp, gpio_desc->membase + POWER_VOL_SEL); - } - - return 0; + uint32_t bank, temp; + struct gpio_desc *gpio_desc; + + gpio_desc = pin_to_gpio_desc(pin); + + if (gpio_desc == NULL) + { + return -1; + } + + bank = (pin - gpio_desc->pin_base) / PINS_PER_BANK; + temp = hal_readl(gpio_desc->membase + POWER_MODE_SEL); + temp &= ~(1 << bank); + temp |= (pm_sel << bank); + + if (bank == 5) + hal_gpio_power_switch_pf(gpio_desc, ~pm_sel, temp); + else + hal_writel(temp, gpio_desc->membase + POWER_MODE_SEL); + + return 0; } int hal_gpio_set_debounce(gpio_pin_t pin, unsigned value) { - uint32_t irq, hw_irq, reg, reg_val; - struct gpio_desc *gpio_desc; - unsigned bank_base; - unsigned int val_clk_select, val_clk_per_scale; - int ret = 0; + uint32_t irq, hw_irq, reg, reg_val; + struct gpio_desc *gpio_desc; + unsigned bank_base; + unsigned int val_clk_select, val_clk_per_scale; + int ret = 0; - gpio_desc = pin_to_gpio_desc(pin); + gpio_desc = pin_to_gpio_desc(pin); - if (gpio_desc == NULL) - { - return -1; - } + if (gpio_desc == NULL) + { + return -1; + } - ret = hal_gpio_to_irq(pin, &irq); + ret = hal_gpio_to_irq(pin, &irq); - if (ret < 0) - { - GPIO_ERR("gpio to irq error"); - return -1; - } + if (ret < 0) + { + GPIO_ERR("gpio to irq error"); + return -1; + } - hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; - bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; - reg = gpio_irq_debounce_reg(hw_irq, bank_base); + hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; + bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; + reg = gpio_irq_debounce_reg(hw_irq, bank_base); - reg_val = hal_readl(gpio_desc->membase + reg); - val_clk_select = value & 1; - val_clk_per_scale = (value >> 4) & 0x07; + reg_val = hal_readl(gpio_desc->membase + reg); + val_clk_select = value & 1; + val_clk_per_scale = (value >> 4) & 0x07; - /*set debounce pio interrupt clock select */ - reg_val &= ~(1 << 0); - reg_val |= val_clk_select; + /*set debounce pio interrupt clock select */ + reg_val &= ~(1 << 0); + reg_val |= val_clk_select; - /* set debounce clock pre scale */ - reg_val &= ~(7 << 4); - reg_val |= val_clk_per_scale << 4; - hal_writel(reg_val, gpio_desc->membase + reg); + /* set debounce clock pre scale */ + reg_val &= ~(7 << 4); + reg_val |= val_clk_per_scale << 4; + hal_writel(reg_val, gpio_desc->membase + reg); - return 0; + return 0; } int hal_gpio_to_irq(gpio_pin_t pin, uint32_t *irq) { - int i = 0; - struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); - - for (i = 0; i < gpio_desc->irq_banks * IRQ_PER_BANK; i++) - { - if (pin != gpio_desc->irq_desc[i].pin) - { - continue; - } - GPIO_INFO("gpio %lu to irq %lu succeed!", pin, gpio_desc->irq_desc[i].virq); - *irq = gpio_desc->irq_desc[i].virq; - return 0; - } - - return -1; + int i = 0; + struct gpio_desc *gpio_desc = pin_to_gpio_desc(pin); + + for (i = 0; i < gpio_desc->irq_banks * IRQ_PER_BANK; i++) + { + if (pin != gpio_desc->irq_desc[i].pin) + { + continue; + } + GPIO_INFO("gpio %lu to irq %lu succeed!", pin, gpio_desc->irq_desc[i].virq); + *irq = gpio_desc->irq_desc[i].virq; + return 0; + } + + return -1; } int hal_gpio_irq_request(uint32_t irq, hal_irq_handler_t hdle, unsigned long flags, void *data) { - struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); - GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); - int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; - int ret = 0; - - irq -= gpio_desc->virq_offset; - - if (irq >= GPIO_IRQ_START && irq < irq_max_num) - { - if (hdle && gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq == bad_gpio_irq_handle) - { - gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq = hdle; - gpio_desc->irq_desc[irq - GPIO_IRQ_START].flags = flags; - gpio_desc->irq_desc[irq - GPIO_IRQ_START].data = data; - } - /*set irq tpye*/ - gpio_irq_set_type(gpio_desc, irq - GPIO_IRQ_START, flags); - - /*set pin mux*/ - ret = hal_gpio_pinmux_set_function(gpio_desc->irq_desc[irq - GPIO_IRQ_START].pin, GPIO_MUXSEL_EINT); - - if (ret < 0) - { - GPIO_ERR("set pin mux error!"); - return -1; - } - GPIO_INFO("request irq %lu succeed!", irq); - return irq; - } - - GPIO_ERR("Wrong irq NO.(%u) to request !!", (unsigned int)irq); - return -1; + struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); + GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); + int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; + int ret = 0; +#ifdef CONFIG_AMP_SHARE_IRQ + uint32_t hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; + uint32_t bank_mask; +#endif + irq -= gpio_desc->virq_offset; + +#ifdef CONFIG_AMP_SHARE_IRQ + bank_mask = sunxi_get_banks_mask(gpio_desc->irq[hw_irq / IRQ_PER_BANK]); + bank_mask &= (1 << hw_irq); + if (!bank_mask) { + GPIO_ERR("irq%d not belong to this chip,hwirq %d, mask=0x%lx\n", irq, + gpio_desc->irq[hw_irq / IRQ_PER_BANK], + sunxi_get_banks_mask(gpio_desc->irq[hw_irq / IRQ_PER_BANK])); + return -1; + } +#endif + if (irq >= GPIO_IRQ_START && irq < irq_max_num) + { + if (hdle && gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq == bad_gpio_irq_handle) + { + gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq = hdle; + gpio_desc->irq_desc[irq - GPIO_IRQ_START].flags = flags; + gpio_desc->irq_desc[irq - GPIO_IRQ_START].data = data; + } + /*set irq tpye*/ + gpio_irq_set_type(gpio_desc, irq - GPIO_IRQ_START, flags); + + /*set pin mux*/ + ret = hal_gpio_pinmux_set_function(gpio_desc->irq_desc[irq - GPIO_IRQ_START].pin, GPIO_MUXSEL_EINT); + + if (ret < 0) + { + GPIO_ERR("set pin mux error!"); + return -1; + } + GPIO_INFO("request irq %lu succeed!", irq); + return irq; + } + + GPIO_ERR("Wrong irq NO.(%u) to request !!", (unsigned int)irq); + return -1; } int hal_gpio_irq_free(uint32_t irq) { - struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); - int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; - irq -= gpio_desc->virq_offset; - if (irq >= GPIO_IRQ_START && irq < irq_max_num) - { - gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq = bad_gpio_irq_handle; - gpio_desc->irq_desc[irq - GPIO_IRQ_START].flags = 0; - gpio_desc->irq_desc[irq - GPIO_IRQ_START].data = NULL; - GPIO_INFO("free irq %lu succeed!", irq); - return irq; - } - - GPIO_ERR("Wrong irq NO.(%u) to free !!", (unsigned int)irq); - return -1; + struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); + int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; + irq -= gpio_desc->virq_offset; + if (irq >= GPIO_IRQ_START && irq < irq_max_num) + { + gpio_desc->irq_desc[irq - GPIO_IRQ_START].handle_irq = bad_gpio_irq_handle; + gpio_desc->irq_desc[irq - GPIO_IRQ_START].flags = 0; + gpio_desc->irq_desc[irq - GPIO_IRQ_START].data = NULL; + GPIO_INFO("free irq %lu succeed!", irq); + return irq; + } + + GPIO_ERR("Wrong irq NO.(%u) to free !!", (unsigned int)irq); + return -1; } int hal_gpio_irq_enable(uint32_t irq) { - struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); - GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); - int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; - uint32_t hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; - unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; - uint32_t reg = gpio_irq_ctrl_reg(hw_irq, bank_base); - uint32_t index = gpio_irq_ctrl_offset(hw_irq); - uint32_t val = 0; - - irq -= gpio_desc->virq_offset; - - if (irq < GPIO_IRQ_START || irq >= irq_max_num) - { - GPIO_ERR("Wrong irq NO.(%u) to enable !!", (unsigned int)irq); - return -1; - } - - /*clear pending*/ - gpio_irq_ack(gpio_desc, hw_irq); - - /*unmask the irq,should keep spin lock to protect*/ - val = hal_readl(gpio_desc->membase + reg); - hal_writel(val | (1 << index), gpio_desc->membase + reg); - return 0; + struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); + GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); + int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; + uint32_t hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; + unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; + uint32_t reg = gpio_irq_ctrl_reg(hw_irq, bank_base); + uint32_t index = gpio_irq_ctrl_offset(hw_irq); + uint32_t val = 0; + + irq -= gpio_desc->virq_offset; + + if (irq < GPIO_IRQ_START || irq >= irq_max_num) + { + GPIO_ERR("Wrong irq NO.(%u) to enable !!", (unsigned int)irq); + return -1; + } + + /*clear pending*/ + gpio_irq_ack(gpio_desc, hw_irq); + + /*unmask the irq,should keep spin lock to protect*/ + val = hal_readl(gpio_desc->membase + reg); + hal_writel(val | (1 << index), gpio_desc->membase + reg); + return 0; } #ifdef CONFIG_STANDBY struct gpio_pm_reg_cache gpio_pm_reg; @@ -957,110 +1004,221 @@ int hal_gpio_resume() return 0; } -#else +#endif +#ifdef CONFIG_COMPONENTS_PM +struct gpio_pm_reg_cache gpio_pm_reg; + static int gpio_pm_alloc_mem(uint32_t desc_index, uint32_t mem_size) { + if (desc_index > 1) + { + GPIO_ERR("index[%d] exceed desc_index range!", desc_index); + return -1; + } + + gpio_pm_reg.reg_dump[desc_index] = hal_malloc(mem_size); + if (gpio_pm_reg.reg_dump[desc_index] == NULL) + { + GPIO_ERR("malloc reg_mem[%d] error!", desc_index); + return -1; + } + + gpio_pm_reg.reg_dump_size[desc_index] = mem_size; + + return 0; +} + +static int hal_gpio_suspend(struct pm_device *dev, suspend_mode_t mode) +{ + int i; + void *mem = NULL; + uint32_t mem_size; + uint32_t flags; + struct gpio_desc *gpio_desc = NULL; + + flags = hal_interrupt_save(); + for (i = 0; g_gpio_desc[i] != NULL; i++) { + gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; + mem = gpio_pm_reg.reg_dump[i]; + mem_size = gpio_pm_reg.reg_dump_size[i]; + if (mem != NULL) + memcpy(mem, (uint32_t *)gpio_desc->membase, mem_size); + } + hal_interrupt_restore(flags); + + printf("gpio suspend end\n"); + return 0; +} + +static int hal_gpio_resume(struct pm_device *dev, suspend_mode_t mode) +{ + int i; + void *mem = NULL; + uint32_t mem_size; + uint32_t flags; + struct gpio_desc *gpio_desc = NULL; + + flags = hal_interrupt_save(); + for (i = 0; g_gpio_desc[i] != NULL; i++) { + gpio_desc = (struct gpio_desc *)g_gpio_desc[i]; + mem = gpio_pm_reg.reg_dump[i]; + mem_size = gpio_pm_reg.reg_dump_size[i]; + if (gpio_pm_reg.reg_dump[i] != NULL) + memcpy((uint32_t *)gpio_desc->membase, mem, mem_size); + } + hal_interrupt_restore(flags); + + printf("gpio resume end\n"); + return 0; } + +struct pm_devops pm_gpio_ops = { + .suspend_noirq = hal_gpio_suspend, + .resume_noirq = hal_gpio_resume, +}; + +struct pm_device pm_gpio = { + .name = "sunxi_gpio", + .ops = &pm_gpio_ops, +}; #endif + int hal_gpio_irq_disable(uint32_t irq) { - struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); - GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); - int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; - uint32_t hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; - unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; - uint32_t reg = gpio_irq_ctrl_reg(hw_irq, bank_base); - uint32_t index = gpio_irq_ctrl_offset(hw_irq); - uint32_t val = 0; - irq -= gpio_desc->virq_offset; - if (irq < GPIO_IRQ_START || irq >= irq_max_num) - { - GPIO_ERR("Wrong irq NO.(%u) to enable !!", (unsigned int)irq); - return -1; - } - - /*mask the irq,should keep spin lock to protect*/ - val = hal_readl(gpio_desc->membase + reg); - hal_writel(val & ~(1 << index), gpio_desc->membase + reg); - return 0; + struct gpio_desc *gpio_desc = virq_to_gpio_desc(irq); + GPIO_INFO("[%s]gpio_desc address is 0x%lx.", __func__, gpio_desc->membase); + int irq_max_num = gpio_desc->irq_desc_size + GPIO_IRQ_START; + uint32_t hw_irq = irq - gpio_desc->virq_offset - GPIO_IRQ_START; + unsigned bank_base = gpio_desc->irq_bank_base[hw_irq / IRQ_PER_BANK]; + uint32_t reg = gpio_irq_ctrl_reg(hw_irq, bank_base); + uint32_t index = gpio_irq_ctrl_offset(hw_irq); + uint32_t val = 0; + irq -= gpio_desc->virq_offset; + if (irq < GPIO_IRQ_START || irq >= irq_max_num) + { + GPIO_ERR("Wrong irq NO.(%u) to enable !!", (unsigned int)irq); + return -1; + } + + /*mask the irq,should keep spin lock to protect*/ + val = hal_readl(gpio_desc->membase + reg); + hal_writel(val & ~(1 << index), gpio_desc->membase + reg); + return 0; } int hal_gpio_init(void) { - int i, j, ret; - struct gpio_desc *gpio_desc = NULL; - struct gpio_irq_desc *irq_desc = NULL; - int irq_desc_array_size = 0; - char irqname[32] = {0}; - - /* initialize g_gpio_desc */ - g_gpio_desc = gpio_get_platform_desc(); - if (g_gpio_desc == NULL) - { - GPIO_ERR("initialize global platform desc failed!"); - return -1; - } - - for (j = 0; g_gpio_desc[j] != NULL; j++) - { - gpio_desc = (struct gpio_desc *)g_gpio_desc[j]; - irq_desc_array_size = gpio_desc->irq_banks * IRQ_PER_BANK; - gpio_desc->irq_desc_size = irq_desc_array_size; - - irq_desc = (struct gpio_irq_desc *)hal_malloc(irq_desc_array_size * sizeof(struct gpio_irq_desc)); - if (irq_desc == NULL) - { - GPIO_ERR("alloc memory failed!"); - return -1; - } - - ret = gpio_pm_alloc_mem(j, gpio_desc->resource_size); - if (ret) + int i, j, ret; + struct gpio_desc *gpio_desc = NULL; + struct gpio_irq_desc *irq_desc = NULL; + int irq_desc_array_size = 0; + char irqname[32] = {0}; + + /* initialize g_gpio_desc */ + g_gpio_desc = gpio_get_platform_desc(); + if (g_gpio_desc == NULL) { - GPIO_ERR("gpio[%d] pm alloc mem err!", j); - return ret; + GPIO_ERR("initialize global platform desc failed!"); + return -1; } - memset(irq_desc, 0, irq_desc_array_size * sizeof(struct gpio_irq_desc)); - for (i = 0; i < irq_desc_array_size; i++) - { - unsigned int j = i / IRQ_PER_BANK; - unsigned int k = i % IRQ_PER_BANK; - unsigned bank_base = gpio_desc->irq_bank_base[j]; - irq_desc[i].pin = gpio_get_pin_base_from_bank(j, bank_base) + gpio_desc->virq_offset + k; - irq_desc[i].virq = GPIO_IRQ_START + gpio_desc->virq_offset + i; - irq_desc[i].handle_irq = bad_gpio_irq_handle; - } - - gpio_desc->irq_desc = irq_desc; - - for (i = 0; i < gpio_desc->irq_banks; i++) - { - /* mask all irq */ - unsigned bank_base = gpio_desc->irq_bank_base[i]; - hal_writel(0, gpio_desc->membase + - gpio_irq_ctrl_reg_from_bank(i, bank_base)); - /* clear pending flags */ - hal_writel(0xffffffff, gpio_desc->membase + - gpio_irq_status_reg_from_bank(i, bank_base)); - } - - /* request irq */ - for (i = 0; i < gpio_desc->irq_arry_size; i++) - { - snprintf(irqname, 32, "gpio-ctl%d%d", j, i); - ret = hal_request_irq(gpio_desc->irq[i], gpio_irq_handle, irqname, (void *)&gpio_desc->irq[i]); - } - - /* enable irq */ - for (i = 0; i < gpio_desc->irq_arry_size; i++) - { - hal_enable_irq(gpio_desc->irq[i]); - } - } - GPIO_INFO("gpio init success!"); - return 0; + for (j = 0; g_gpio_desc[j] != NULL; j++) + { + gpio_desc = (struct gpio_desc *)g_gpio_desc[j]; + irq_desc_array_size = gpio_desc->irq_banks * IRQ_PER_BANK; + gpio_desc->irq_desc_size = irq_desc_array_size; + +#ifdef CONFIG_STANDBY + ret = gpio_pm_alloc_mem(j, gpio_desc->resource_size); + if (ret) + { + GPIO_ERR("gpio[%d] pm alloc mem err!", j); + return ret; + } +#endif +#ifdef CONFIG_COMPONENTS_PM + ret = gpio_pm_alloc_mem(j, gpio_desc->resource_size); + if (ret) + { + GPIO_ERR("gpio[%d] pm alloc mem err!", j); + return ret; + } + pm_devops_register(&pm_gpio); +#endif + + irq_desc = (struct gpio_irq_desc *)hal_malloc(irq_desc_array_size * sizeof(struct gpio_irq_desc)); + if (irq_desc == NULL) + { + GPIO_ERR("alloc memory failed!"); + return -1; + } + + memset(irq_desc, 0, irq_desc_array_size * sizeof(struct gpio_irq_desc)); + for (i = 0; i < irq_desc_array_size; i++) + { + unsigned int j = i / IRQ_PER_BANK; + unsigned int k = i % IRQ_PER_BANK; + unsigned bank_base = gpio_desc->irq_bank_base[j]; + irq_desc[i].pin = gpio_get_pin_base_from_bank(j, bank_base) + gpio_desc->virq_offset + k; + irq_desc[i].virq = GPIO_IRQ_START + gpio_desc->virq_offset + i; + irq_desc[i].handle_irq = bad_gpio_irq_handle; + } + + gpio_desc->irq_desc = irq_desc; + + for (i = 0; i < gpio_desc->irq_banks; i++) + { + /* mask all irq */ + unsigned bank_base = gpio_desc->irq_bank_base[i]; +#ifdef CONFIG_AMP_SHARE_IRQ + uint32_t bank_mask, ctrl_val, sta_val, hw_irq; + unsigned long ctrl_reg, sta_reg; + + ctrl_reg = gpio_desc->membase + gpio_irq_ctrl_reg_from_bank(i, bank_base); + sta_reg = gpio_desc->membase + gpio_irq_status_reg_from_bank(i, bank_base); + + /* get gpio bank mask from share interrupt table */ + bank_mask = sunxi_get_banks_mask(gpio_desc->irq[i]); + ctrl_val = hal_readl(ctrl_reg) & (~bank_mask); + sta_val = 0xffffffff & bank_mask; + + hal_writel(ctrl_val, ctrl_reg); + hal_writel(sta_val, sta_reg); +#else + hal_writel(0, gpio_desc->membase + + gpio_irq_ctrl_reg_from_bank(i, bank_base)); + /* clear pending flags */ + hal_writel(0xffffffff, gpio_desc->membase + + gpio_irq_status_reg_from_bank(i, bank_base)); +#endif + } + + /* request irq */ + for (i = 0; i < gpio_desc->irq_arry_size; i++) + { +#ifdef CONFIG_AMP_SHARE_IRQ + uint32_t bank_mask = sunxi_get_banks_mask(gpio_desc->irq[i]); + if (!bank_mask) + continue; +#endif + snprintf(irqname, 32, "gpio-ctl%d%d", j, i); + ret = hal_request_irq(gpio_desc->irq[i], gpio_irq_handle, irqname, (void *)&gpio_desc->irq[i]); + } + + /* enable irq */ + for (i = 0; i < gpio_desc->irq_arry_size; i++) + { +#ifdef CONFIG_AMP_SHARE_IRQ + uint32_t bank_mask = sunxi_get_banks_mask(gpio_desc->irq[i]); + if (!bank_mask) + continue; +#endif + hal_enable_irq(gpio_desc->irq[i]); + } + } + GPIO_INFO("gpio init success!"); + return 0; } int hal_gpio_r_irq_disable(uint32_t irq) diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/hal_pwm.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/hal_pwm.c old mode 100755 new mode 100644 index 42558cb4..0383adf7 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/hal_pwm.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/hal_pwm.c @@ -64,6 +64,9 @@ #ifdef CONFIG_STANDBY #include #endif +#ifdef CONFIG_COMPONENTS_PM +#include +#endif hal_pwm_t sunxi_pwm; static int pwm_init = 0; @@ -121,7 +124,6 @@ void hal_pwm_clk_div_m(uint32_t channel_in, uint32_t div_m) hal_writel(reg_val, reg_addr); } - void hal_pwm_prescal_set(uint32_t channel_in, uint32_t prescal) { unsigned long reg_addr = PWM_BASE + PWM_PCR; @@ -192,12 +194,38 @@ static uint32_t get_pccr_reg_offset(uint32_t channel) default : PWM_ERR("channel is error \n"); return PWM_PCCR01; + } +} + +static uint32_t get_pdzcr_reg_offset(uint32_t channel) +{ + uint32_t val; + + switch (channel) + { + case 0: + case 1: + return PWM_PDZCR01; + break; + case 2: + case 3: + return PWM_PDZCR23; break; + case 4: + case 5: + return PWM_PDZCR45; + break; + case 6: + case 7: + return PWM_PDZCR67; + break; + default : + PWM_ERR("channel is error \n"); + return -1; } } /************ enable **************/ - void hal_pwm_enable_clk_gating(uint32_t channel_in) { unsigned long reg_addr = PWM_BASE + PWM_PCGR; @@ -229,12 +257,11 @@ void hal_pwm_disable_controller(uint32_t channel_in) unsigned long reg_addr = PWM_BASE + PWM_PER; reg_val = readl(reg_addr); - reg_val |= 1 << channel_in; + reg_val &= 0 << channel_in; writel(reg_val, reg_addr); } - /*************** polarity *****************/ void hal_pwm_porality(uint32_t channel_in, hal_pwm_polarity polarity) { @@ -279,7 +306,7 @@ static int hal_pwm_pinctrl_init(hal_pwm_t sunxi_pwm, int channel) ret = hal_gpio_set_driving_level(sunxi_pwm.pin[channel], gpio_cfg.drv_level); if (ret) { - PWM_ERR("[spi%d] PIN%u set driving level failed! return %d\n", channel, gpio_cfg.drv_level, ret); + PWM_ERR("[pwm%d] PIN%u set driving level failed! return %d\n", channel, gpio_cfg.drv_level, ret); return -1; } @@ -288,6 +315,7 @@ static int hal_pwm_pinctrl_init(hal_pwm_t sunxi_pwm, int channel) return hal_gpio_set_pull(sunxi_pwm.pin[channel], gpio_cfg.pull); } + sunxi_pwm.pin_state[channel] = true; return 0; #else PWM_ERR("[pwm%d] not support in sys_config\n", channel); @@ -307,9 +335,129 @@ static int hal_pwm_pinctrl_exit(hal_pwm_t sunxi_pwm, uint32_t channel) } } -/****the function provide for pwm driverr******************************************/ +#ifdef CONFIG_STANDBY +int hal_pwm_resume(void *dev) +{ + if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) + { + return -1; + } + + if (hal_reset_control_deassert(sunxi_pwm.pwm_reset)) + { + return -1; + } + + if (hal_clock_enable(sunxi_pwm.pwm_bus_clk)) + { + return -1; + } + + PWM_INFO("hal pwm resume"); + return 0; +} + +int hal_pwm_suspend(void *dev) +{ + if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) + { + return -1; + } + + if (hal_clock_disable(sunxi_pwm.pwm_bus_clk)) + { + return -1; + } + + PWM_INFO("hal pwm suspend"); + return 0; +} +#endif + +#ifdef CONFIG_COMPONENTS_PM +static inline void sunxi_pwm_save_regs(hal_pwm_t *pwm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hal_pwm_regs_offset); i++) + pwm->regs_backup[i] = readl(PWM_BASE + hal_pwm_regs_offset[i]); +} + +static inline void sunxi_pwm_restore_regs(hal_pwm_t *pwm) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hal_pwm_regs_offset); i++) + writel(pwm->regs_backup[i], PWM_BASE + hal_pwm_regs_offset[i]); +} + +static int sunxi_pwm_resume(struct pm_device *dev, suspend_mode_t mode) +{ + hal_pwm_t *pwm = &sunxi_pwm; + int i, err; + + hal_reset_control_reset(sunxi_pwm.pwm_reset); + hal_clock_enable(sunxi_pwm.pwm_bus_clk); + + for (i = 0; i < PWM_NUM; i++) + { + if (sunxi_pwm.pin_state[i]) + { + PWM_ERR("the pwm%d is resume\n", i); + sunxi_pwm.pin_state[i] = false; + err = hal_pwm_pinctrl_init(sunxi_pwm, i); + if (err) + { + err = hal_gpio_pinmux_set_function(pwm_gpio[i].pwm_pin, pwm_gpio[i].pwm_function); + if (err) + { + PWM_ERR("pinmux set failed\n"); + return -1; + } + sunxi_pwm.pin_state[i] = true; + } + } + } + + sunxi_pwm_restore_regs(pwm); + + PWM_INFO("hal pwm resume\n"); + return 0; +} + +static int sunxi_pwm_suspend(struct pm_device *dev, suspend_mode_t mode) +{ + hal_pwm_t *pwm = &sunxi_pwm; + int i; + + sunxi_pwm_save_regs(pwm); + + for (i = 0; i < PWM_NUM; i++) + if (sunxi_pwm.pin_state[i]) + hal_pwm_pinctrl_exit(sunxi_pwm, i); + + hal_clock_disable(sunxi_pwm.pwm_bus_clk); + hal_reset_control_assert(sunxi_pwm.pwm_reset); + + PWM_INFO("hal pwm suspend\n"); + return 0; +} + +struct pm_devops pm_pwm_ops = { + .suspend = sunxi_pwm_suspend, + .resume = sunxi_pwm_resume, +}; + +struct pm_device pm_pwm = { + .name = "sunxi_pwm", + .ops = &pm_pwm_ops, +}; +#endif + pwm_status_t hal_pwm_init(void) { + int i; + PWM_INFO("pwm init start"); if (pwm_init) @@ -322,19 +470,16 @@ pwm_status_t hal_pwm_init(void) sunxi_pwm.pwm_bus_clk_id = SUNXI_PWM_CLK_ID; sunxi_pwm.pwm_reset_type = SUNXI_PWM_RESET_TYPE; sunxi_pwm.pwm_reset_id = SUNXI_PWM_RESET_ID; + for (i = 0; i < PWM_NUM; i++) + sunxi_pwm.pin_state[i] = false; if (!sunxi_pwm.pwm_reset) - { sunxi_pwm.pwm_reset = hal_reset_control_get(sunxi_pwm.pwm_reset_type, sunxi_pwm.pwm_reset_id); - } - hal_reset_control_deassert(sunxi_pwm.pwm_reset); + hal_reset_control_reset(sunxi_pwm.pwm_reset); if (!sunxi_pwm.pwm_bus_clk) - { sunxi_pwm.pwm_bus_clk = hal_clock_get(sunxi_pwm.pwm_clk_type, sunxi_pwm.pwm_bus_clk_id); - PWM_INFO("pwm_bus_clk name:%s", sunxi_pwm.pwm_bus_clk->name); - } if (hal_clock_enable(sunxi_pwm.pwm_bus_clk)) { @@ -345,6 +490,10 @@ pwm_status_t hal_pwm_init(void) register_pm_dev_notify(hal_pwm_suspend, hal_pwm_resume, NULL); #endif +#ifdef CONFIG_COMPONENTS_PM + pm_devops_register(&pm_pwm); +#endif + PWM_INFO("pwm init end "); pwm_init++; @@ -353,11 +502,23 @@ pwm_status_t hal_pwm_init(void) pwm_status_t hal_pwm_deinit(void) { + int i; + if (pwm_init) { pwm_init--; if (!pwm_init) { + +#ifdef CONFIG_COMPONENTS_PM + pm_devops_unregister(&pm_pwm); +#endif + for (i = 0; i < PWM_NUM; i++) + { + hal_pwm_pinctrl_exit(sunxi_pwm, i); + sunxi_pwm.pin_state[i] = false; + } + hal_reset_control_assert(sunxi_pwm.pwm_reset); hal_reset_control_put(sunxi_pwm.pwm_reset); @@ -369,10 +530,8 @@ pwm_status_t hal_pwm_deinit(void) return 0; } -pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) +pwm_status_t hal_pwm_control_single(int channel, struct pwm_config *config_pwm) { - PWM_INFO("pwm control start"); - unsigned int temp; unsigned long long c = 0; unsigned long entire_cycles = 256, active_cycles = 192; @@ -383,6 +542,20 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) int32_t clk_osc24m; char pwm_name[16]; int err; + uint32_t pre_scal_id = 0, div_m = 0, prescale = 0; + uint32_t pre_scal[][2] = + { + /* reg_val clk_pre_div */ + {0, 1}, + {1, 2}, + {2, 4}, + {3, 8}, + {4, 16}, + {5, 32}, + {6, 64}, + {7, 128}, + {8, 256}, + }; PWM_INFO("period_ns = %ld", config_pwm->period_ns); PWM_INFO("duty_ns = %ld", config_pwm->duty_ns); @@ -399,7 +572,13 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) err = hal_pwm_pinctrl_init(sunxi_pwm, channel); if (err) { - hal_gpio_pinmux_set_function(pwm_gpio[channel].pwm_pin, pwm_gpio[channel].pwm_function); + err = hal_gpio_pinmux_set_function(pwm_gpio[channel].pwm_pin, pwm_gpio[channel].pwm_function); + if (err) + { + PWM_ERR("pinmux set failed\n"); + return -1; + } + sunxi_pwm.pin_state[channel] = true; } /* pwm enable controller */ @@ -408,22 +587,6 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) /* pwm set polarity */ hal_pwm_porality(channel, config_pwm->polarity); - /* pwm config function */ - uint32_t pre_scal_id = 0, div_m = 0, prescale = 0; - uint32_t pre_scal[][2] = - { - /* reg_val clk_pre_div */ - {0, 1}, - {1, 2}, - {2, 4}, - {3, 8}, - {4, 16}, - {5, 32}, - {6, 64}, - {7, 128}, - {8, 256}, - }; - reg_clk_src_shift = PWM_CLK_SRC_SHIFT; reg_clk_src_width = PWM_CLK_SRC_WIDTH; reg_offset = get_pccr_reg_offset(channel); @@ -442,7 +605,6 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) if (clk_osc24m) { /* if need freq 24M, then direct output 24M clock,set clk_bypass. */ reg_bypass_shift = channel; - reg_offset = get_pccr_reg_offset(channel); temp = hal_readl(PWM_BASE + PWM_PCGR); temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* clk_gating set */ @@ -459,10 +621,14 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) if (config_pwm->period_ns > 0 && config_pwm->period_ns <= 10) { - /* if freq lt 100M, then direct output 100M clock,set by pass. */ +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq lt 96M, then direct output 96M clock,set by pass. */ + c = 96000000; +#else + /* if freq lt 100M, then direct output 100M clock,set by pass. */ c = 100000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ reg_bypass_shift = channel; - reg_offset = get_pccr_reg_offset(channel); temp = hal_readl(PWM_BASE + PWM_PCGR); temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* clk_gating set */ @@ -477,8 +643,13 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) } else if (config_pwm->period_ns > 10 && config_pwm->period_ns <= 334) { - /* if freq between 3M~100M, then select 100M as clock */ +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq between 3M~100M, then select 96M as clock */ + c = 96000000; +#else + /* if freq between 3M~100M, then select 100M as clock */ c = 100000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ /* clk_src_reg : use APB1 clock */ temp = hal_readl(PWM_BASE + reg_offset); @@ -487,8 +658,13 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) } else if (config_pwm->period_ns > 334) { - /* if freq < 3M, then select 24M clock */ +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq < 3M, then select 40M clock */ + c = 40000000; +#else + /* if freq < 3M, then select 24M clock */ c = 24000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ /* clk_src_reg : use OSC24M clock */ temp = hal_readl(PWM_BASE + reg_offset); @@ -569,44 +745,349 @@ pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) temp = SET_BITS(reg_shift, reg_width, temp, (entire_cycles - 1)); hal_writel(temp, PWM_BASE + reg_offset); - PWM_INFO("pwm control end "); + PWM_INFO("pwm control single channel end\n"); return 0; } -pwm_status_t hal_pwm_resume(void) +pwm_status_t hal_pwm_control_dual(int channel, struct pwm_config *config_pwm) { - if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) + unsigned int temp; + unsigned long long c, clk_temp, clk = 0; + unsigned long reg_dead, dead_time = 0, entire_cycles = 256, active_cycles = 192; + unsigned int reg_offset, reg_shift, reg_width; + unsigned int reg_bypass_shift; + unsigned int reg_clk_src_shift, reg_clk_src_width; + unsigned int reg_div_m_shift, reg_div_m_width, value; + int channels[2] = {0}; + int err, i; + uint32_t pre_scal_id = 0, div_m = 0, prescale = 0; + uint32_t pre_scal[][2] = { + /* reg_val clk_pre_div */ + {0, 1}, + {1, 2}, + {2, 4}, + {3, 8}, + {4, 16}, + {5, 32}, + {6, 64}, + {7, 128}, + {8, 256}, + }; + + PWM_INFO("period_ns = %ld", config_pwm->period_ns); + PWM_INFO("duty_ns = %ld", config_pwm->duty_ns); + PWM_INFO("polarity = %d", config_pwm->polarity); + PWM_INFO("channel = %d", channel); + + if ((config_pwm->period_ns < config_pwm->duty_ns) || (!config_pwm->period_ns)) + { + PWM_ERR("paremeter error : period_ns can't greater than duty_ns and period_ns can't be 0\n"); return -1; } - if (hal_reset_control_deassert(sunxi_pwm.pwm_reset)) - { + channels[0] = channel; + channels[1] = pwm_gpio[channel].bind_channel; + dead_time = pwm_gpio[channel].dead_time; + + reg_offset = get_pdzcr_reg_offset(channels[0]); + reg_shift = PWM_DZ_EN_SHIFT; + reg_width = PWM_DZ_EN_WIDTH; + + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_shift, reg_width, temp, 1); + hal_writel(temp, PWM_BASE + reg_offset); + temp = hal_readl(PWM_BASE + reg_offset); + if (config_pwm->duty_ns < dead_time || temp == 0) { + PWM_ERR("duty time or dead zone error\n"); return -1; } - if (hal_clock_enable(sunxi_pwm.pwm_bus_clk)) + for (i = 0; i < PWM_BIND_NUM; i++) { + /* pwm set port */ + err = hal_pwm_pinctrl_init(sunxi_pwm, channels[i]); + if (err) + { + err = hal_gpio_pinmux_set_function(pwm_gpio[channels[i]].pwm_pin, pwm_gpio[channels[i]].pwm_function); + if (err) + { + PWM_ERR("pinmux set failed\n"); + return -1; + } + sunxi_pwm.pin_state[channels[i]] = true; + } + } + + reg_clk_src_shift = PWM_CLK_SRC_SHIFT; + reg_clk_src_width = PWM_CLK_SRC_WIDTH; + + if (config_pwm->period_ns > 0 && config_pwm->period_ns <= 10) { - return -1; +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq lt 96M, then direct output 96M clock,set by pass. */ + clk = 96000000; +#else + /* if freq lt 100M, then direct output 100M clock,set by pass. */ + clk = 100000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ + for (i = 0; i < PWM_BIND_NUM; i++) { + reg_bypass_shift = channels[i]; + reg_offset = get_pccr_reg_offset(channels[i]); + + temp = hal_readl(PWM_BASE + PWM_PCGR); + temp = SET_BITS(reg_bypass_shift, 1, temp, 1); /* clk_gating set */ + temp = SET_BITS(reg_bypass_shift + 16, 1, temp, 1); /* clk_bypass set */ + hal_writel(temp, PWM_BASE + PWM_PCGR); + /* clk_src_reg */ + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1); /* select clock source */ + hal_writel(temp, PWM_BASE + reg_offset); + + return 0; + } + } + else if (config_pwm->period_ns > 10 && config_pwm->period_ns <= 334) + { +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq between 3M~100M, then select 96M as clock */ + clk = 96000000; +#else + /* if freq between 3M~100M, then select 100M as clock */ + clk = 100000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ + + for (i = 0; i < PWM_BIND_NUM; i++) { + reg_offset = get_pccr_reg_offset(channels[i]); + /* clk_src_reg : use APB1 clock */ + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 1); + hal_writel(temp, PWM_BASE + reg_offset); + } + } + else if (config_pwm->period_ns > 334) + { +#if defined(CONFIG_ARCH_SUN20IW2) + /* if freq < 3M, then select 40M clock */ + clk = 40000000; +#else + /* if freq < 3M, then select 24M clock */ + clk = 24000000; +#endif /* CONFIG_ARCH_SUN20IW2 */ + + for (i = 0; i < PWM_BIND_NUM; i++) { + reg_offset = get_pccr_reg_offset(channels[i]); + /* clk_src_reg : use OSC24M clock */ + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_clk_src_shift, reg_clk_src_width, temp, 0); + hal_writel(temp, PWM_BASE + reg_offset); + } } - PWM_INFO("hal pwm resume"); + c = clk * config_pwm->period_ns; + pwm_do_div(c, 1000000000); + entire_cycles = (unsigned long)c; + + clk_temp = clk * dead_time; + pwm_do_div(clk_temp, 1000000000); + reg_dead = (unsigned long)clk_temp; + for (pre_scal_id = 0; pre_scal_id < 9; pre_scal_id++) + { + if (entire_cycles <= 65536 && reg_dead <= 255) + break; + + for (prescale = 0; prescale < PRESCALE_MAX + 1; prescale++) + { + entire_cycles = ((unsigned long)c / pre_scal[pre_scal_id][1]) / (prescale + 1); + reg_dead = clk_temp; + pwm_do_div(reg_dead, pre_scal[pre_scal_id][1] * (prescale + 1)); + if (entire_cycles <= 65536 && reg_dead <= 255) + { + div_m = pre_scal[pre_scal_id][0]; + break; + } + } + } + + c = (unsigned long long)entire_cycles * config_pwm->duty_ns; + pwm_do_div(c, config_pwm->period_ns); + active_cycles = c; + + if (entire_cycles == 0) + entire_cycles++; + + for (i = 0; i < PWM_BIND_NUM; i++) { + reg_offset = get_pccr_reg_offset(channels[i]); + /* config clk div_m */ + reg_div_m_shift = PWM_DIV_M_SHIFT; + reg_div_m_width = PWM_DIV_M_WIDTH; + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_div_m_shift, reg_div_m_width, temp, div_m); + hal_writel(temp, PWM_BASE + reg_offset); + + /* config gating */ +#ifdef CONFIG_ARCH_SUN8IW18P1 + reg_shift = PWM_CLK_GATING_SHIFT; + value = hal_readl(PWM_BASE + reg_offset); + value = SET_BITS(reg_shift, 1, value, 1); /* set gating */ + hal_writel(value, PWM_BASE + reg_offset); +#else + reg_shift = channels[i]; + value = hal_readl(PWM_BASE + PWM_PCGR); + value = SET_BITS(reg_shift, 1, value, 1); /* set gating */ + hal_writel(value, PWM_BASE + PWM_PCGR); +#endif + + /* config prescal */ + reg_offset = PWM_PCR + 0x20 * channels[i]; + reg_shift = PWM_PRESCAL_SHIFT; + reg_width = PWM_PRESCAL_WIDTH; + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_shift, reg_width, temp, prescale); + hal_writel(temp, PWM_BASE + reg_offset); + + /* config active cycles */ + reg_offset = PWM_PPR + 0x20 * channels[i]; + reg_shift = PWM_ACT_CYCLES_SHIFT; + reg_width = PWM_ACT_CYCLES_WIDTH; + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_shift, reg_width, temp, active_cycles); + hal_writel(temp, PWM_BASE + reg_offset); + + /* config period cycles */ + reg_offset = PWM_PPR + 0x20 * channels[i]; + reg_shift = PWM_PERIOD_CYCLES_SHIFT; + reg_width = PWM_PERIOD_CYCLES_WIDTH; + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_shift, reg_width, temp, (entire_cycles - 1)); + hal_writel(temp, PWM_BASE + reg_offset); + } + + /* config dead zone, one config for two pwm */ + reg_offset = get_pdzcr_reg_offset(channels[0]); + reg_shift = PWM_PDZINTV_SHIFT; + reg_width = PWM_PDZINTV_WIDTH; + temp = hal_readl(PWM_BASE + reg_offset); + temp = SET_BITS(reg_shift, reg_width, temp, reg_dead); /* set reg_dead time */ + hal_writel(temp, PWM_BASE + reg_offset); + + /* pwm set channels[0] polarity */ + hal_pwm_porality(channels[0], config_pwm->polarity); + /* channels[1]'s polarity opposite to channels[0]'s polarity */ + hal_pwm_porality(channels[1], !config_pwm->polarity); + + for (i = 0; i < PWM_BIND_NUM; i++) + /* pwm enable controller */ + hal_pwm_enable_controller(channels[i]); + + PWM_INFO("pwm control dual channel end\n"); + return 0; } -pwm_status_t hal_pwm_suspend(void) +pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm) { - if (hal_reset_control_assert(sunxi_pwm.pwm_reset)) - { - return -1; + bool bind_mode; + + bind_mode = pwm_gpio[channel].bind_mode; + if (!bind_mode) + hal_pwm_control_single(channel, config_pwm); + else + hal_pwm_control_dual(channel, config_pwm); + + return 0; +} + +pwm_status_t hal_pwm_release_single(int channel) +{ + unsigned int reg_offset, reg_shift, reg_width; + unsigned int value; + + reg_shift = PWM_CLK_SRC_SHIFT; + reg_width = PWM_CLK_SRC_WIDTH; + reg_offset = get_pccr_reg_offset(channel); + + /* pwm disable controller */ + hal_pwm_disable_controller(channel); + + /* config gating */ +#ifdef CONFIG_ARCH_SUN8IW18P1 + reg_shift = PWM_CLK_GATING_SHIFT; + value = hal_readl(PWM_BASE + reg_offset); + value = SET_BITS(reg_shift, 1, value, 0); /* set gating */ + hal_writel(value, PWM_BASE + reg_offset); +#else + reg_shift = channel; + value = hal_readl(PWM_BASE + PWM_PCGR); + value = SET_BITS(reg_shift, 1, value, 0); /* set gating */ + hal_writel(value, PWM_BASE + PWM_PCGR); +#endif + + /* pwm set port */ + hal_pwm_pinctrl_exit(sunxi_pwm, channel); + sunxi_pwm.pin_state[channel] = false; + + return 0; +} + +pwm_status_t hal_pwm_release_dual(int channel) +{ + unsigned int reg_offset, reg_shift, reg_width; + unsigned int value; + int channels[2] = {0}; + int err, i; + + channels[0] = channel; + channels[1] = pwm_gpio[channel].bind_channel; + + for (i = 0; i < PWM_BIND_NUM; i++) + /* pwm disable controller */ + hal_pwm_disable_controller(channel); + + for (i = 0; i < PWM_BIND_NUM; i++) { + reg_shift = PWM_CLK_SRC_SHIFT; + reg_width = PWM_CLK_SRC_WIDTH; + reg_offset = get_pccr_reg_offset(channels[i]); + /* config gating */ +#ifdef CONFIG_ARCH_SUN8IW18P1 + reg_shift = PWM_CLK_GATING_SHIFT; + value = hal_readl(PWM_BASE + reg_offset); + value = SET_BITS(reg_shift, 1, value, 0); /* set gating */ + hal_writel(value, PWM_BASE + reg_offset); +#else + reg_shift = channel; + value = hal_readl(PWM_BASE + PWM_PCGR); + value = SET_BITS(reg_shift, 1, value, 0); /* set gating */ + hal_writel(value, PWM_BASE + PWM_PCGR); +#endif } - if (hal_clock_disable(sunxi_pwm.pwm_bus_clk)) - { - return -1; + /* release dead zone, one release for two pwm */ + reg_offset = get_pdzcr_reg_offset(channels[0]); + reg_shift = PWM_DZ_EN_SHIFT; + reg_width = PWM_DZ_EN_WIDTH; + value = hal_readl(PWM_BASE + reg_offset); + value = SET_BITS(reg_shift, reg_width, value, 0); + hal_writel(value, PWM_BASE + reg_offset); + + for (i = 0; i < PWM_BIND_NUM; i++) { + /* pwm set port */ + hal_pwm_pinctrl_exit(sunxi_pwm, channels[i]); + sunxi_pwm.pin_state[channels[i]] = false; } - PWM_INFO("hal pwm suspend"); + return 0; +} + +pwm_status_t hal_pwm_release(int channel) +{ + bool bind_mode; + + bind_mode = pwm_gpio[channel].bind_mode; + if (!bind_mode) + hal_pwm_release_single(channel); + else + hal_pwm_release_dual(channel); + return 0; } diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/platform/pwm_sun20iw3.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/platform/pwm_sun20iw3.h index 1463b6ec..18a7a265 100644 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/platform/pwm_sun20iw3.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/pwm/platform/pwm_sun20iw3.h @@ -122,7 +122,7 @@ #define PWM_NUM 12 #define SUNXI_PWM_CLK_TYPE HAL_SUNXI_CCU -#define SUNXI_PWM_CLK_ID HAL_CLK_PERIPH_DMA +#define SUNXI_PWM_CLK_ID HAL_CLK_PERIPH_PWM #define SUNXI_PWM_RESET_TYPE HAL_SUNXI_RESET #define SUNXI_PWM_RESET_ID 0 @@ -133,6 +133,9 @@ typedef struct pwm_gpio_t { gpio_pin_t pwm_pin; int pwm_function; + bool bind_mode; + u32 bind_channel; + u32 dead_time; } pwm_gpio_t; static pwm_gpio_t pwm_gpio[PWM_NUM] = diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Kconfig b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Kconfig new file mode 100755 index 00000000..9b6b9a54 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Kconfig @@ -0,0 +1,17 @@ +menu "SPI Devices" + +config DRIVERS_SPI + bool "enable spi driver" + default n + +config DRIVERS_SPI_PANIC_TRANSFER + bool "support sp transfer if crash" + depends on DRIVERS_SPI + default n + +config HAL_TEST_SPI + bool "enable spi hal APIs test command" + depends on DRIVERS_SPI + default n + +endmenu diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Makefile new file mode 100755 index 00000000..3cd67b41 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/Makefile @@ -0,0 +1 @@ +obj-y += hal_spi.o diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/common_spi.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/common_spi.h new file mode 100755 index 00000000..7fe269de --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/common_spi.h @@ -0,0 +1,318 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __COMMON_SPI_I_H__ +#define __COMMON_SPI_I_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUNXI_SPI_REG_SIZE 0x1000 /* controler reg sized */ + +#define HEXADECIMAL (0x10) +#define REG_INTERVAL (0x04) +#define REG_CL (0x0c) + +#define SPI_FIFO_DEPTH (128) +#define MAX_FIFU 64 +#define BULK_DATA_BOUNDARY 64 /* can modify to adapt the application */ +#define SPI_MAX_FREQUENCY 100000000 /* spi controller just support 100Mhz */ +#define SPI_HIGH_FREQUENCY 60000000 /* sample mode threshold frequency */ +#define SPI_LOW_FREQUENCY 24000000 /* sample mode threshold frequency */ +#define SPI_MOD_CLK 50000000 /* sample mode frequency */ + +/* SPI Registers offsets from peripheral base address */ +#define SPI_VER_REG (0x00) /* version number register */ +#define SPI_GC_REG (0x04) /* global control register */ +#define SPI_TC_REG (0x08) /* transfer control register */ +#define SPI_INT_CTL_REG (0x10) /* interrupt control register */ +#define SPI_INT_STA_REG (0x14) /* interrupt status register */ +#define SPI_FIFO_CTL_REG (0x18) /* fifo control register */ +#define SPI_FIFO_STA_REG (0x1C) /* fifo status register */ +#define SPI_WAIT_CNT_REG (0x20) /* wait clock counter register */ +#define SPI_CLK_CTL_REG \ + (0x24) /* clock rate control register. better not to use it */ +#define SPI_BURST_CNT_REG (0x30) /* burst counter register */ +#define SPI_TRANSMIT_CNT_REG (0x34) /* transmit counter register */ +#define SPI_BCC_REG (0x38) /* burst control counter register */ +#define SPI_DMA_CTL_REG (0x88) /* DMA control register, only for 1639 */ +#define SPI_TXDATA_REG (0x200) /* tx data register */ +#define SPI_RXDATA_REG (0x300) /* rx data register */ + +/* SPI Global Control Register Bit Fields & Masks,default value:0x0000_0080 */ +#define SPI_GC_EN \ + (0x1 \ + << 0) /* SPI module enable control 1:enable; 0:disable; default:0 */ +#define SPI_GC_MODE \ + (0x1 << 1) /* SPI function mode select 1:master; 0:slave; default:0 */ +#define SPI_GC_TP_EN \ + (0x1 << 7) /* SPI transmit stop enable 1:stop transmit data when \ +RXFIFO is full; 0:ignore RXFIFO status; default:1 */ +#define SPI_GC_SRST \ + (0x1 << 31) /* soft reset, write 1 will clear SPI control, auto \ +clear to 0 */ +/* SPI Transfer Control Register Bit Fields & Masks,default value:0x0000_0087 */ +#define SPI_TC_PHA \ + (0x1 << 0) /* SPI Clock/Data phase control,0: phase0,1: \ +phase1;default:1 */ +#define SPI_TC_POL \ + (0x1 << 1) /* SPI Clock polarity control,0:low level idle,1:high \ +level idle;default:1 */ +#define SPI_TC_SPOL \ + (0x1 << 2) /* SPI Chip select signal polarity control,default: 1,low \ +effective like this:~~|_____~~ */ +#define SPI_TC_SSCTL \ + (0x1 \ + << 3) /* SPI chip select control,default 0:SPI_SSx remains asserted \ +between SPI bursts,1:negate SPI_SSx between SPI bursts */ +#define SPI_TC_SS_MASK \ + (0x3 << 4) /* SPI chip \ +select:00-SPI_SS0;01-SPI_SS1;10-SPI_SS2;11-SPI_SS3*/ +#define SPI_TC_SS_OWNER \ + (0x1 << 6) /* SS output mode select default is 0:automatic output \ +SS;1:manual output SS */ +#define SPI_TC_SS_LEVEL \ + (0x1 << 7) /* defautl is 1:set SS to high;0:set SS to low */ +#define SPI_TC_DHB \ + (0x1 \ + << 8) /* Discard Hash Burst,default 0:receiving all spi burst in BC \ +period 1:discard unused,fectch WTC bursts */ +#define SPI_TC_DDB \ + (0x1 << 9) /* Dummy burst Type,default 0: dummy spi burst is \ +zero;1:dummy spi burst is one */ +#define SPI_TC_RPSM \ + (0x1 << 10) /* select mode for high speed write,0:normal write \ +mode,1:rapids write mode,default 0 */ +#define SPI_TC_SDM \ + (0x1 << 13) /* master sample data mode, 1: normal sample \ +mode;0:delay sample mode. */ +#define SPI_TC_SDC \ + (0x1 << 11) /* master sample data control, 1: delay--high speed \ +operation;0:no delay. */ +#define SPI_TC_FBS \ + (0x1 << 12) /* LSB/MSB transfer first select 0:MSB,1:LSB,default \ +0:MSB first */ +#define SPI_TC_XCH \ + (0x1 \ + << 31) /* Exchange burst default 0:idle,1:start exchange;when BC is \ +zero,this bit cleared by SPI controller*/ +#define SPI_TC_SS_BIT_POS (4) + +/* SPI Interrupt Control Register Bit Fields & Masks,default value:0x0000_0000 +*/ +#define SPI_INTEN_RX_RDY \ + (0x1 << 0) /* rxFIFO Ready Interrupt Enable,---used for immediately \ +received,0:disable;1:enable */ +#define SPI_INTEN_RX_EMP \ + (0x1 << 1) /* rxFIFO Empty Interrupt Enable ---used for IRQ received \ +*/ +#define SPI_INTEN_RX_FULL \ + (0x1 << 2) /* rxFIFO Full Interrupt Enable ---seldom used */ +#define SPI_INTEN_TX_ERQ \ + (0x1 << 4) /* txFIFO Empty Request Interrupt Enable ---seldom used */ +#define SPI_INTEN_TX_EMP \ + (0x1 << 5) /* txFIFO Empty Interrupt Enable ---used for IRQ tx */ +#define SPI_INTEN_TX_FULL \ + (0x1 << 6) /* txFIFO Full Interrupt Enable ---seldom used */ +#define SPI_INTEN_RX_OVF \ + (0x1 \ + << 8) /* rxFIFO Overflow Interrupt Enable ---used for error detect */ +#define SPI_INTEN_RX_UDR \ + (0x1 \ + << 9) /* rxFIFO Underrun Interrupt Enable ---used for error detect */ +#define SPI_INTEN_TX_OVF \ + (0x1 << 10) /* txFIFO Overflow Interrupt Enable ---used for error \ +detect */ +#define SPI_INTEN_TX_UDR \ + (0x1 << 11) /* txFIFO Underrun Interrupt Enable ---not happened */ +#define SPI_INTEN_TC \ + (0x1 << 12) /* Transfer Completed Interrupt Enable ---used */ +#define SPI_INTEN_SSI \ + (0x1 << 13) /* SSI interrupt Enable,chip select from valid state to \ +invalid state,for slave used only */ +#define SPI_INTEN_ERR \ + (SPI_INTEN_TX_OVF | SPI_INTEN_RX_UDR | \ + SPI_INTEN_RX_OVF) /* NO txFIFO underrun */ +#define SPI_INTEN_MASK (0x77 | (0x3f << 8)) + +/* SPI Interrupt Status Register Bit Fields & Masks,default value:0x0000_0022 */ +#define SPI_INT_STA_RX_RDY \ + (0x1 << 0) /* rxFIFO ready, 0:RX_WL < RX_TRIG_LEVEL,1:RX_WL >= \ +RX_TRIG_LEVEL */ +#define SPI_INT_STA_RX_EMP \ + (0x1 << 1) /* rxFIFO empty, this bit is set when rxFIFO is empty */ +#define SPI_INT_STA_RX_FULL \ + (0x1 << 2) /* rxFIFO full, this bit is set when rxFIFO is full */ +#define SPI_INT_STA_TX_RDY \ + (0x1 << 4) /* txFIFO ready, 0:TX_WL > TX_TRIG_LEVEL,1:TX_WL <= \ +TX_TRIG_LEVEL */ +#define SPI_INT_STA_TX_EMP \ + (0x1 << 5) /* txFIFO empty, this bit is set when txFIFO is empty */ +#define SPI_INT_STA_TX_FULL \ + (0x1 << 6) /* txFIFO full, this bit is set when txFIFO is full */ +#define SPI_INT_STA_RX_OVF \ + (0x1 << 8) /* rxFIFO overflow, when set rxFIFO has overflowed */ +#define SPI_INT_STA_RX_UDR \ + (0x1 << 9) /* rxFIFO underrun, when set rxFIFO has underrun */ +#define SPI_INT_STA_TX_OVF \ + (0x1 << 10) /* txFIFO overflow, when set txFIFO has overflowed */ +#define SPI_INT_STA_TX_UDR \ + (0x1 << 11) /* fxFIFO underrun, when set txFIFO has underrun */ +#define SPI_INT_STA_TC (0x1 << 12) /* Transfer Completed */ +#define SPI_INT_STA_SSI \ + (0x1 << 13) /* SS invalid interrupt, when set SS has changed from \ +valid to invalid */ +#define SPI_INT_STA_ERR \ + (SPI_INT_STA_TX_OVF | SPI_INT_STA_RX_UDR | \ + SPI_INT_STA_RX_OVF) /* NO txFIFO underrun */ +#define SPI_INT_STA_MASK (0x77 | (0x3f << 8)) + +/* SPI FIFO Control Register Bit Fields & Masks,default value:0x0040_0001 */ +#define SPI_FIFO_CTL_RX_LEVEL \ + (0xFF << 0) /* rxFIFO reday request trigger level,default 0x1 */ +#define SPI_FIFO_CTL_RX_DRQEN \ + (0x1 << 8) /* rxFIFO DMA request enable,1:enable,0:disable */ +#define SPI_FIFO_CTL_RX_TESTEN \ + (0x1 << 14) /* rxFIFO test mode enable,1:enable,0:disable */ +#define SPI_FIFO_CTL_RX_RST \ + (0x1 << 15) /* rxFIFO reset, write 1, auto clear to 0 */ +#define SPI_FIFO_CTL_TX_LEVEL \ + (0xFF << 16) /* txFIFO empty request trigger level,default 0x40 */ +#define SPI_FIFO_CTL_TX_DRQEN \ + (0x1 << 24) /* txFIFO DMA request enable,1:enable,0:disable */ +#define SPI_FIFO_CTL_TX_TESTEN \ + (0x1 << 30) /* txFIFO test mode enable,1:enable,0:disable */ +#define SPI_FIFO_CTL_TX_RST \ + (0x1 << 31) /* txFIFO reset, write 1, auto clear to 0 */ +#define SPI_FIFO_CTL_DRQEN_MASK (SPI_FIFO_CTL_TX_DRQEN | SPI_FIFO_CTL_RX_DRQEN) + +/* SPI FIFO Status Register Bit Fields & Masks,default value:0x0000_0000 */ +#define SPI_FIFO_STA_RX_CNT \ + (0xFF << 0) /* rxFIFO counter,how many bytes in rxFIFO */ +#define SPI_FIFO_STA_RB_CNT \ + (0x7 << 12) /* rxFIFO read buffer counter,how many bytes in rxFIFO \ +read buffer */ +#define SPI_FIFO_STA_RB_WR (0x1 << 15) /* rxFIFO read buffer write enable */ +#define SPI_FIFO_STA_TX_CNT \ + (0xFF << 16) /* txFIFO counter,how many bytes in txFIFO */ +#define SPI_FIFO_STA_TB_CNT \ + (0x7 << 28) /* txFIFO write buffer counter,how many bytes in txFIFO \ +write buffer */ +#define SPI_FIFO_STA_TB_WR (0x1 << 31) /* txFIFO write buffer write enable */ +#define SPI_RXCNT_BIT_POS (0) +#define SPI_TXCNT_BIT_POS (16) + +/* SPI Wait Clock Register Bit Fields & Masks,default value:0x0000_0000 */ +#define SPI_WAIT_WCC_MASK \ + (0xFFFF << 0) /* used only in master mode: Wait Between Transactions \ +*/ +#define SPI_WAIT_SWC_MASK \ + (0xF << 16) /* used only in master mode: Wait before start dual data \ +transfer in dual SPI mode */ + +/* SPI Clock Control Register Bit Fields & Masks,default:0x0000_0002 */ +#define SPI_CLK_CTL_CDR2 \ + (0xFF << 0) /* Clock Divide Rate 2,master mode only : SPI_CLK = \ +AHB_CLK/(2*(n+1)) */ +#define SPI_CLK_CTL_CDR1 \ + (0xF << 8) /* Clock Divide Rate 1,master mode only : SPI_CLK = \ +AHB_CLK/2^n */ +#define SPI_CLK_CTL_DRS \ + (0x1 << 12) /* Divide rate select,default,0:rate 1;1:rate 2 */ +#define SPI_CLK_SCOPE (SPI_CLK_CTL_CDR2 + 1) + +/* SPI Master Burst Counter Register Bit Fields & Masks,default:0x0000_0000 */ +/* master mode: when SMC = 1,BC specifies total burst number, Max length is + * 16Mbytes */ +#define SPI_BC_CNT_MASK \ + (0xFFFFFF << 0) /* Total Burst Counter, tx length + rx length ,SMC=1 \ +*/ + +/* SPI Master Transmit Counter reigster default:0x0000_0000 */ +#define SPI_TC_CNT_MASK \ + (0xFFFFFF \ + << 0) /* Write Transmit Counter, tx length, NOT rx length!!! */ + +/* SPI Master Burst Control Counter reigster Bit Fields & + * Masks,default:0x0000_0000 */ +#define SPI_BCC_STC_MASK \ + (0xFFFFFF << 0) /* master single mode transmit counter */ +#define SPI_BCC_DBC_MASK (0xF << 24) /* master dummy burst counter */ +#define SPI_BCC_DUAL_MODE (0x1 << 28) /* master dual mode RX enable */ +#define SPI_BCC_QUAD_MODE (0x1 << 29) /* master quad mode RX enable */ + +#define SPI_PHA_ACTIVE_ (0x01) +#define SPI_POL_ACTIVE_ (0x02) + +#define SPI_MODE_0_ACTIVE_ (0 | 0) +#define SPI_MODE_1_ACTIVE_ (0 | SPI_PHA_ACTIVE_) +#define SPI_MODE_2_ACTIVE_ (SPI_POL_ACTIVE_ | 0) +#define SPI_MODE_3_ACTIVE_ (SPI_POL_ACTIVE_ | SPI_PHA_ACTIVE_) +#define SPI_CS_HIGH_ACTIVE_ (0x04) +#define SPI_LSB_FIRST_ACTIVE_ (0x08) +#define SPI_DUMMY_ONE_ACTIVE_ (0x10) +#define SPI_RECEIVE_ALL_ACTIVE_ (0x20) + +#define SUNXI_SPI_DRQ_RX(ch) (DRQSRC_SPI0_RX + ch) +#define SUNXI_SPI_DRQ_TX(ch) (DRQDST_SPI0_TX + ch) + +#define SPIM_BUSY (1) +#define SPIM_IDLE (0) + +#define spim_set_idle(master_port) \ + do { \ + g_spi_master_status[master_port] = SPIM_IDLE; \ + } while (0) + +#define SPI_MASTER_MB_LSB_FIRST (0x1UL << 3) +#define SPI_MASTER_MB_MSB_FIRST (0x0UL << 3) + +#define SPI_MASTER_CPOL_0 (0x0UL << 4) +#define SPI_MASTER_CPOL_1 (0x1UL << 4) + +#define SPI_MASTER_CPHA_0 (0x0UL << 5) +#define SPI_MASTER_CPHA_1 (0x1UL << 5) + +#define SPI_MASTER_INT_DISABLE (0x0UL << 9) +#define SPI_MASTER_INT_ENABLE (0x1UL << 9) + +#define SPI_MASTER_HALF_DUPLEX (0x0UL << 10) +#define SPI_MASTER_FULL_DUPLEX (0x1UL << 10) + +#define SPI_MASTER_SLAVE_SEL_0 (0x0UL << 29) +#define SPI_MASTER_SLAVE_SEL_1 (0x1UL << 29) + +#ifdef __cplusplus +} +#endif +#endif /* __COMMON_SPI_I_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/hal_spi.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/hal_spi.c new file mode 100755 index 00000000..5e8ab164 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/hal_spi.c @@ -0,0 +1,2415 @@ +/* + * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. + * + * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in + * the the People's Republic of China and other countries. + * All Allwinner Technology Co.,Ltd. trademarks are used with permission. + * + * DISCLAIMER + * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. + * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR + * MPEGLA, ETC.) + * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN + * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. + * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT + * TO MATTERS + * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. + * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY. + * + * + * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT + * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING + * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE + * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OS_MELIS +#include +#include +#endif + +#include + +#define SPI_ALIGN(x, a) ALIGN_UP(x, a) + +#ifndef CONFIG_DRIVERS_DMA +#define CONFIG_SUNXI_SPI_CPU_XFER_ONLY +#endif + +#if (0) +#define SPI_INFO_LEVEL +#endif + +#if (0) +#define SPI_DATA_LEVEL +#endif + +#if (0) +#define SPI_DUMPREG_LEVEL +#endif + + +#ifdef SPI_INFO_LEVEL +#define SPI_INFO(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg) +#else +#define SPI_INFO(fmt, arg...) \ + do { \ + } while (0); +#endif + +#define SPI_ERR(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg) +#define SPI_INIT(fmt, arg...) printf("%s()%d " fmt, __func__, __LINE__, ##arg) + +static sunxi_spi_t g_sunxi_spi[HAL_SPI_MASTER_MAX]; +struct sunxi_spi_params_t g_sunxi_spi_params[] = { +#ifdef SPI0_PARAMS + SPI0_PARAMS, +#endif +#ifdef SPI1_PARAMS + SPI1_PARAMS, +#endif +#ifdef SPI2_PARAMS + SPI2_PARAMS, +#endif +#ifdef SPI3_PARAMS + SPI3_PARAMS, +#endif +}; + + +struct sunxi_spi_params_t g_sunxi_spi_params_sip[] = { +#ifdef SIP_SPI0_PARAMS + SIP_SPI0_PARAMS, +#endif +}; + +void spi_dump_reg(sunxi_spi_t *sspi, uint32_t offset, uint32_t len) +{ + uint32_t i; + uint8_t buf[64], cnt = 0; + + for (i = 0; i < len; i = i + REG_INTERVAL) + { + if (i % HEXADECIMAL == 0) + cnt += sprintf((char *)(buf + cnt), "0x%08lx: ", + (unsigned long)(sspi->base + offset + i)); + + cnt += sprintf((char *)(buf + cnt), "%08lx ", + (unsigned long)hal_readl(sspi->base + offset + i)); + + if (i % HEXADECIMAL == REG_CL) + { + printf("%s\n", buf); + cnt = 0; + } + } +} + +/* config chip select */ +static spi_master_status_t spi_set_cs(hal_spi_master_slave_port_t chipselect, sunxi_spi_t *sspi) +{ + spi_master_status_t ret; + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + + if (chipselect < 4) + { + reg_val &= ~SPI_TC_SS_MASK; /* SS-chip select, clear two bits */ + reg_val |= chipselect + << SPI_TC_SS_BIT_POS; /* set chip select */ + hal_writel(reg_val, sspi->base + SPI_TC_REG); + ret = SPI_MASTER_OK; + } + else + { + SPI_ERR("[spi%d] Chip Select set fail! cs = %d\n", sspi->port, + chipselect); + ret = SPI_MASTER_INVALID_PARAMETER; + } + + return ret; +} + +/* config spi */ +static void spi_config_tc(uint32_t config, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + + /*1. POL */ + if (config & SPI_POL_ACTIVE_) + { + reg_val |= SPI_TC_POL; /*default POL = 1 */ + } + else + { + reg_val &= ~SPI_TC_POL; + } + + /*2. PHA */ + if (config & SPI_PHA_ACTIVE_) + { + reg_val |= SPI_TC_PHA; /*default PHA = 1 */ + } + else + { + reg_val &= ~SPI_TC_PHA; + } + + /*3. SSPOL,chip select signal polarity */ + if (config & SPI_CS_HIGH_ACTIVE_) + { + reg_val &= ~SPI_TC_SPOL; + } + else + { + reg_val |= SPI_TC_SPOL; /*default SSPOL = 1,Low level effect */ + } + + /*4. LMTF--LSB/MSB transfer first select */ + if (config & SPI_LSB_FIRST_ACTIVE_) + { + reg_val |= SPI_TC_FBS; + } + else + { + reg_val &= ~SPI_TC_FBS; /*default LMTF =0, MSB first */ + } + + /* set DDB,DHB,SMC,SSCTL */ + /*5. dummy burst type */ + if (config & SPI_DUMMY_ONE_ACTIVE_) + { + reg_val |= SPI_TC_DDB; + } + else + { + reg_val &= ~SPI_TC_DDB; /*default DDB =0, ZERO */ + } + + /*6.discard hash burst-DHB */ + if (config & SPI_RECEIVE_ALL_ACTIVE_) + { + reg_val &= ~SPI_TC_DHB; + } + else + { + reg_val |= SPI_TC_DHB; /*default DHB =1, discard unused burst */ + } + + /*7. set SMC = 1 , SSCTL = 0 ,TPE = 1 */ + reg_val &= ~SPI_TC_SSCTL; + + hal_writel(reg_val, sspi->base + SPI_TC_REG); +} + +/* delay internal read sample point*/ +static void spi_sample_delay(uint32_t sdm, uint32_t sdc, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + uint32_t org_val = reg_val; + + if (sdm) + { + reg_val |= SPI_TC_SDM; + } + else + { + reg_val &= ~SPI_TC_SDM; + } + + if (sdc) + { + reg_val |= SPI_TC_SDC; + } + else + { + reg_val &= ~SPI_TC_SDC; + } + + if (reg_val != org_val) + { + hal_writel(reg_val, sspi->base + SPI_TC_REG); + } +} + +/* start spi transfer */ +static void spi_start_xfer(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + + reg_val |= SPI_TC_XCH; + hal_writel(reg_val, sspi->base + SPI_TC_REG); +} + +/* enable spi bus */ +static void spi_enable_bus(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_GC_REG); + + reg_val |= SPI_GC_EN; + hal_writel(reg_val, sspi->base + SPI_GC_REG); +} + +/* disbale spi bus */ +static void spi_disable_bus(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_GC_REG); + + reg_val &= ~SPI_GC_EN; + hal_writel(reg_val, sspi->base + SPI_GC_REG); +} + +/* set master mode */ +static void spi_set_master(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_GC_REG); + + reg_val |= SPI_GC_MODE; + hal_writel(reg_val, sspi->base + SPI_GC_REG); +} + +/* soft reset spi controller */ +static void spi_soft_reset(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_GC_REG); + + reg_val |= SPI_GC_SRST; + hal_writel(reg_val, sspi->base + SPI_GC_REG); +} + +/* enable transmit pause */ +static void spi_enable_tp(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_GC_REG); + + reg_val |= SPI_GC_TP_EN; + hal_writel(reg_val, sspi->base + SPI_GC_REG); +} + +/* set ss control */ +static void spi_ss_owner(sunxi_spi_t *sspi, uint32_t on_off) +{ + u32 reg_val = hal_readl(sspi->base + SPI_TC_REG); + + on_off &= 0x1; + if (on_off) + { + reg_val |= SPI_TC_SS_OWNER; + } + else + { + reg_val &= ~SPI_TC_SS_OWNER; + } + hal_writel(reg_val, sspi->base + SPI_TC_REG); +} + +/* enable irq type */ +static void spi_enable_irq(uint32_t bitmap, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_INT_CTL_REG); + + bitmap &= SPI_INTEN_MASK; + reg_val |= bitmap; + hal_writel(reg_val, sspi->base + SPI_INT_CTL_REG); +} + +/* disable irq type */ +static void spi_disable_irq(uint32_t bitmap, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_INT_CTL_REG); + + bitmap &= SPI_INTEN_MASK; + reg_val &= ~bitmap; + hal_writel(reg_val, sspi->base + SPI_INT_CTL_REG); +} + +/* enable dma irq */ +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY +static void spi_enable_dma_irq(uint32_t bitmap, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_FIFO_CTL_REG); + + bitmap &= SPI_FIFO_CTL_DRQEN_MASK; + reg_val |= bitmap; + hal_writel(reg_val, sspi->base + SPI_FIFO_CTL_REG); +} +#endif + +/* disable dma irq */ +static void spi_disable_dma_irq(uint32_t bitmap, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_FIFO_CTL_REG); + + bitmap &= SPI_FIFO_CTL_DRQEN_MASK; + reg_val &= ~bitmap; + hal_writel(reg_val, sspi->base + SPI_FIFO_CTL_REG); +} + +/* query irq enable */ +static uint32_t spi_qry_irq_enable(sunxi_spi_t *sspi) +{ + return (SPI_INTEN_MASK & hal_readl(sspi->base + SPI_INT_CTL_REG)); +} + +/* query irq pending */ +static uint32_t spi_qry_irq_pending(sunxi_spi_t *sspi) +{ + return (SPI_INT_STA_MASK & hal_readl(sspi->base + SPI_INT_STA_REG)); +} + +/* clear irq pending */ +static void spi_clr_irq_pending(uint32_t pending_bit, sunxi_spi_t *sspi) +{ + pending_bit &= SPI_INT_STA_MASK; + hal_writel(pending_bit, sspi->base + SPI_INT_STA_REG); +} + +/* query txfifo bytes */ +static uint32_t spi_query_txfifo(sunxi_spi_t *sspi) +{ + uint32_t reg_val = + (SPI_FIFO_STA_TX_CNT & hal_readl(sspi->base + SPI_FIFO_STA_REG)); + + reg_val >>= SPI_TXCNT_BIT_POS; + return reg_val; +} + +/* query rxfifo bytes */ +static uint32_t spi_query_rxfifo(sunxi_spi_t *sspi) +{ + uint32_t reg_val = + (SPI_FIFO_STA_RX_CNT & hal_readl(sspi->base + SPI_FIFO_STA_REG)); + + reg_val >>= SPI_RXCNT_BIT_POS; + return reg_val; +} + +/* reset fifo */ +static void spi_reset_fifo(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_FIFO_CTL_REG); + + reg_val |= (SPI_FIFO_CTL_RX_RST | SPI_FIFO_CTL_TX_RST); + /* Set the trigger level of RxFIFO/TxFIFO. */ + reg_val &= ~(SPI_FIFO_CTL_RX_LEVEL | SPI_FIFO_CTL_TX_LEVEL); + reg_val |= (0x20 << 16) | 0x20; + hal_writel(reg_val, sspi->base + SPI_FIFO_CTL_REG); +} + +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY +static void spi_set_rx_trig(uint32_t val, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_FIFO_CTL_REG); + + reg_val &= ~SPI_FIFO_CTL_RX_LEVEL; + reg_val |= val & SPI_FIFO_CTL_RX_LEVEL; + hal_writel(reg_val, sspi->base + SPI_FIFO_CTL_REG); +} + +static void spi_set_tx_trig(uint32_t val, sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_FIFO_CTL_REG); + + reg_val &= ~SPI_FIFO_CTL_TX_LEVEL; + reg_val |= (val << 16) & SPI_FIFO_CTL_TX_LEVEL; + hal_writel(reg_val, sspi->base + SPI_FIFO_CTL_REG); +} +#endif + +/* set transfer total length BC, transfer length TC and single transmit length + * STC */ +static void spi_set_bc_tc_stc(uint32_t tx_len, uint32_t rx_len, + uint32_t stc_len, uint32_t dummy_cnt, + sunxi_spi_t *sspi) +{ + uint32_t reg_val; + + /* set MBC(0x30) = tx_len + rx_len + dummy_cnt */ + reg_val = hal_readl(sspi->base + SPI_BURST_CNT_REG); + reg_val &= ~SPI_BC_CNT_MASK; + reg_val |= (SPI_BC_CNT_MASK & (tx_len + rx_len + dummy_cnt)); + hal_writel(reg_val, sspi->base + SPI_BURST_CNT_REG); + + /* set MTC(0x34) = tx_len */ + reg_val = hal_readl(sspi->base + SPI_TRANSMIT_CNT_REG); + reg_val &= ~SPI_TC_CNT_MASK; + reg_val |= (SPI_TC_CNT_MASK & tx_len); + hal_writel(reg_val, sspi->base + SPI_TRANSMIT_CNT_REG); + + /* set BBC(0x38) = dummy cnt & single mode transmit counter */ + reg_val = hal_readl(sspi->base + SPI_BCC_REG); + reg_val &= ~SPI_BCC_STC_MASK; + reg_val |= (SPI_BCC_STC_MASK & stc_len); + reg_val &= ~(0xf << 24); + reg_val |= (dummy_cnt << 24); + hal_writel(reg_val, sspi->base + SPI_BCC_REG); +} + +#if 0 +/* set ss control */ +static void spi_ss_ctrl(sunxi_spi_t *sspi, uint8_t on_off) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + + on_off &= 0x1; + if (on_off) + { + reg_val |= SPI_TC_SS_LEVEL; + } + else + { + reg_val &= ~SPI_TC_SS_LEVEL; + } + hal_writel(reg_val, sspi->base + SPI_TC_REG); +} +#endif + +/* set dhb, 1: discard unused spi burst; 0: receiving all spi burst */ +static void spi_set_all_burst_received(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_TC_REG); + + reg_val &= ~SPI_TC_DHB; + writel(reg_val, sspi->base + SPI_TC_REG); +} + +static void spi_disable_dual(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_BCC_REG); + reg_val &= ~SPI_BCC_DUAL_MODE; + hal_writel(reg_val, sspi->base + SPI_BCC_REG); +} + +static void spi_enable_dual(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_BCC_REG); + reg_val &= ~SPI_BCC_QUAD_MODE; + reg_val |= SPI_BCC_DUAL_MODE; + hal_writel(reg_val, sspi->base + SPI_BCC_REG); +} + +static void spi_disable_quad(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_BCC_REG); + + reg_val &= ~SPI_BCC_QUAD_MODE; + hal_writel(reg_val, sspi->base + SPI_BCC_REG); +} + +static void spi_enable_quad(sunxi_spi_t *sspi) +{ + uint32_t reg_val = hal_readl(sspi->base + SPI_BCC_REG); + + reg_val |= SPI_BCC_QUAD_MODE; + hal_writel(reg_val, sspi->base + SPI_BCC_REG); +} + +static spi_master_status_t spi_mode_check(sunxi_spi_t *sspi) +{ + if (sspi->mode_type != MODE_TYPE_NULL) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + + /* full duplex */ + if (sspi->transfer->tx_buf && sspi->transfer->rx_buf) + { + /* fake full duplex for flash read/write */ + if (sspi->config.flash) + { + spi_set_bc_tc_stc(sspi->transfer->tx_len, + sspi->transfer->rx_len, + sspi->transfer->tx_single_len, + sspi->transfer->dummy_byte, sspi); + sspi->mode_type = FULL_DUPLEX_TX_RX; + + if (sspi->transfer->rx_nbits == SPI_NBITS_QUAD) + { + spi_disable_dual(sspi); + spi_enable_quad(sspi); + SPI_INFO("[spi%d] Quad mode fake Full duplex tx rx\n", + sspi->port); + } + else if (sspi->transfer->rx_nbits == SPI_NBITS_DUAL) + { + spi_disable_quad(sspi); + spi_enable_dual(sspi); + SPI_INFO("[spi%d] Dual mode fake Full duplex tx rx\n", + sspi->port); + } + else + { + spi_disable_quad(sspi); + spi_disable_dual(sspi); + SPI_INFO("[spi%d] Single mode fake Full duplex tx rx\n", + sspi->port); + } + } /* real full duplex transmit by single mode */ + else + { + spi_disable_quad(sspi); + spi_disable_dual(sspi); + spi_set_all_burst_received(sspi); + spi_set_bc_tc_stc(sspi->transfer->tx_len, 0, + sspi->transfer->tx_single_len, + 0, sspi); + sspi->mode_type = SINGLE_FULL_DUPLEX_RX_TX; + SPI_INFO("[spi%d] Single mode real Full duplex tx rx\n", + sspi->port); + } + } /* half duplex transmit */ + else if (sspi->transfer->tx_buf) + { + if (sspi->transfer->tx_nbits == SPI_NBITS_QUAD) + { + spi_disable_dual(sspi); + spi_enable_quad(sspi); + spi_set_bc_tc_stc(sspi->transfer->tx_len, 0, + sspi->transfer->tx_single_len, + sspi->transfer->dummy_byte, sspi); + sspi->mode_type = QUAD_HALF_DUPLEX_TX; + SPI_INFO("[spi%d] Quad mode Half duplex tx\n", + sspi->port); + } + else if (sspi->transfer->tx_nbits == SPI_NBITS_DUAL) + { + spi_disable_quad(sspi); + spi_enable_dual(sspi); + spi_set_bc_tc_stc(sspi->transfer->tx_len, 0, + sspi->transfer->tx_single_len, + sspi->transfer->dummy_byte, sspi); + sspi->mode_type = DUAL_HALF_DUPLEX_TX; + SPI_INFO("[spi%d] Dual mode Half duplex tx\n", + sspi->port); + } + else + { + spi_disable_quad(sspi); + spi_disable_dual(sspi); + spi_set_bc_tc_stc(sspi->transfer->tx_len, 0, + sspi->transfer->tx_len, + sspi->transfer->dummy_byte, sspi); + sspi->mode_type = SGLE_HALF_DUPLEX_TX; + SPI_INFO("[spi%d] Single mode Half duplex tx\n", + sspi->port); + } + } /* half duplex receive */ + else if (sspi->transfer->rx_buf) + { + if (sspi->transfer->rx_nbits == SPI_NBITS_QUAD) + { + spi_disable_dual(sspi); + spi_enable_quad(sspi); + sspi->mode_type = QUAD_HALF_DUPLEX_RX; + SPI_INFO("[spi%d] Quad mode Half duplex rx\n", + sspi->port); + } + else if (sspi->transfer->rx_nbits == SPI_NBITS_DUAL) + { + spi_disable_quad(sspi); + spi_enable_dual(sspi); + sspi->mode_type = DUAL_HALF_DUPLEX_RX; + SPI_INFO("[spi%d] Dual mode Half duplex rx\n", + sspi->port); + } + else + { + spi_disable_quad(sspi); + spi_disable_dual(sspi); + sspi->mode_type = SGLE_HALF_DUPLEX_RX; + SPI_INFO("[spi%d] Single mode Half duplex rx\n", + sspi->port); + } + spi_set_bc_tc_stc(0, sspi->transfer->rx_len, 0, + sspi->transfer->dummy_byte, sspi); + } + + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_cpu_write(sunxi_spi_t *sspi) +{ + uint32_t len = sspi->transfer->tx_len; + const uint8_t *buf = sspi->transfer->tx_buf; + uint32_t poll_time = 0x7ffffff; +#ifdef SPI_DATA_LEVEL + uint32_t i, j; + uint8_t dbuf[64], cnt = 0; +#endif + + if (NULL == buf) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + +#ifdef SPI_DUMPREG_LEVEL + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); +#endif + +#ifdef SPI_DATA_LEVEL + SPI_INFO("tx_len = %d\n", len); + for (i = 0; i < len; i += 16) + { + cnt = 0; + cnt += sprintf(dbuf + cnt, "%04x: ", i); + for (j = 0; ((i + j) < len) && (j < 16); j++) + cnt += sprintf(dbuf + cnt, "%02x ", + ((uint8_t *)(buf))[i + j]); + printf("%s\n", dbuf); + } +#endif + + for (; len > 0; --len) + { + hal_writeb(*buf++, sspi->base + SPI_TXDATA_REG); + while ((spi_query_txfifo(sspi) >= MAX_FIFU) && poll_time--) + ; + if (poll_time == 0) + { + SPI_ERR("[spi%d] cpu transfer data time out!\n", + sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + return SPI_MASTER_ERROR_TIMEOUT; + } + } + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_cpu_read(sunxi_spi_t *sspi) +{ + uint32_t len = sspi->transfer->rx_len; + uint8_t *buf = sspi->transfer->rx_buf; + uint32_t poll_time = 0x7ffffff; + uint32_t n; + +#ifdef SPI_DATA_LEVEL + uint32_t i, j; + uint8_t dbuf[64], cnt = 0; +#endif + + if (NULL == buf) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + +#ifdef SPI_DUMPREG_LEVEL + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); +#endif + + for (n = 0; n < len; n++) + { + while (!spi_query_rxfifo(sspi) && poll_time--) + ; + if (poll_time <= 0) + { + SPI_ERR("[spi%d] cpu receive data time out!\n", + sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + return SPI_MASTER_ERROR_TIMEOUT; + } + + *(buf + n) = hal_readb(sspi->base + SPI_RXDATA_REG); + } + +#ifdef SPI_DATA_LEVEL + SPI_INFO("rx_len = %d\n", len); + for (i = 0; i < len; i += 16) + { + cnt = 0; + cnt += sprintf(dbuf + cnt, "%04x: ", i); + for (j = 0; ((i + j) < len) && (j < 16); j++) + cnt += sprintf(dbuf + cnt, "%02x ", + ((uint8_t *)(buf))[i + j]); + printf("%s\n", dbuf); + } +#endif + + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_cpu_write_read(sunxi_spi_t *sspi) +{ + uint32_t len = sspi->transfer->tx_len; + uint8_t *tx_buf = sspi->transfer->tx_buf; + uint8_t *rx_buf = sspi->transfer->rx_buf; + uint32_t align_loop, left_loop; + int i; + int ret = SPI_MASTER_OK; + + align_loop = len / MAX_FIFU; + left_loop = len % MAX_FIFU; + + SPI_INFO("[spi%d] data align loop %d\n", sspi->port, align_loop); + SPI_INFO("[spi%d] data left loop\n", sspi->port, left_loop); + + /* len over FIFO size, need slipt the buffer */ + if (align_loop > 0) { + for (i = 0; i < align_loop; i++) { + sspi->transfer->tx_len = MAX_FIFU; + sspi->transfer->rx_len = MAX_FIFU; + ret = spi_cpu_write(sspi); + if (ret != SPI_MASTER_OK) { + goto err0; + } + ret = spi_cpu_read(sspi); + if (ret != SPI_MASTER_OK) { + goto err0; + } + sspi->transfer->tx_buf += MAX_FIFU; + sspi->transfer->rx_buf += MAX_FIFU; + } + } + + /* Left Bytes */ + sspi->transfer->tx_len = left_loop; + sspi->transfer->rx_len = left_loop; + ret = spi_cpu_write(sspi); + if (ret != SPI_MASTER_OK) { + goto err0; + } + ret = spi_cpu_read(sspi); + if (ret != SPI_MASTER_OK) { + goto err0; + } + +err0: + sspi->transfer->tx_len = len; + sspi->transfer->rx_len = len; + sspi->transfer->tx_buf = tx_buf; + sspi->transfer->rx_buf = rx_buf; + + return ret; +} + +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY +static spi_master_status_t spi_dma_tx_config(struct sunxi_spi *sspi) +{ + hal_dma_chan_status_t ret; + uint32_t flags = 0; + uint32_t len = sspi->transfer->tx_len; + uint8_t const *buf = sspi->transfer->tx_buf; + struct dma_slave_config *config = &sspi->dma_tx.config; + +#ifdef SPI_DATA_LEVEL + unsigned int i, j; + u8 dbuf[64], cnt = 0; +#endif + + if (NULL == buf) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + + if (len <= ALIGN_DMA_BUF_SIZE) + { + memcpy(sspi->align_dma_buf, buf, len); + buf = sspi->align_dma_buf; + } + else + { + SPI_ERR("[spi%d] tx size over dma align buf size\n", + sspi->port); + /* buffer on DMA must align to cache line */ + if ((unsigned long)buf & (64 - 1) || len & (64 - 1)) + { + SPI_ERR("[spi%d] tx buf or len not align to 64\n", + sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + } + hal_dcache_clean((unsigned long)buf, SPI_ALIGN(len, 64)); + +#ifdef SPI_DATA_LEVEL + SPI_INFO("tx_len = %d\n", len); + for (i = 0; i < len; i += 16) + { + cnt = 0; + cnt += sprintf(dbuf + cnt, "%03x: ", i); + for (j = 0; ((i + j) < len) && (j < 16); j++) + cnt += sprintf(dbuf + cnt, "%02x ", + ((uint8_t *)(buf))[i + j]); + printf("%s\n", dbuf); + } +#endif + + ret = hal_dma_chan_request(&sspi->dma_tx.chan); + if (ret == HAL_DMA_CHAN_STATUS_BUSY) + { + SPI_ERR("[spi%d] request dma_rx failed\n", sspi->port); + return SPI_MASTER_ERROR; + } + + spi_set_tx_trig(32, sspi); + spi_set_rx_trig(32, sspi); + spi_enable_dma_irq(SPI_FIFO_CTL_TX_DRQEN, sspi); + +#ifdef SPI_DUMPREG_LEVEL + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); +#endif + + config->direction = DMA_MEM_TO_DEV; + config->dst_addr = sspi->base + SPI_TXDATA_REG; + config->src_addr = (unsigned long)buf; + + if (len % DMA_SLAVE_BUSWIDTH_4_BYTES) + { + config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config->dst_maxburst = DMA_SLAVE_BURST_16; + config->src_maxburst = DMA_SLAVE_BURST_16; + } + else + { + config->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config->dst_maxburst = DMA_SLAVE_BURST_8; + config->src_maxburst = DMA_SLAVE_BURST_8; + } + + config->slave_id = + sunxi_slave_id(SUNXI_SPI_DRQ_TX(sspi->port), DRQSRC_SDRAM); + + SPI_INFO("[spi%d] config:\n" + " direction: %d\n" + " src_addr: 0x%08lx," + " dst_addr: 0x%08lx\n" + " src_addr_width: %d," + " dst_addr_width: %d\n" + " src_maxburst: %lu," + " dst_maxburst: %lu\n" + " slave_id: 0x%08lx\n", + sspi->port, config->direction, config->src_addr, + config->dst_addr, config->src_addr_width, + config->dst_addr_width, config->src_maxburst, + config->dst_maxburst, config->slave_id); + + return SPI_MASTER_OK; +} + +#ifdef SPI_INFO_LEVEL +static void spi_dma_tx_callback(void *para) +{ + sunxi_spi_t *sspi = (sunxi_spi_t *)para; + SPI_INFO("[spi%d] DMA TX callback function\n", sspi->port); +} +#endif + +static spi_master_status_t spi_dma_tx_submit(struct sunxi_spi *sspi) +{ + hal_dma_status_t ret; + uint32_t len = sspi->transfer->tx_len; + struct dma_slave_config *config = &sspi->dma_tx.config; + struct sunxi_dma_chan *chan = sspi->dma_tx.chan; + + ret = hal_dma_slave_config(chan, config); + if (ret) + { + SPI_ERR("[spi%d] dma slave config failed! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + + ret = hal_dma_prep_device(chan, config->dst_addr, config->src_addr, len, + config->direction); + if (ret) + { + SPI_ERR("[spi%d] dma prep device failed! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + +#ifdef SPI_INFO_LEVEL + chan->callback = spi_dma_tx_callback; + chan->callback_param = sspi; +#endif + + ret = hal_dma_start(chan); + if (ret) + { + SPI_ERR("[spi%d] dma start error! return %d\n", sspi->port, + ret); + return SPI_MASTER_ERROR; + } + + return SPI_MASTER_OK; +} + +static void spi_dma_rx_callback(void *para) +{ + sunxi_spi_t *sspi = (sunxi_spi_t *)para; + + if (hal_sem_post(sspi->xSemaphore_rx)) + { + SPI_ERR("[spi%d] xSemaphoreGive failed.\n", sspi->port); + } +} + +static spi_master_status_t spi_dma_rx_config(struct sunxi_spi *sspi) +{ + hal_dma_chan_status_t ret; + uint32_t flags = 0; + uint32_t len = sspi->transfer->rx_len, size = 0; + uint8_t *buf = sspi->transfer->rx_buf; + struct dma_slave_config *config = &sspi->dma_rx.config; + + if (NULL == buf) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + + if (len <= ALIGN_DMA_BUF_SIZE) + { + buf = sspi->align_dma_buf; + memset(buf, 0, len); + } + else + { + SPI_ERR("[spi%d] rx size over dma align buf size\n", + sspi->port); + /* buffer on DMA must align to cache line */ + if ((unsigned long)buf & (64 - 1) || len & (64 - 1)) + { + SPI_ERR("[spi%d] rx buf or len not align to 64\n", + sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + } + hal_dcache_invalidate((unsigned long)buf, SPI_ALIGN(len, 64)); + spi_enable_dma_irq(SPI_FIFO_CTL_RX_DRQEN, sspi); + +#ifdef SPI_DUMPREG_LEVEL + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); +#endif + + ret = hal_dma_chan_request(&sspi->dma_rx.chan); + if (ret == HAL_DMA_CHAN_STATUS_BUSY) + { + SPI_ERR("[spi%d] request dma_rx failed\n", sspi->port); + return SPI_MASTER_ERROR; + } + + config->direction = DMA_DEV_TO_MEM; + config->dst_addr = (unsigned long)buf; + config->src_addr = sspi->base + SPI_RXDATA_REG; + + if (len % DMA_SLAVE_BUSWIDTH_4_BYTES) + { + config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config->dst_maxburst = DMA_SLAVE_BURST_16; + config->src_maxburst = DMA_SLAVE_BURST_16; + } + else + { + config->src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + config->dst_maxburst = DMA_SLAVE_BURST_8; + config->src_maxburst = DMA_SLAVE_BURST_8; + } + + config->slave_id = + sunxi_slave_id(DRQDST_SDRAM, SUNXI_SPI_DRQ_RX(sspi->port)); + + SPI_INFO("[spi%d] config:\n" + " direction: %d\n" + " src_addr: 0x%08lx," + " dst_addr: 0x%08lx\n" + " src_addr_width: %d," + " dst_addr_width: %d\n" + " src_maxburst: %lu," + " dst_maxburst: %lu\n" + " slave_id: 0x%08lx\n", + sspi->port, config->direction, config->src_addr, + config->dst_addr, config->src_addr_width, + config->dst_addr_width, config->src_maxburst, + config->dst_maxburst, config->slave_id); + + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_dma_rx_submit(struct sunxi_spi *sspi) +{ + hal_dma_status_t ret; + uint32_t flags = 0; + uint32_t len = sspi->transfer->rx_len, size = 0; + struct sunxi_dma_chan *chan = sspi->dma_rx.chan; + struct dma_slave_config *config = &sspi->dma_rx.config; + + ret = hal_dma_slave_config(chan, config); + if (ret) + { + SPI_ERR("[spi%d] dma slave config failed! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + + ret = hal_dma_prep_device(chan, config->dst_addr, config->src_addr, len, + config->direction); + if (ret) + { + SPI_ERR("[spi%d] dma prep device failed! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + + chan->callback = spi_dma_rx_callback; + chan->callback_param = sspi; + + ret = hal_dma_start(chan); + if (ret) + { + SPI_ERR("[spi%d] dma start error! return %d\n", sspi->port, + ret); + return SPI_MASTER_ERROR; + } + + return SPI_MASTER_OK; +} + +#endif + +static spi_master_status_t spi_transfer(sunxi_spi_t *sspi) +{ + switch (sspi->mode_type) + { + case SGLE_HALF_DUPLEX_RX: + case DUAL_HALF_DUPLEX_RX: + case QUAD_HALF_DUPLEX_RX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->rx_len > BULK_DATA_BOUNDARY) + { + SPI_INFO("[spi%d] rx by dma\n", sspi->port); + /* For Rx mode, the DMA end(not TC flag) is real end. */ + spi_disable_irq(SPI_INTEN_TC, sspi); + if (spi_dma_rx_config(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_rx_submit(sspi)) + { + return SPI_MASTER_ERROR; + } + spi_start_xfer(sspi); + } + else + { +#endif + SPI_INFO("[spi%d] rx by cpu\n", sspi->port); + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_start_xfer(sspi); + spi_cpu_read(sspi); +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + case SGLE_HALF_DUPLEX_TX: + case DUAL_HALF_DUPLEX_TX: + case QUAD_HALF_DUPLEX_TX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->tx_len > BULK_DATA_BOUNDARY) + { + SPI_INFO("[spi%d] tx by dma\n", sspi->port); + sspi->sem = 1; + spi_start_xfer(sspi); + if (spi_dma_tx_config(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_tx_submit(sspi)) + { + return SPI_MASTER_ERROR; + } + } + else + { +#endif + SPI_INFO("[spi%d] tx by cpu\n", sspi->port); + spi_start_xfer(sspi); + spi_cpu_write(sspi); +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + case SINGLE_FULL_DUPLEX_RX_TX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->rx_len > BULK_DATA_BOUNDARY && sspi->transfer->tx_len > BULK_DATA_BOUNDARY) + { + SPI_INFO("[spi%d] tx and rx by dma\n", sspi->port); + /* For Rx mode, the DMA end(not TC flag) is real end. */ + // spi_disable_irq(SPI_INTEN_TC, sspi); + spi_start_xfer(sspi); + sspi->sem = 1; + if (spi_dma_rx_config(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_rx_submit(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_tx_config(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_tx_submit(sspi)) + { + return SPI_MASTER_ERROR; + } + } + else + { +#endif + SPI_INFO("[spi%d] tx and rx by cpu\n", sspi->port); + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_start_xfer(sspi); + spi_cpu_write_read(sspi); +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + case FULL_DUPLEX_TX_RX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->rx_len > BULK_DATA_BOUNDARY) + { + SPI_INFO("[spi%d] tx and rx by dma\n", sspi->port); + /* For Rx mode, the DMA end(not TC flag) is real end. */ + spi_disable_irq(SPI_INTEN_TC, sspi); + spi_start_xfer(sspi); + spi_cpu_write(sspi); + if (spi_dma_rx_config(sspi)) + { + return SPI_MASTER_ERROR; + } + if (spi_dma_rx_submit(sspi)) + { + return SPI_MASTER_ERROR; + } + } + else + { +#endif + SPI_INFO("[spi%d] tx and rx by cpu\n", sspi->port); + spi_start_xfer(sspi); + spi_cpu_write(sspi); + spi_cpu_read(sspi); +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + default: + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + } + + return SPI_MASTER_OK; +} + +/* wake up the sleep thread, and give the result code */ +static hal_irqreturn_t spi_irq_handler(void *ptr) +{ + uint32_t status = 0, enable = 0; + sunxi_spi_t *sspi = (sunxi_spi_t *)ptr; + + enable = spi_qry_irq_enable(sspi); + status = spi_qry_irq_pending(sspi); + spi_clr_irq_pending(status, sspi); + + sspi->result = SPI_XFER_OK; + + /* master mode, Transfer Complete Interrupt */ + if (status & SPI_INT_STA_TC) + { + SPI_INFO("[spi%d] SPI TC COME\n", sspi->port); + spi_disable_irq(SPI_INT_STA_TC | SPI_INT_STA_ERR, sspi); +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + if (sspi->sem) + { + sspi->sem = 0; + if (hal_sem_post(sspi->xSemaphore_tx)) + SPI_ERR("[spi%d] xSemaphorePostFromISR failed.\n", + sspi->port); + } +#endif + return 0; + } + else if (status & SPI_INT_STA_ERR) /* master mode:err */ + { + SPI_ERR("[spi%d] SPI ERR! status %"PRIx32"\n", sspi->port, status); + /* __log("[spi%d] dump reg:\n", sspi->port); */ + /* spi_dump_reg(sspi, 0, 0x60); */ + spi_disable_irq(SPI_INT_STA_TC | SPI_INT_STA_ERR, sspi); + sspi->result = SPI_XFER_FAILED; +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + if (sspi->sem) + { + sspi->sem = 0; + if (hal_sem_post(sspi->xSemaphore_tx)) + SPI_ERR("[spi%d] xSemaphorePostFromISR failed.\n", + sspi->port); + } +#endif + return 0; + } + return 0; +} + +static spi_master_status_t spi_pinctrl_init(sunxi_spi_t *sspi, uint32_t sip) +{ +#ifdef CONFIG_OS_MELIS + user_gpio_set_t gpio_cfg[6] = {0}; + gpio_pin_t spi_pin[6]; + gpio_muxsel_t spi_muxsel[6]; + int count, i; + char spi_name[16]; + int ret = SPI_MASTER_OK; + + if (sspi->port >= HAL_SPI_MASTER_MAX) + { + SPI_ERR("[spi%d] invalid port\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + + sprintf(spi_name, "spi%d", sspi->port); + count = Hal_Cfg_GetGPIOSecKeyCount(spi_name); + if (!count) + { + SPI_ERR("[spi%d] not support in sys_config\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + Hal_Cfg_GetGPIOSecData(spi_name, gpio_cfg, count); + + for (i = 0; i < count; i++) + { + spi_pin[i] = (gpio_cfg[i].port - 1) * 32 + gpio_cfg[i].port_num; + spi_muxsel[i] = gpio_cfg[i].mul_sel; + ret = hal_gpio_pinmux_set_function(spi_pin[i], spi_muxsel[i]); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set function failed! return %d\n", + sspi->port, spi_pin[i], ret); + return SPI_MASTER_ERROR; + } + ret = hal_gpio_set_driving_level(spi_pin[i], gpio_cfg[i].drv_level); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set driving level failed! return %d\n", + sspi->port, gpio_cfg[i].drv_level, ret); + return SPI_MASTER_ERROR; + } + if (gpio_cfg[i].pull) + { + ret = hal_gpio_set_pull(spi_pin[i], gpio_cfg[i].pull); + } + } + + return ret; +#elif defined(CONFIG_ARCH_SUN20IW2) +//#elif 1 + uint8_t i; + gpio_pin_t spi_pin[6]; + int ret = SPI_MASTER_OK; + struct sunxi_spi_params_t *para; + + if (sspi->port >= HAL_SPI_MASTER_MAX) + { + SPI_ERR("[spi%d] invalid port\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } +#ifdef SIP_SPI0_PARAMS + if (sip) { + para = &g_sunxi_spi_params_sip[sspi->port]; + } + else +#endif + { + para = &g_sunxi_spi_params[sspi->port]; + } + + spi_pin[0] = para->gpio_clk; + spi_pin[1] = para->gpio_mosi; + spi_pin[2] = para->gpio_cs0; + spi_pin[3] = para->gpio_miso; + spi_pin[4] = para->gpio_wp; + spi_pin[5] = para->gpio_hold; + + for (i = 0; i < para->gpio_num; i++) + { + ret = hal_gpio_pinmux_set_function(spi_pin[i], + para->mux); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set function failed! return %d\n", + sspi->port, spi_pin[i], ret); + ret = SPI_MASTER_ERROR; + goto err; + } + ret = hal_gpio_set_driving_level(spi_pin[i], + para->driv_level); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set driving level failed! return %d\n", + sspi->port, spi_pin[i], ret); + ret = SPI_MASTER_ERROR; + goto err; + } + if (i == 2) //CS + { + ret = hal_gpio_set_pull(spi_pin[i], GPIO_PULL_UP); + } + else + { + ret = hal_gpio_set_pull(spi_pin[i], GPIO_PULL_DOWN_DISABLED); + } + } + +err: + return ret; +#else + //SPI_ERR("[spi%d] not support sys_config format\n", sspi->port); + uint8_t i; + gpio_pin_t spi_pin[6]; + int ret = SPI_MASTER_OK; + struct sunxi_spi_params_t *para; + + if (sspi->port >= HAL_SPI_MASTER_MAX) + { + SPI_ERR("[spi%d] invalid port\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } +#ifdef SIP_SPI0_PARAMS + if (sip) { + para = &g_sunxi_spi_params_sip[sspi->port]; + } + else +#endif + { + para = &g_sunxi_spi_params[sspi->port]; + } + + spi_pin[0] = para->gpio_clk; + spi_pin[1] = para->gpio_mosi; + spi_pin[2] = para->gpio_cs0; + spi_pin[3] = para->gpio_miso; + spi_pin[4] = para->gpio_wp; + spi_pin[5] = para->gpio_hold; + + for (i = 0; i < para->gpio_num; i++) + { + ret = hal_gpio_pinmux_set_function(spi_pin[i], + para->mux); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set function failed! return %d\n", + sspi->port, spi_pin[i], ret); + ret = SPI_MASTER_ERROR; + goto err; + } + ret = hal_gpio_set_driving_level(spi_pin[i], + para->driv_level); + if (ret) + { + SPI_ERR("[spi%d] PIN%u set driving level failed! return %d\n", + sspi->port, spi_pin[i], ret); + ret = SPI_MASTER_ERROR; + goto err; + } + if (i == 2) //CS + { + ret = hal_gpio_set_pull(spi_pin[i], GPIO_PULL_UP); + } + else + { + ret = hal_gpio_set_pull(spi_pin[i], GPIO_PULL_DOWN_DISABLED); + } + } +err: + return ret; + + +#endif +} + +static spi_master_status_t spi_clk_init(sunxi_spi_t *sspi, u32 mode_clk, struct sunxi_spi_params_t *para) +{ + unsigned long rate; + int rate_pll = 0, rate_hosc = 0; + hal_clk_status_t ret; + hal_clk_t pclk_pll, pclk_hosc; + + sspi->reset = hal_reset_control_get(para->reset_type, para->reset_id); + hal_reset_control_deassert(sspi->reset); + + sspi->mclk = hal_clock_get(para->mclk_type, para->mclk_id); + sspi->bus_clk = hal_clock_get(para->bus_type, para->bus_id); + pclk_pll = hal_clock_get(para->pclk_pll_type, para->pclk_pll_id); + pclk_hosc = hal_clock_get(para->pclk_hosc_type, para->pclk_hosc_id); + + SPI_INFO("[spi%d] get pclk_pll %d\n", sspi->port, hal_clk_get_rate(pclk_pll)); + SPI_INFO("[spi%d] get pclk_hosc %d\n", sspi->port, hal_clk_get_rate(pclk_hosc)); + + if (hal_clk_get_rate(pclk_pll) >= mode_clk) + { + if (!hal_clk_set_parent(sspi->mclk, pclk_pll)) + rate_pll = hal_clk_round_rate(sspi->mclk, mode_clk); + } + if (hal_clk_get_rate(pclk_hosc) >= mode_clk) + { + if (!hal_clk_set_parent(sspi->mclk, pclk_hosc)) + rate_hosc = hal_clk_round_rate(sspi->mclk, mode_clk); + } + + SPI_INFO("[spi%d] get pll rate %d\n", sspi->port, rate_pll); + SPI_INFO("[spi%d] get hosc rate %d\n", sspi->port, rate_hosc); + SPI_INFO("[spi%d] get mode rate %d\n", sspi->port, mode_clk); + + if (abs(rate_pll - mode_clk) < abs(rate_hosc - mode_clk)) + sspi->pclk = pclk_pll; + else + sspi->pclk = pclk_hosc; + + ret = hal_clk_set_parent(sspi->mclk, sspi->pclk); + if (ret) + { + SPI_ERR("[spi%d] clk set parent failed! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + + ret = hal_clk_set_rate(sspi->mclk, mode_clk); + if (ret) + { + SPI_ERR("[spi%d] clk set rate failed! return %d\n", sspi->port, + ret); + return SPI_MASTER_ERROR; + } + + rate = hal_clk_get_rate(sspi->mclk); + if (!rate) + { + SPI_ERR("[spi%d] clk get rate failed! return %ld\n", sspi->port, + rate); + return SPI_MASTER_ERROR; + } + else if (rate != mode_clk) + { + SPI_ERR("[spi%d] clk rate auto adjust to %ld\n", + sspi->port, rate); + } + + ret = hal_clock_enable(sspi->bus_clk); + if (ret) + { + SPI_ERR("[spi%d] couldn't enable bus_clk! return %d\n", sspi->port, + ret); + return SPI_MASTER_ERROR; + } + + ret = hal_clock_enable(sspi->mclk); + if (ret) + { + SPI_ERR("[spi%d] couldn't enable mclk! return %d\n", sspi->port, + ret); + return SPI_MASTER_ERROR; + } + + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_clk_exit(sunxi_spi_t *sspi) +{ + hal_clk_status_t ret; + + ret = hal_clock_disable(sspi->mclk); + if (ret) + { + SPI_ERR("[spi%d] couldn't disable mclk! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + ret = hal_clock_disable(sspi->bus_clk); +#ifdef CONFIG_DRIVERS_SUNXI_CLK + if (ret && ret != HAL_CLK_STATUS_ERROR_CLK_FACTOR_REFUSED) +#else + if (ret) +#endif + { + SPI_ERR("[spi%d] couldn't disable bus_clk! return %d\n", + sspi->port, ret); + return SPI_MASTER_ERROR; + } + + hal_clock_put(sspi->mclk); + hal_clock_put(sspi->bus_clk); + + hal_reset_control_assert(sspi->reset); + hal_reset_control_put(sspi->reset); + + return SPI_MASTER_OK; +} + +static spi_master_status_t spi_cpu_complete(sunxi_spi_t *sspi) +{ + uint32_t timeout = 0xffff; + + SPI_INFO("[spi%d] :wait complete\n", sspi->port); + while (!sspi->result && timeout--) + ; + if (timeout <= 0) + { + SPI_ERR("[spi%d] xfer timeout\n", sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + return SPI_MASTER_ERROR_TIMEOUT; + } + else if (SPI_XFER_FAILED == sspi->result) + { + SPI_ERR("[spi%d] xfer failed...\n", sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + return SPI_MASTER_ERROR; + } + + return SPI_MASTER_OK; +} + +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY +static spi_master_status_t spi_dma_tx_complete(sunxi_spi_t *sspi) +{ + uint32_t flags = 0; + uint32_t timeout = 0x7fffffff; + struct sunxi_dma_chan *chan = sspi->dma_tx.chan; + hal_dma_status_t dma_ret; + spi_master_status_t ret = 0; + int xResult; + + xResult = hal_sem_timedwait(sspi->xSemaphore_tx, 100);//100*10ms + if (xResult == 0) + { + if (SPI_XFER_OK == sspi->result) + { + SPI_INFO("ok\n"); + ret = SPI_MASTER_OK; + } + else if (SPI_XFER_FAILED == sspi->result) + { + SPI_ERR("[spi%d] xfer failed...\n", sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + ret = SPI_MASTER_ERROR; + } + } + else + { + SPI_ERR("[spi%d] dma xfer timeout\n", sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x60); + + sspi->result = SPI_XFER_FAILED; + + if (hal_sem_post(sspi->xSemaphore_tx)) + { + SPI_ERR("[spi%d] xSemaphoreGive failed.\n", sspi->port); + } + + ret = SPI_MASTER_ERROR_TIMEOUT; + } + +end: + + dma_ret = hal_dma_stop(chan); + if (dma_ret) + { + SPI_ERR("[spi%d] dma stop error! ret %d\n", sspi->port, + dma_ret); + return SPI_MASTER_ERROR; + } + + dma_ret = hal_dma_chan_free(chan); + if (dma_ret) + { + SPI_ERR("[spi%d] free dma_tx failed, ret %d\n", sspi->port, + dma_ret); + return SPI_MASTER_ERROR; + } + + return ret; +} + +static spi_master_status_t spi_dma_rx_complete(sunxi_spi_t *sspi) +{ + uint32_t flags = 0; + uint32_t len = sspi->transfer->rx_len, size = 0; + uint8_t *buf = sspi->transfer->rx_buf; + struct sunxi_dma_chan *chan = sspi->dma_rx.chan; + hal_dma_status_t dma_ret; + spi_master_status_t ret; + int xResult; + +#ifdef SPI_DATA_LEVEL + unsigned int i, j; + u8 dbuf[64], cnt = 0; +#endif + + xResult = hal_sem_timedwait(sspi->xSemaphore_rx, 100);//100*10ms + if (xResult != 0) + { + SPI_ERR("[spi%d] dma xfer timeout\n", sspi->port); + SPI_INFO("[spi%d] dump reg:\n", sspi->port); + spi_dump_reg(sspi, 0, 0x40); + + sspi->result = SPI_XFER_FAILED; + + ret = SPI_MASTER_ERROR_TIMEOUT; + goto end; + } + + hal_dcache_invalidate((unsigned long)sspi->align_dma_buf, SPI_ALIGN(len, 64)); + sspi->result = SPI_XFER_OK; + if (len <= ALIGN_DMA_BUF_SIZE) + { + memcpy(buf, sspi->align_dma_buf, len); + } + ret = SPI_MASTER_OK; + SPI_INFO("ok\n"); + +#ifdef SPI_DATA_LEVEL + SPI_INFO("rx_len = %d\n", len); + for (i = 0; i < len; i += 16) + { + cnt = 0; + cnt += sprintf(dbuf + cnt, "%03x: ", i); + for (j = 0; ((i + j) < len) && (j < 16); j++) + cnt += sprintf(dbuf + cnt, "%02x ", + ((uint8_t *)(buf))[i + j]); + printf("%s\n", dbuf); + } +#endif + +end: + spi_disable_irq(SPI_INT_STA_TC | SPI_INT_STA_ERR, sspi); + + dma_ret = hal_dma_stop(chan); + if (dma_ret) + { + SPI_ERR("[spi%d] dma stop error! ret %d\n", sspi->port, + dma_ret); + ret = SPI_MASTER_ERROR; + } + + dma_ret = hal_dma_chan_free(chan); + if (dma_ret) + { + SPI_ERR("[spi%d] free dma_rx failed, ret %d\n", sspi->port, + dma_ret); + return SPI_MASTER_ERROR; + } + + return ret; +} +#endif + +/* + * < 64 : cpu ; >= 64 : dma + * wait for done completion in this function, wakup in the irq hanlder + */ +spi_master_status_t hal_spi_xfer(hal_spi_master_port_t port, + hal_spi_master_transfer_t *transfer) +{ + spi_master_status_t ret = 0; + sunxi_spi_t *sspi = &g_sunxi_spi[port]; + + if (NULL == transfer) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + + SPI_INFO("[spi%d] tl=%lu rl=%lu, tsl=%lu\n", sspi->port, transfer->tx_len, + transfer->rx_len, transfer->tx_single_len); + + if ((!transfer->tx_buf && !transfer->rx_buf) || + (!transfer->tx_len && !transfer->rx_buf)) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + +#ifdef CONFIG_COMPONENTS_PM + pm_wakelocks_acquire(&sspi->wl, PM_WL_TYPE_WAIT_INC, OS_WAIT_FOREVER); +#endif + + sspi->result = SPI_XFER_READY; + sspi->transfer = transfer; + + if (spi_mode_check(sspi)) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_disable_dma_irq(SPI_FIFO_CTL_DRQEN_MASK, sspi); + spi_reset_fifo(sspi); + spi_enable_irq(SPI_INTEN_TC | SPI_INTEN_ERR, sspi); + + if (spi_transfer(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + + switch (sspi->mode_type) + { + case SGLE_HALF_DUPLEX_RX: + case DUAL_HALF_DUPLEX_RX: + case QUAD_HALF_DUPLEX_RX: + case FULL_DUPLEX_TX_RX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->rx_len > BULK_DATA_BOUNDARY) + { + if (spi_dma_rx_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + } + else + { +#endif + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + case SGLE_HALF_DUPLEX_TX: + case DUAL_HALF_DUPLEX_TX: + case QUAD_HALF_DUPLEX_TX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->tx_len > BULK_DATA_BOUNDARY) + { + if (spi_dma_tx_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + } + else + { +#endif + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + case SINGLE_FULL_DUPLEX_RX_TX: + { +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + /* >64 use DMA transfer, or use cpu */ + if (sspi->transfer->rx_len > BULK_DATA_BOUNDARY && sspi->transfer->tx_len > BULK_DATA_BOUNDARY) + { + if (spi_dma_tx_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + if (spi_dma_rx_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + } + else + { +#endif + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + } +#endif + break; + } + default: + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + } + } + +end: + if (sspi->mode_type != MODE_TYPE_NULL) + { + sspi->mode_type = MODE_TYPE_NULL; + } + +#ifdef CONFIG_COMPONENTS_PM + pm_wakelocks_release(&sspi->wl); +#endif + + return ret; +} + +#if 0 +static int sunxi_get_spic_clk(sunxi_spi_t *sspi) +{ + unsigned long rate; + + rate = hal_clk_get_rate(sspi->mclk); + if (!rate) + SPI_ERR("[spi%d] clk get rate failed! return %ld\n", sspi->port, rate); + return rate; +} +#endif + +spi_master_status_t hal_spi_hw_config(hal_spi_master_port_t port, hal_spi_master_config_t *spi_config) +{ + unsigned long clock_frequency; + sunxi_spi_t *sspi = &g_sunxi_spi[port]; + struct sunxi_spi_params_t *para; + + if (NULL == spi_config) + { + SPI_ERR("[spi%d] invalid parameter\n", port); + return SPI_MASTER_INVALID_PARAMETER; + } +#ifdef SIP_SPI0_PARAMS + if (spi_config->sip) { + para = &g_sunxi_spi_params_sip[port]; + } else +#endif + { + para = &g_sunxi_spi_params[port]; + } + + sspi->base = para->reg_base; + sspi->port = port; + sspi->mode_type = MODE_TYPE_NULL; + + if (spi_config->clock_frequency) + clock_frequency = spi_config->clock_frequency; + else + clock_frequency = SPI_MOD_CLK; + + if (clock_frequency > SPI_MAX_FREQUENCY) + { + clock_frequency = SPI_MAX_FREQUENCY; + SPI_ERR("[spi%d] invalid parameter! max_frequency is 100MHZ\n", + sspi->port); + } + else + { + SPI_INIT("[spi%d] clock_frequency = %ldHZ\n", sspi->port, + clock_frequency); + } + + if (clock_frequency >= SPI_HIGH_FREQUENCY) + { + spi_sample_delay(0, 1, sspi); + } + else if (clock_frequency <= SPI_LOW_FREQUENCY) + { + spi_sample_delay(1, 0, sspi); + } + else + { + spi_sample_delay(0, 0, sspi); + } + + if (spi_clk_init(sspi, clock_frequency, para)) + { + SPI_ERR("[spi%d] init clk %ld failed, use default clk\n", sspi->port, clock_frequency); + spi_clk_init(sspi, SPI_MAX_FREQUENCY, para); + } + + if (spi_config->slave_port) + { + SPI_ERR("[spi%d] software control cs isn't support \n", + sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + else + { + spi_set_cs(spi_config->slave_port, sspi); + } + + if (spi_config->bit_order) + { + spi_config_tc(SPI_LSB_FIRST_ACTIVE_, sspi); + } + + spi_config_tc((spi_config->cpol) | (spi_config->cpha), sspi); + + spi_enable_bus(sspi); + spi_set_master(sspi); + spi_enable_tp(sspi); + /*spi controller sends ss signal automatically*/ + spi_ss_owner(sspi, 0); + /* reset fifo */ + spi_reset_fifo(sspi); + + return SPI_MASTER_OK; + +} + +#ifdef CONFIG_COMPONENTS_PM +static int spi_dev_suspend(struct pm_device *dev, suspend_mode_t mode) +{ + sunxi_spi_t *sspi = (sunxi_spi_t *)dev->data; + SPI_INFO("spi_dev_suspend port %d\n", sspi->port); + + spi_disable_bus(sspi); + + hal_disable_irq(sspi->irqnum); + + if (spi_clk_exit(sspi)) + { + SPI_ERR("[spi%d] exit clk error\n", sspi->port); + return -1; + } + + return 0; +} + +static int spi_dev_resume(struct pm_device *dev, suspend_mode_t mode) +{ + sunxi_spi_t *sspi = (sunxi_spi_t *)dev->data; + struct sunxi_spi_params_t *para; + SPI_INFO("spi_dev_resume port %d\n", sspi->port); + +#ifdef SIP_SPI0_PARAMS + if (sspi->config.sip) { + para = &g_sunxi_spi_params_sip[sspi->port]; + } else +#endif + { + para = &g_sunxi_spi_params[sspi->port]; + } + + hal_enable_irq(sspi->irqnum); + + spi_soft_reset(sspi); + + hal_spi_hw_config(sspi->port, &sspi->config); + + return 0; +} + +static struct pm_devops spi_dev_devops = { + .suspend = spi_dev_suspend, + .resume = spi_dev_resume, +}; +#endif + +spi_master_status_t hal_spi_init(hal_spi_master_port_t port, + hal_spi_master_config_t *cfg) +{ + sunxi_spi_t *sspi = &g_sunxi_spi[port]; + struct sunxi_spi_params_t *para; + char irqname[32]; +#ifdef CONFIG_COMPONENTS_PM + char *devicename; + char *wlname; +#endif + + if (port >= HAL_SPI_MASTER_MAX) + { + SPI_ERR("[spi%d] invalid port\n", port); + return SPI_MASTER_ERROR; + } + + if (sspi->used != HAL_SPI_MASTER_IDLE) + { + SPI_ERR("[spi%d] re-init port is in used\n", port); + return SPI_MASTER_ERROR_BUSY; + } + + sspi->used = HAL_SPI_MASTER_BUSY; + +#ifdef SIP_SPI0_PARAMS + if (cfg->sip) { + para = &g_sunxi_spi_params_sip[port]; + } else +#endif + { + para = &g_sunxi_spi_params[port]; + } + + sspi->base = para->reg_base; + sspi->irqnum = para->irq_num; + sspi->port = port; + sspi->mode_type = MODE_TYPE_NULL; + memcpy(&sspi->config, cfg, sizeof(sspi->config)); + + SPI_INFO("spi[%d] init, reg base is %lx \n", port, sspi->base); + + snprintf(irqname, 32, "spi%d", port); + if (hal_request_irq(sspi->irqnum, spi_irq_handler, irqname, sspi) < 0) + { + SPI_ERR("[spi%d] request irq error\n", sspi->port); + return SPI_MASTER_ERROR; + } + hal_enable_irq(sspi->irqnum); + if (spi_pinctrl_init(sspi, cfg->sip)) + { + SPI_ERR("[spi%d] init pinctrl error\n", sspi->port); + return SPI_MASTER_ERROR; + } + + spi_soft_reset(sspi); + + hal_spi_hw_config(port, cfg); + +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + sspi->xSemaphore_tx = hal_sem_create(0); + if (sspi->xSemaphore_tx == NULL) + { + SPI_ERR("[spi%d] creating semaphore_tx failed.\n", sspi->port); + return SPI_MASTER_ERROR; + } + sspi->xSemaphore_rx = hal_sem_create(0); + if (sspi->xSemaphore_rx == NULL) + { + SPI_ERR("[spi%d] creating semaphore_rx failed.\n", sspi->port); + return SPI_MASTER_ERROR; + } + sspi->align_dma_buf = dma_alloc_coherent(ALIGN_DMA_BUF_SIZE); + if (!sspi->align_dma_buf) + { + SPI_ERR("[spi%d] alloc memory failed\n", sspi->port); + return SPI_MASTER_ERROR_NOMEM; + } + SPI_INIT("[spi%d] DMA xfer enable\n", sspi->port); +#else + SPI_INIT("[spi%d] CPU xfer only\n", sspi->port); +#endif + +#ifdef CONFIG_COMPONENTS_PM + wlname = hal_malloc(32); + snprintf(wlname, 32, "spi%d_wakelock", port); + sspi->wl.name = wlname; + sspi->wl.ref = 0; + + devicename = hal_malloc(32); + snprintf(devicename, 32, "spi%d_dev", port); + sspi->pm.name = devicename; + sspi->pm.ops = &spi_dev_devops; + sspi->pm.data = sspi; + + pm_devops_register(&sspi->pm); +#endif + + return SPI_MASTER_OK; +} + +spi_master_status_t hal_spi_deinit(hal_spi_master_port_t port) +{ + sunxi_spi_t *sspi = &g_sunxi_spi[port]; + + if (sspi->used != HAL_SPI_MASTER_BUSY) + { + SPI_ERR("[spi%d] un-used port cannot deinit\n", sspi->port); + return SPI_MASTER_ERROR; + } + + sspi->used = HAL_SPI_MASTER_IDLE; + +#ifdef CONFIG_COMPONENTS_PM + pm_devops_unregister(&sspi->pm); + hal_free((void *)sspi->wl.name); + hal_free((void *)sspi->pm.name); +#endif + + spi_disable_bus(sspi); + + hal_disable_irq(sspi->irqnum); + +#ifndef CONFIG_SUNXI_SPI_CPU_XFER_ONLY + dma_free_coherent(sspi->align_dma_buf); + hal_sem_delete(sspi->xSemaphore_tx); + hal_sem_delete(sspi->xSemaphore_rx); +#endif + + if (spi_clk_exit(sspi)) + { + SPI_ERR("[spi%d] exit clk error\n", sspi->port); + return SPI_MASTER_ERROR; + } + + hal_free_irq(sspi->irqnum); + + return SPI_MASTER_OK; +} + +spi_master_status_t hal_spi_write(hal_spi_master_port_t port, + void *buf, uint32_t size) +{ + spi_master_status_t ret; + hal_spi_master_transfer_t tr; + + tr.tx_buf = buf; + tr.tx_len = size; + tr.rx_buf = NULL; + tr.rx_len = 0; + tr.dummy_byte = 0; + tr.tx_single_len = size; + tr.tx_nbits = SPI_NBITS_SINGLE; + + SPI_INFO("spi[%d] write data,len is %ld \n", port, size); + ret = hal_spi_xfer(port, &tr); + return ret; +} + +spi_master_status_t hal_spi_read(hal_spi_master_port_t port, + void *buf, uint32_t size) +{ + spi_master_status_t ret; + hal_spi_master_transfer_t tr; + + tr.rx_buf = buf; + tr.rx_len = size; + tr.tx_buf = NULL; + tr.tx_len = 0; + tr.dummy_byte = 0; + tr.tx_single_len = size; + tr.rx_nbits = SPI_NBITS_SINGLE; + + SPI_INFO("spi[%d] read data,len is %ld \n", port, size); + ret = hal_spi_xfer(port, &tr); + return ret; +} + +#ifdef CONFIG_DRIVERS_SPI_PANIC_TRANSFER +static spi_master_status_t spi_panic_transfer(sunxi_spi_t *sspi) +{ + switch (sspi->mode_type) + { + case SGLE_HALF_DUPLEX_RX: + case DUAL_HALF_DUPLEX_RX: + case QUAD_HALF_DUPLEX_RX: + { + SPI_INFO("[spi%d] rx by cpu\n", sspi->port); + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_start_xfer(sspi); + spi_cpu_read(sspi); + break; + } + case SGLE_HALF_DUPLEX_TX: + case DUAL_HALF_DUPLEX_TX: + case QUAD_HALF_DUPLEX_TX: + { + SPI_INFO("[spi%d] tx by cpu\n", sspi->port); + spi_start_xfer(sspi); + spi_cpu_write(sspi); + break; + } + case SINGLE_FULL_DUPLEX_RX_TX: + { + SPI_INFO("[spi%d] tx and rx by cpu\n", sspi->port); + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_start_xfer(sspi); + spi_cpu_write_read(sspi); + break; + } + case FULL_DUPLEX_TX_RX: + { + SPI_INFO("[spi%d] tx and rx by cpu\n", sspi->port); + spi_start_xfer(sspi); + spi_cpu_write(sspi); + spi_cpu_read(sspi); + break; + } + default: + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + return SPI_MASTER_INVALID_PARAMETER; + } + } + + return SPI_MASTER_OK; +} + +/* + * < 64 : cpu ; >= 64 : dma + * wait for done completion in this function, wakup in the irq hanlder + */ +spi_master_status_t hal_spi_panic_xfer(hal_spi_master_port_t port, + hal_spi_master_transfer_t *transfer) +{ + uint32_t flags = 0; + spi_master_status_t ret = 0; + sunxi_spi_t *sspi = &g_sunxi_spi[port]; + + if (NULL == transfer) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + + SPI_INFO("[spi%d] tl=%lu rl=%lu, tsl=%lu\n", sspi->port, transfer->tx_len, + transfer->rx_len, transfer->tx_single_len); + + if ((!transfer->tx_buf && !transfer->rx_buf) || + (!transfer->tx_len && !transfer->rx_buf)) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + + sspi->result = SPI_XFER_READY; + sspi->transfer = transfer; + + if (spi_mode_check(sspi)) + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + goto end; + } + + spi_clr_irq_pending(SPI_INT_STA_MASK, sspi); + spi_disable_dma_irq(SPI_FIFO_CTL_DRQEN_MASK, sspi); + spi_reset_fifo(sspi); + spi_enable_irq(SPI_INTEN_TC | SPI_INTEN_ERR, sspi); + + if (spi_panic_transfer(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + + switch (sspi->mode_type) + { + case SGLE_HALF_DUPLEX_RX: + case DUAL_HALF_DUPLEX_RX: + case QUAD_HALF_DUPLEX_RX: + case FULL_DUPLEX_TX_RX: + { + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } + break; + } + case SGLE_HALF_DUPLEX_TX: + case DUAL_HALF_DUPLEX_TX: + case QUAD_HALF_DUPLEX_TX: + { + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } + break; + } + case SINGLE_FULL_DUPLEX_RX_TX: + { + if (spi_cpu_complete(sspi)) + { + ret = SPI_MASTER_ERROR; + goto end; + } + else + { + ret = SPI_MASTER_OK; + } + break; + } + default: + { + SPI_ERR("[spi%d] invalid parameter\n", sspi->port); + ret = SPI_MASTER_INVALID_PARAMETER; + } + } +end: + if (sspi->mode_type != MODE_TYPE_NULL) + { + sspi->mode_type = MODE_TYPE_NULL; + } + + return ret; +} +#endif + diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform/spi_sun8iw21.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform/spi_sun8iw21.h new file mode 100755 index 00000000..0c7dda2c --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform/spi_sun8iw21.h @@ -0,0 +1,93 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY��S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS��SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY��S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __SPI_SUN8IW21_H__ +#define __SPI_SUN8IW21_H__ + +#define SUNXI_SPI0_PBASE (0x04025000ul) /* 4K */ +#define SUNXI_SPI1_PBASE (0x04026000ul) /* 4K */ +#define SUNXI_SPI2_PBASE (0x04027000ul) /* 4K */ +#define SUNXI_SPI3_PBASE (0x04028000ul) /* 4K */ +#ifdef CONFIG_SOC_SUN20IW3 +#define SUNXI_IRQ_SPI0 31 +#define SUNXI_IRQ_SPI1 32 +#define SUNXI_IRQ_SPI2 33 +#define SUNXI_IRQ_SPI3 37 +#else +#define SUNXI_IRQ_SPI0 47 +#define SUNXI_IRQ_SPI1 48 +#define SUNXI_IRQ_SPI2 49 +#define SUNXI_IRQ_SPI3 53 +#endif + +#define SPI_MAX_NUM 4 +#define SPI0_PARAMS \ +{ .port = 0, \ + .reg_base = SUNXI_SPI0_PBASE, .irq_num = SUNXI_IRQ_SPI0, \ + .pclk_pll_type = HAL_SUNXI_CCU, .pclk_pll_id = HAL_CLK_PLL_PERI0300M, \ + .pclk_hosc_type = HAL_SUNXI_CCU, .pclk_hosc_id = HAL_CLK_SRC_HOSC, \ + .bus_type = HAL_SUNXI_CCU, .bus_id = 0, \ + .mclk_type = HAL_SUNXI_CCU, .mclk_id = HAL_CLK_PERIPH_SPI0, \ + .reset_type = HAL_SUNXI_RESET, .reset_id = 0, \ +} + +#define SPI1_PARAMS \ +{ .port = 1, \ + .reg_base = SUNXI_SPI1_PBASE, .irq_num = SUNXI_IRQ_SPI1, \ + .pclk_pll_type = HAL_SUNXI_CCU, .pclk_pll_id = HAL_CLK_PLL_PERI0300M, \ + .pclk_hosc_type = HAL_SUNXI_CCU, .pclk_hosc_id = HAL_CLK_SRC_HOSC, \ + .bus_type = HAL_SUNXI_CCU, .bus_id = 0, \ + .mclk_type = HAL_SUNXI_CCU, .mclk_id = HAL_CLK_PERIPH_SPI1, \ + .reset_type = HAL_SUNXI_RESET, .reset_id = 0, \ +} + +#define SPI2_PARAMS \ +{ .port = 2, \ + .reg_base = SUNXI_SPI2_PBASE, .irq_num = SUNXI_IRQ_SPI2, \ + .pclk_pll_type = HAL_SUNXI_CCU, .pclk_pll_id = HAL_CLK_PLL_PERI0300M, \ + .pclk_hosc_type = HAL_SUNXI_CCU, .pclk_hosc_id = HAL_CLK_SRC_HOSC, \ + .bus_type = HAL_SUNXI_CCU, .bus_id = 0, \ + .mclk_type = HAL_SUNXI_CCU, .mclk_id = HAL_CLK_PERIPH_SPI2, \ + .reset_type = HAL_SUNXI_RESET, .reset_id = 0, \ +} + +#define SPI3_PARAMS \ +{ .port = 3, \ + .reg_base = SUNXI_SPI3_PBASE, .irq_num = SUNXI_IRQ_SPI3, \ + .pclk_pll_type = HAL_SUNXI_CCU, .pclk_pll_id = HAL_CLK_PLL_PERI0300M, \ + .pclk_hosc_type = HAL_SUNXI_CCU, .pclk_hosc_id = HAL_CLK_SRC_HOSC, \ + .bus_type = HAL_SUNXI_CCU, .bus_id = 0, \ + .mclk_type = HAL_SUNXI_CCU, .mclk_id = HAL_CLK_PERIPH_SPI3, \ + .reset_type = HAL_SUNXI_RESET, .reset_id = 0, \ +} + +#endif /*__SPI_SUN8IW21_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform_spi.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform_spi.h new file mode 100755 index 00000000..2ee16258 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/spi/platform_spi.h @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the People's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY’S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS’SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY’S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef __PLATFORM_SPI_H__ +#define __PLATFORM_SPI_H__ + +#include +#include +#include + +struct sunxi_spi_params_t { + uint8_t port; + unsigned long reg_base; + uint16_t irq_num; + /* clock */ + hal_clk_type_t pclk_pll_type; + hal_clk_id_t pclk_pll_id; + hal_clk_type_t pclk_hosc_type; + hal_clk_id_t pclk_hosc_id; + hal_clk_type_t bus_type; + hal_clk_id_t bus_id; + hal_clk_type_t mclk_type; + hal_clk_id_t mclk_id; + hal_reset_type_t reset_type; + u32 reset_id; + /* gpio */ + uint8_t gpio_num; + gpio_pin_t gpio_clk; + gpio_pin_t gpio_mosi; + gpio_pin_t gpio_miso; + gpio_pin_t gpio_cs0; + gpio_pin_t gpio_wp; + gpio_pin_t gpio_hold; + uint8_t mux; + uint8_t driv_level; +}; + + +#if defined(CONFIG_ARCH_SUN8IW18P1) +#include "platform/spi_sun8iw18.h" +#endif + +#if defined(CONFIG_ARCH_SUN8IW19) +#include "platform/spi_sun8iw19.h" +#endif + +#if defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_SOC_SUN20IW1) +#include "platform/spi_sun8iw20.h" +#endif + +#if defined(CONFIG_ARCH_SUN20IW2) +#include "platform/spi_sun20iw2.h" +#endif + +#if defined(CONFIG_ARCH_SUN8IW21) || defined(CONFIG_ARCH_SUN20IW3) +#include "platform/spi_sun8iw21.h" +#endif + +#if defined(CONFIG_ARCH_SUN55IW3) +#include "platform/spi_sun55iw3.h" +#endif + +#endif /* __PLATFORM_SPI_H__ */ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/common_twi.h b/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/common_twi.h index 0aed7e65..8b9329db 100644 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/common_twi.h +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/common_twi.h @@ -210,7 +210,7 @@ extern "C" { #define ADDR_BYTE (0xff<<16) /* Offset:0x0210. Twi driver bus control register(Default Value:0x0000_00C0) */ -#define TWI_DRV_CLK_DUTY (0x01<<16) +#define TWI_DRV_CLK_DUTY (0x01<<15) #define TWI_DRV_CLK_M (0x0f<<8) #define TWI_DRV_CLK_N (0x07<<12) @@ -280,6 +280,8 @@ extern "C" { #define TWI_PIN_NUM 2 /*pin num of twi*/ +#define OSC24M (24000000) + #ifdef __cplusplus } #endif diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/hal_twi.c b/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/hal_twi.c index 8639f95c..536541cf 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/hal_twi.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/source/twi/hal_twi.c @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include #include @@ -95,19 +93,26 @@ static void twi_clk_write_reg(hal_twi_t *twi, unsigned int reg_clk, { const unsigned long base_addr = twi->base_addr; unsigned int reg_val = readl(base_addr + reg_clk); + u32 duty; if (reg_clk == TWI_DRIVER_BUSC) { reg_val &= ~(mask_clk_m | mask_clk_n); reg_val |= ((clk_m | (clk_n << 4)) << 8); - writel(reg_val, base_addr + reg_clk); + duty = TWI_DRV_CLK_DUTY; } else { reg_val &= ~(mask_clk_m | mask_clk_n); reg_val |= ((clk_m << 3) | clk_n); - writel(reg_val, base_addr + reg_clk); + duty = TWI_CLK_DUTY; } + if (twi->freq > TWI_FREQUENCY_100K) + reg_val |= duty; + else + reg_val &= ~(duty); + + writel(reg_val, base_addr + reg_clk); } /* @@ -1699,13 +1704,18 @@ twi_status_t hal_twi_xfer(twi_port_t port, twi_msg_t *msgs, int32_t num) return TWI_STATUS_INVALID_PARAMETER; } +#ifdef CONFIG_COMPONENTS_PM + pm_wakelocks_acquire(&twi->wl, PM_WL_TYPE_WAIT_INC, OS_WAIT_FOREVER); +#endif + if (twi->twi_drv_used) { TWI_INFO("[twi%d] twi driver xfer", twi->port); ret = hal_twi_drv_do_xfer(twi, msgs, num); if (ret < 0) { - return TWI_STATUS_ERROR; + ret = TWI_STATUS_ERROR; + goto end; } } else @@ -1714,10 +1724,15 @@ twi_status_t hal_twi_xfer(twi_port_t port, twi_msg_t *msgs, int32_t num) ret = hal_twi_engine_do_xfer(twi, msgs, num); if (ret < 0) { - return TWI_STATUS_ERROR; + ret = TWI_STATUS_ERROR; + goto end; } } +end: +#ifdef CONFIG_COMPONENTS_PM + pm_wakelocks_release(&twi->wl); +#endif return ret == num ? TWI_STATUS_OK : TWI_STATUS_ERROR; } @@ -1733,7 +1748,7 @@ static twi_status_t hal_twi_sys_pinctrl_init(hal_twi_t *twi) count = Hal_Cfg_GetGPIOSecKeyCount(twi_name); if (!count) { - TWI_ERR("[twi%d] not support in sys_config\n", twi->port); + TWI_WARN("[twi%d] not support in sys_config\n", twi->port); return TWI_STATUS_ERROR; } Hal_Cfg_GetGPIOSecData(twi_name, gpio_cfg, count); @@ -1926,76 +1941,78 @@ static twi_status_t hal_twi_clk_init(hal_twi_t *twi) } #else - rate =24000000; + //rate =OSC24M; /* use hal_clk_get_rate */ hal_clk_type_t clk_type = HAL_SUNXI_CCU; hal_clk_id_t twi_clk_id; - hal_clk_t clk; - hal_reset_type_t reset_type = HAL_SUNXI_RESET; hal_reset_id_t twi_reset_id; - struct reset_control *reset; switch (twi->port) { - case 0: - twi_clk_id = SUNXI_CLK_TWI(0); - twi_reset_id = SUNXI_CLK_RST_TWI(0); - break; - case 1: - twi_clk_id = SUNXI_CLK_TWI(1); - twi_reset_id = SUNXI_CLK_RST_TWI(1); - break; + case 0: + twi_clk_id = SUNXI_CLK_TWI(0); + twi_reset_id = SUNXI_CLK_RST_TWI(0); + break; + case 1: + twi_clk_id = SUNXI_CLK_TWI(1); + twi_reset_id = SUNXI_CLK_RST_TWI(1); + break; #if !defined(CONFIG_ARCH_SUN20IW2) - case 2: - twi_clk_id = SUNXI_CLK_TWI(2); - twi_reset_id = SUNXI_CLK_RST_TWI(2); - break; - case 3: - twi_clk_id = SUNXI_CLK_TWI(3); - twi_reset_id = SUNXI_CLK_RST_TWI(3); - break; + case 2: + twi_clk_id = SUNXI_CLK_TWI(2); + twi_reset_id = SUNXI_CLK_RST_TWI(2); + break; + case 3: + twi_clk_id = SUNXI_CLK_TWI(3); + twi_reset_id = SUNXI_CLK_RST_TWI(3); + break; #endif #ifdef CONFIG_ARCH_SUN20IW3 - case 4: - twi_clk_id = SUNXI_CLK_TWI(4); - twi_reset_id = SUNXI_CLK_RST_TWI(4); - break; + case 4: + twi_clk_id = SUNXI_CLK_TWI(4); + twi_reset_id = SUNXI_CLK_RST_TWI(4); + break; #endif - default: - TWI_ERR("twi%d is invalid\n", twi->port); - return TWI_STATUS_ERROR; + default: + TWI_ERR("twi%d is invalid\n", twi->port); + return TWI_STATUS_ERROR; } if (twi_reset_id) { - reset = hal_reset_control_get(reset_type, twi_reset_id); - if (!reset) + twi->reset = hal_reset_control_get(reset_type, twi_reset_id); + if (!twi->reset) { - TWI_ERR("twi reset control get error"); + TWI_ERR("twi reset control get error"); return TWI_STATUS_ERROR; } - hal_reset_control_deassert(reset); - hal_reset_control_put(reset); + hal_reset_control_reset(twi->reset); } - clk = hal_clock_get(clk_type, twi_clk_id); - if (!clk) + twi->clk = hal_clock_get(clk_type, twi_clk_id); + if (!twi->clk) { - TWI_ERR("twi clock get error "); - return TWI_STATUS_ERROR; + TWI_ERR("twi clock get error "); + return TWI_STATUS_ERROR; + } + + rate = hal_clk_get_rate(twi->clk); + if (!rate) { + TWI_INFO("twi%d fail to get twi clk rate, use 24M\n", twi->port); + rate = OSC24M; /* FIXME: fixed to 24MHz */ } - if (hal_clock_enable(clk)) + if (hal_clock_enable(twi->clk)) { - TWI_ERR("twi clock enable error\n"); - return TWI_STATUS_ERROR; + TWI_ERR("twi clock enable error\n"); + return TWI_STATUS_ERROR; } #endif if (twi->twi_drv_used) { - twi_set_clock(twi, TWI_DRIVER_BUSC, 24000000, twi->freq, + twi_set_clock(twi, TWI_DRIVER_BUSC, OSC24M, twi->freq, TWI_DRV_CLK_M, TWI_DRV_CLK_N); twi_enable(twi->base_addr, TWI_DRIVER_CTRL, TWI_DRV_EN); } @@ -2006,6 +2023,8 @@ static twi_status_t hal_twi_clk_init(hal_twi_t *twi) twi_enable(twi->base_addr, TWI_CTL_REG, TWI_CTL_BUSEN); } + TWI_INFO("twi clock_reg is %x\n", readl(twi->base_addr + TWI_CLK_REG)); + return TWI_STATUS_OK; } @@ -2014,12 +2033,54 @@ static void hal_twi_clk_exit(hal_twi_t *twi) /* disable twi bus */ twi_disable(twi->base_addr, TWI_DRIVER_CTRL, TWI_DRV_EN); - //hal_clock_disable(twi->mclk); +#if !(defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN20IW2) || defined(CONFIG_ARCH_SUN20IW3)) + hal_clock_disable(twi->mclk); +#else + hal_clock_disable(twi->clk); + hal_reset_control_assert(twi->reset); +#endif } +#ifdef CONFIG_COMPONENTS_PM +static int hal_twi_suspend(struct pm_device *dev, suspend_mode_t mode) +{ + hal_twi_t *twi = (hal_twi_t *)dev->data; + + hal_disable_irq(twi->irqnum); + hal_twi_pinctrl_exit(twi); + hal_twi_clk_exit(twi); + + TWI_ERR("[twi%d] suspend\n", twi->port); + return 0; +} + +static int hal_twi_resume(struct pm_device *dev, suspend_mode_t mode) +{ + hal_twi_t *twi = (hal_twi_t *)dev->data; + + hal_twi_clk_init(twi); + + if (hal_twi_sys_pinctrl_init(twi)) { + if (hal_twi_pinctrl_init(twi)) { + TWI_ERR("[twi%d] pinctrl init error\n", twi->port); + return TWI_STATUS_ERROR; + } + } + + hal_enable_irq(twi->irqnum); + + TWI_ERR("[twi%d] resume\n", twi->port); + return 0; +} + +struct pm_devops pm_twi_ops = { + .suspend = hal_twi_suspend, + .resume = hal_twi_resume, +}; +#endif + twi_status_t hal_twi_init(twi_port_t port) { - char irqname[32]; hal_twi_t *twi = &hal_twi[port]; if (twi->already_init) //if twi has been inited, return ok @@ -2077,16 +2138,16 @@ twi_status_t hal_twi_init(twi_port_t port) goto errclk; } - if (hal_twi_sys_pinctrl_init(twi)) { - if (hal_twi_pinctrl_init(twi)) { - TWI_ERR("[twi%d] pinctrl init error", port); - goto errpin; - } - } + if (hal_twi_sys_pinctrl_init(twi)) { + if (hal_twi_pinctrl_init(twi)) { + TWI_ERR("[twi%d] pinctrl init error", port); + goto errpin; + } + } - snprintf(irqname, 32, "twi%d", port); + snprintf(twi->irqname, 32, "twi%d", port); - if (hal_request_irq(twi->irqnum, hal_twi_handler, irqname, twi) < 0) + if (hal_request_irq(twi->irqnum, hal_twi_handler, twi->irqname, twi) < 0) { TWI_ERR("[twi%d] request irq error", twi->port); goto errirq; @@ -2099,6 +2160,16 @@ twi_status_t hal_twi_init(twi_port_t port) hal_dma_chan_request(&twi->dma_chan); } +#ifdef CONFIG_COMPONENTS_PM + twi->wl.name = twi->irqname; + twi->wl.ref = 0; + twi->pm.name = twi->irqname; + twi->pm.ops = &pm_twi_ops; + twi->pm.data = twi; + + pm_devops_register(&twi->pm); +#endif + twi->already_init++; return TWI_STATUS_OK; @@ -2134,13 +2205,16 @@ twi_status_t hal_twi_uninit(twi_port_t port) twi->already_init--; if (twi->already_init == 0) { +#ifdef CONFIG_COMPONENTS_PM + pm_devops_unregister(&twi->pm); +#endif hal_disable_irq(twi->irqnum); hal_free_irq(twi->irqnum); hal_twi_pinctrl_exit(twi); - if (twi->twi_drv_used) - { + if (twi->twi_drv_used) + { hal_dma_chan_free(twi->dma_chan); - } + } hal_twi_clk_exit(twi); #if !(defined(CONFIG_ARCH_SUN8IW18P1) || defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_DSP)) hal_twi_regulator_exit(twi); diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/test/Makefile index d933c07d..ad7fd42c 100644 --- a/Software/BSP/e907_rtos/rtos-hal/hal/test/Makefile +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/Makefile @@ -3,6 +3,8 @@ obj-$(CONFIG_HAL_TEST_GPIO) += gpio/ obj-$(CONFIG_HAL_TEST_DMA) += dma/ obj-$(CONFIG_HAL_TEST_UART) += uart/ obj-$(CONFIG_HAL_TEST_TWI) += twi/ +obj-$(CONFIG_HAL_TEST_SPI) += spi/ obj-$(CONFIG_HAL_TEST_PWM) += pwm/ obj-$(CONFIG_HAL_TEST_RTC) += rtc/ obj-$(CONFIG_HAL_TEST_MSGBOX) += msgbox/ +obj-$(CONFIG_HAL_TEST_GPADC) += gpadc/ diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/Makefile new file mode 100644 index 00000000..381fd6a7 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/Makefile @@ -0,0 +1 @@ +obj-y += test_gpadc.o diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/test_gpadc.c b/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/test_gpadc.c new file mode 100644 index 00000000..8cdadcfa --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/gpadc/test_gpadc.c @@ -0,0 +1,91 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the people's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY'S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS'SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY'S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include +#include + +#include +#include +#include + +int channel = -1; + +int sunxigpadc_irq_callback(uint32_t dada_type, uint32_t data) +{ + int vol_data; + data = ((VOL_RANGE / 4096) * data); + vol_data = data / 1000; + printf("channel %d vol data: %d\n", channel, vol_data); + //hal_gpadc_channel_exit(channel); + //hal_gpadc_deinit(); + return 0; +} + +int cmd_test_gpadc(int argc, char **argv) +{ + int ret = -1; + uint32_t vol_data; + + printf("Run gpadc test\n"); + + if (argc < 2) + { + hal_log_err("usage: hal_gpadc channel\n"); + return -1; + } + + ret = hal_gpadc_init(); + if (ret) { + hal_log_err("gpadc init failed!\n"); + return -1; + } + + channel = strtol(argv[1], NULL, 0); + + if (channel < 0 || channel > CHANNEL_NUM) + { + hal_log_err("channel %d is wrong, must between 0 and %d\n", CHANNEL_NUM); + return -1; + } + + hal_gpadc_channel_init(channel); + //hal_gpadc_register_callback(channel, sunxigpadc_irq_callback); + + vol_data = gpadc_read_channel_data(channel); + printf("channel %d vol data is %u\n", channel, vol_data); + + return 0; +} + +FINSH_FUNCTION_EXPORT_CMD(cmd_test_gpadc, hal_gpadc, gpadc hal APIs tests) diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/pwm/test_pwm.c b/Software/BSP/e907_rtos/rtos-hal/hal/test/pwm/test_pwm.c index f474d3db..ef1a1e3b 100644 --- a/Software/BSP/e907_rtos/rtos-hal/hal/test/pwm/test_pwm.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/pwm/test_pwm.c @@ -45,22 +45,25 @@ static int cmd_test_pwm(int argc, char **argv) struct pwm_config *config; uint8_t port; uint8_t ns; + ulong period, duty; - if (argc < 2) + if (argc < 4) { - hal_log_info("Usage: pwm port"); + hal_log_info("Usage: pwm port | duty | period\n"); return -1; } - hal_log_info("Run pwm hal layer test case "); + hal_log_info("Run pwm hal layer test case\n"); port = strtol(argv[1], NULL, 0); hal_log_info("port = %d", port); + duty = strtoul(argv[2], NULL, 0); + period = strtoul(argv[3], NULL, 0); config = (struct pwm_config *)malloc(sizeof(struct pwm_config)); - config->duty_ns = 7000000; - config->period_ns = 10000000; + config->duty_ns = duty; + config->period_ns = period; config->polarity = PWM_POLARITY_NORMAL; hal_log_info("duty_ns = %d \n", config->duty_ns); hal_log_info("period_ns = %d \n", config->period_ns); @@ -70,9 +73,37 @@ static int cmd_test_pwm(int argc, char **argv) hal_pwm_control(port, config); - hal_log_info("Pwm test finish"); + hal_log_info("control pwm test finish\n"); return 0; } FINSH_FUNCTION_EXPORT_CMD(cmd_test_pwm, hal_pwm, pwm hal APIs tests) + +static int cmd_release_pwm_channel(int argc, char **argv) +{ + + struct pwm_config *config; + uint8_t port; + uint8_t ns; + ulong period, duty; + + if (argc < 2) + { + hal_log_info("Usage: pwm port\n"); + return -1; + } + + hal_log_info("Run close pwm channel test case\n"); + + port = strtol(argv[1], NULL, 0); + hal_log_info("port = %d", port); + + hal_pwm_release(port); + + hal_log_info("release pwm channel finish\n"); + + return 0; +} + +FINSH_FUNCTION_EXPORT_CMD(cmd_release_pwm_channel, hal_pwm_close, release pwm channel hal APIs tests) diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/Makefile b/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/Makefile new file mode 100644 index 00000000..de96cbc4 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/Makefile @@ -0,0 +1 @@ +obj-y += test_spi.o diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/test_spi.c b/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/test_spi.c new file mode 100644 index 00000000..c08c3688 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/spi/test_spi.c @@ -0,0 +1,274 @@ +/* +* Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved. +* +* Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in +* the the people's Republic of China and other countries. +* All Allwinner Technology Co.,Ltd. trademarks are used with permission. +* +* DISCLAIMER +* THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT. +* IF YOU NEED TO INTEGRATE THIRD PARTY'S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.) +* IN ALLWINNERS'SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN +* ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES. +* ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS +* COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE. +* YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY'S TECHNOLOGY. +* +* +* THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT +* PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND, +* WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING +* THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE +* OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +* IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +* OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define TEST_READ 0 +#define TEST_WRITE 1 + +static int cmd_test_spi(int argc, const char **argv) +{ + hal_spi_master_port_t port; + hal_spi_master_config_t cfg; + char tbuf[10]={0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20}; + char rbuf[10]; + char rw = 1; + int c; + + if (argc < 3) + { + printf("Usage:\n"); + printf("\thal_spi <-r|-w>\n"); + return -1; + } + + printf("Run spi test\n"); + + port = strtol(argv[1], NULL, 0); + while ((c = getopt(argc, (char *const *)argv, "r:w")) != -1) + { + switch (c) + { + case 'r': + rw = TEST_READ; + break; + case 'w': + rw = TEST_WRITE; + break; + } + } + + cfg.clock_frequency = 5000000; + cfg.slave_port = HAL_SPI_MASTER_SLAVE_0; + cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE0; + cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY0; + cfg.sip = 0; + cfg.flash = 0; + hal_spi_init(port, &cfg); + if (rw == TEST_READ) + { + hal_spi_read(port, rbuf, 10); + printf("rbuf: %s\n", rbuf); + } + else if (rw == TEST_WRITE) + { + hal_spi_write(port, tbuf, 10); + } + + printf("Spi test finish\n"); + + hal_spi_deinit(port); + + return 0; +} + +FINSH_FUNCTION_EXPORT_CMD(cmd_test_spi, hal_spi, spi hal APIs tests) + +static int cmd_test_spi_quad(int argc, const char **argv) +{ + hal_spi_master_port_t port; + hal_spi_master_config_t cfg; + char tbuf[10]={0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20}; + char rbuf[10]; + + if (argc < 2) + { + printf("Usage:\n"); + printf("\thal_spi_quad \n"); + return -1; + } + + printf("Run spi quad test\n"); + + port = strtol(argv[1], NULL, 0); + + cfg.clock_frequency = 5000000; + cfg.slave_port = HAL_SPI_MASTER_SLAVE_0; + cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE0; + cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY0; + cfg.sip = 0; + cfg.flash = 0; + hal_spi_init(port, &cfg); + hal_spi_master_transfer_t tr; + tr.tx_buf = (uint8_t *)tbuf; + tr.tx_len = 10; + tr.rx_buf = (uint8_t *)rbuf; + tr.rx_len = 0; + tr.tx_nbits = SPI_NBITS_QUAD; + tr.tx_single_len = 10; + tr.dummy_byte = 0; + hal_spi_xfer(port, &tr); + + printf("Spi test finish\n"); + + hal_spi_deinit(port); + + return 0; +} + +FINSH_FUNCTION_EXPORT_CMD(cmd_test_spi_quad, hal_spi_quad, spi hal APIs tests) + +static int cmd_test_spi_loop(int argc, const char **argv) +{ + hal_spi_master_port_t port; + hal_spi_master_config_t cfg; + hal_spi_master_transfer_t tr; + char *tbuf = NULL; + char *rbuf = NULL; + int size = 0; + int i, j, loop; + struct timeval start, end; + int sucess = 0, failed = 0; + unsigned long time = 0; + double tr_speed = 0.0f; + + if (argc < 2) + { + printf("Usage:\n"); + printf("\t%s init \n", argv[0]); + printf("\t%s deinit \n", argv[0]); + printf("\t%s loop_test \n", argv[0]); + return -1; + } + + printf("Run spi loop test\n"); + + port = strtol(argv[2], NULL, 0); + + if (!strcmp(argv[1], "init")) + { + cfg.clock_frequency = strtol(argv[3], NULL, 0); + cfg.slave_port = HAL_SPI_MASTER_SLAVE_0; + cfg.cpha = HAL_SPI_MASTER_CLOCK_PHASE0; + cfg.cpol = HAL_SPI_MASTER_CLOCK_POLARITY0; + cfg.sip = 0; + cfg.flash = 0; + hal_spi_init(port, &cfg); + } + else if (!strcmp(argv[1], "deinit")) + { + hal_spi_deinit(port); + } + else if (!strcmp(argv[1], "loop_test")) + { + size = strtol(argv[3], NULL, 0); + loop = strtol(argv[4], NULL, 0); + tbuf = hal_malloc(size); + rbuf = hal_malloc(size); + if (!(tbuf && rbuf)) + { + printf("Request buffer size %d failed\n", size); + return 0; + } + + /* Init buffer data */ + for (i = 0; i < size; i++) + { + tbuf[i] = i & 0xFF; + } + + tr.tx_buf = (uint8_t *)tbuf; + tr.tx_len = size; + tr.tx_nbits = SPI_NBITS_SINGLE; + tr.tx_single_len = size; + tr.rx_buf = (uint8_t *)rbuf; + tr.rx_len = size; + tr.rx_nbits = SPI_NBITS_SINGLE; + + for (i = 0; i < loop; i++) + { + printf("loop test round %d\n", i); + + if (tr.tx_len <= 32) + { + printf("tbuf: "); + for (j = 0; j < tr.tx_len; j++) + { + printf("%02X ", tr.tx_buf[j]); + } + printf("\n"); + } + + memset(tr.rx_buf, 0, tr.rx_len); + gettimeofday(&start, NULL); + hal_spi_xfer(port, &tr); + gettimeofday(&end, NULL); + + if (tr.rx_len <= 32) + { + printf("rbuf: "); + for (j = 0; j < tr.rx_len; j++) + { + printf("%02X ", tr.rx_buf[j]); + } + printf("\n"); + } + + if (!memcmp(tr.tx_buf, tr.rx_buf, size)) + { + sucess++; + time += (1000000 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec); + printf("compare with tbuf rbuf %d : pass\n", size); + } + else + { + failed++; + printf("compare with tbuf rbuf %d : failed\n", size); + } + + hal_msleep(5); + } + + hal_free((void *)tbuf); + hal_free((void *)rbuf); + + printf("compare buffer total %d : sucess %d, failed %d\n", loop, sucess, failed); + tr_speed = ((double)(size*sucess) / 1024.0f / 1024.0f) / ((double)time / 1000.0f / 1000.0f); + printf("Transfer %d take %ld us (%lf MB/s)\n", size*sucess, time, tr_speed); + } + + printf("Spi test finish\n"); + + return 0; +} + +FINSH_FUNCTION_EXPORT_CMD(cmd_test_spi_loop, hal_spi_loop, spi hal APIs tests) diff --git a/Software/BSP/e907_rtos/rtos-hal/hal/test/twi/test_twi.c b/Software/BSP/e907_rtos/rtos-hal/hal/test/twi/test_twi.c index 04bb1287..854bd30e 100755 --- a/Software/BSP/e907_rtos/rtos-hal/hal/test/twi/test_twi.c +++ b/Software/BSP/e907_rtos/rtos-hal/hal/test/twi/test_twi.c @@ -113,7 +113,7 @@ static int cmd_test_twi(int argc, const char **argv) hal_log_info("Twi test finish"); - hal_twi_uninit(port); + //hal_twi_uninit(port); hal_log_info("Twi test1 finish"); return 0; diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/aw_list.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/aw_list.h index 927b8d5f..022166b6 100644 --- a/Software/BSP/e907_rtos/rtos-hal/include/hal/aw_list.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/aw_list.h @@ -17,6 +17,15 @@ struct list_head { struct list_head *next, *prev; }; +struct hlist_head +{ + struct hlist_node *first; +}; + +struct hlist_node +{ + struct hlist_node *next, * *pprev; +}; #define LIST_POISON1 ((void *) 0x00100100) #define LIST_POISON2 ((void *) 0x00200) diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/hal_gpio.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/hal_gpio.h index 31c91a93..d35c3382 100644 --- a/Software/BSP/e907_rtos/rtos-hal/include/hal/hal_gpio.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/hal_gpio.h @@ -54,7 +54,7 @@ extern "C" { #define GPIO_ERR(fmt, arg...) hal_log_err(fmt, ##arg) /**This enum defines the GPIO MUX function*/ -#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_ARCH_SUN20IW2P1) +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_ARCH_SUN20IW2) || defined(CONFIG_ARCH_SUN20IW3) typedef enum { GPIO_MUXSEL_IN = 0, diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_gpadc.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_gpadc.h new file mode 100644 index 00000000..e4d9779d --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_gpadc.h @@ -0,0 +1,147 @@ +/* + * drivers/input/sensor/sunxi_gpadc.h + * + * Copyright (C) 2016 Allwinner. + * fuzhaoke + * + * SUNXI GPADC Controller Driver Header + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#ifndef HAL_GPADC_H +#define HAL_GPADC_H + +#include +#include +#include "sunxi_hal_common.h" +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* define this macro when debugging is required */ +/* #define CONFIG_DRIVERS_GPADC_DEBUG */ +#ifdef CONFIG_DRIVERS_GPADC_DEBUG +#define GPADC_INFO(fmt, arg...) hal_log_info(fmt, ##arg) +#else +#define GPADC_INFO(fmt, arg...) do {}while(0) +#endif + +#define GPADC_ERR(fmt, arg...) hal_log_err(fmt, ##arg) + +enum +{ + GPADC_DOWN, + GPADC_UP +}; + +typedef enum +{ + GP_CH_0 = 0, + GP_CH_1, + GP_CH_2, + GP_CH_3, + GP_CH_4, + GP_CH_5, + GP_CH_6, + GP_CH_7, + GP_CH_8, + GP_CH_9, + GP_CH_A, + GP_CH_B, + GP_CH_C, + GP_CH_D, + GP_CH_E, + GP_CH_MAX +} hal_gpadc_channel_t; + +typedef enum +{ + GPADC_IRQ_ERROR = -4, + GPADC_CHANNEL_ERROR = -3, + GPADC_CLK_ERROR = -2, + GPADC_ERROR = -1, + GPADC_OK = 0, +} hal_gpadc_status_t; + +typedef enum gp_select_mode +{ + GP_SINGLE_MODE = 0, + GP_SINGLE_CYCLE_MODE, + GP_CONTINUOUS_MODE, + GP_BURST_MODE, +} hal_gpadc_mode_t; + +typedef int (*gpadc_callback_t)(uint32_t data_type, uint32_t data); + +static uint32_t hal_gpadc_regs_offset[] = { + GP_SR_REG, + GP_CTRL_REG, + GP_CS_EN_REG, + GP_FIFO_INTC_REG, + GP_FIFO_DATA_REG, + GP_CB_DATA_REG, + GP_DATAL_INTC_REG, + GP_DATAH_INTC_REG, + GP_DATA_INTC_REG, + GP_CH0_CMP_DATA_REG, + GP_CH1_CMP_DATA_REG, + GP_CH2_CMP_DATA_REG, + GP_CH3_CMP_DATA_REG, + GP_CH4_CMP_DATA_REG, + GP_CH5_CMP_DATA_REG, + GP_CH6_CMP_DATA_REG, + GP_CH7_CMP_DATA_REG, + GP_CH8_CMP_DATA_REG, + GP_CH9_CMP_DATA_REG, + GP_CHA_CMP_DATA_REG, + GP_CHB_CMP_DATA_REG, + GP_CHC_CMP_DATA_REG, + GP_CHD_CMP_DATA_REG, + GP_CHE_CMP_DATA_REG, +}; + +typedef struct +{ + uint32_t reg_base; + uint32_t channel_num; + uint32_t irq_num; + uint32_t sample_rate; + struct reset_control *reset; +#if defined(CONFIG_SOC_SUN20IW1) || defined(CONFIG_ARCH_SUN8IW20) || defined(CONFIG_ARCH_SUN20IW2) + hal_clk_id_t bus_clk; + hal_clk_id_t rst_clk; + hal_clk_t mbus_clk; + hal_clk_t mbus_clk1; +#else + hal_clk_id_t mclk; + hal_clk_id_t pclk; +#endif + hal_gpadc_mode_t mode; + gpadc_callback_t callback[CHANNEL_MAX_NUM]; + uint32_t regs_backup[ARRAY_SIZE(hal_gpadc_regs_offset)]; +} hal_gpadc_t; + +int hal_gpadc_init(void); +hal_gpadc_status_t hal_gpadc_deinit(void); +hal_gpadc_status_t hal_gpadc_channel_init(hal_gpadc_channel_t channal); +hal_gpadc_status_t hal_gpadc_channel_exit(hal_gpadc_channel_t channal); +uint32_t gpadc_read_channel_data(hal_gpadc_channel_t channal); +hal_gpadc_status_t hal_gpadc_register_callback(hal_gpadc_channel_t channal, + gpadc_callback_t user_callback); +void gpadc_key_enable_highirq(hal_gpadc_channel_t channal); +void gpadc_key_disable_highirq(hal_gpadc_channel_t channal); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_pwm.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_pwm.h index aed5ddaf..4f67d0b1 100644 --- a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_pwm.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_pwm.h @@ -81,6 +81,13 @@ extern "C" { #define PWM_PERIOD_CYCLES_SHIFT 0x10 #define PWM_PERIOD_CYCLES_WIDTH 0x10 +#define PWM_DZ_EN_SHIFT 0x0 +#define PWM_DZ_EN_WIDTH 0x1 +#define PWM_PDZINTV_SHIFT 0x8 +#define PWM_PDZINTV_WIDTH 0x8 + +#define PWM_BIND_NUM 2 + /***************************************************************************** * Enums *****************************************************************************/ @@ -112,27 +119,50 @@ typedef struct pwm_config hal_pwm_polarity polarity; } pwm_config_t; +static u32 hal_pwm_regs_offset[] = { + PWM_PIER, + PWM_CIER, + PWM_PCCR01, + PWM_PCCR23, + PWM_PCCR45, + PWM_PCCR67, + PWM_PCGR, + PWM_PDZCR01, + PWM_PDZCR23, + PWM_PDZCR45, + PWM_PDZCR67, + PWM_PER, + PWM_CER, + PWM_PCR, + PWM_PPR, + PWM_CCR, + PWM_PCNTR, +}; + typedef struct { - hal_clk_type_t pwm_clk_type; - hal_clk_id_t pwm_bus_clk_id; - hal_clk_t pwm_bus_clk; - hal_reset_type_t pwm_reset_type; - hal_reset_id_t pwm_reset_id; - struct reset_control *pwm_reset; - - gpio_pin_t pin[8]; - gpio_muxsel_t enable_muxsel[8]; + hal_clk_type_t pwm_clk_type; + hal_clk_id_t pwm_bus_clk_id; + hal_clk_t pwm_bus_clk; + hal_reset_type_t pwm_reset_type; + hal_reset_id_t pwm_reset_id; + struct reset_control *pwm_reset; + + bool pin_state[PWM_NUM]; + gpio_pin_t pin[PWM_NUM]; + gpio_muxsel_t enable_muxsel[PWM_NUM]; + u32 regs_backup[ARRAY_SIZE(hal_pwm_regs_offset)]; } hal_pwm_t; pwm_status_t hal_pwm_init(void); pwm_status_t hal_pwm_control(int channel, struct pwm_config *config_pwm); +pwm_status_t hal_pwm_release(int channel); void hal_pwm_enable_controller(uint32_t channel_in); void hal_pwm_disable_controller(uint32_t channel_in); pwm_status_t hal_pwm_deinit(void); -pwm_status_t hal_pwm_resume(void); -pwm_status_t hal_pwm_suspend(void); +int hal_pwm_resume(void *dev); +int hal_pwm_suspend(void *dev); #ifdef __cplusplus } diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_spi.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_spi.h new file mode 100644 index 00000000..fd45f6f0 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_spi.h @@ -0,0 +1,236 @@ +/* + * =========================================================================================== + * + * Filename: sunxi_hal_spi.h + * + * Description: SPI HAL definition. + * + * Version: Melis3.0 + * Create: 2019-11-18 11:11:56 + * Revision: none + * Compiler: GCC:version 9.2.1 + * + * Author: bantao@allwinnertech.com + * Organization: SWC-BPD + * Last Modified: 2019-12-03 16:02:11 + * + * =========================================================================================== + */ + +#ifndef SUNXI_HAL_SPI_H +#define SUNXI_HAL_SPI_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "sunxi_hal_common.h" +#include +#include +#include +#include +#ifdef CONFIG_COMPONENTS_PM +#include +#include +#endif + +/***************************************************************************** + * spi master + *****************************************************************************/ +/** @brief This enum defines the SPI master port. + * This chip total has 2 SPI master port + */ +typedef enum +{ + HAL_SPI_MASTER_0 = 0, /**< spi master port 0 */ + HAL_SPI_MASTER_1 = 1, /**< spi master port 1 */ + HAL_SPI_MASTER_2 = 2, /**< spi master port 2 */ + HAL_SPI_MASTER_3 = 3, /**< spi master port 3 */ + HAL_SPI_MASTER_MAX = SPI_MAX_NUM, /**< spi master max port number\ */ +} hal_spi_master_port_t; + +typedef struct +{ + uint8_t *tx_buf; /**< Data buffer to send, */ + uint32_t tx_len; /**< The total number of bytes to send. */ + uint32_t + tx_single_len; /**< The number of bytes to send in single mode. */ + uint8_t *rx_buf; /**< Received data buffer, */ + uint32_t rx_len; /**< The valid number of bytes received. */ + uint8_t tx_nbits : 3; /**< Data buffer to send in nbits mode */ + uint8_t rx_nbits : 3; /**< Data buffer to received in nbits mode */ + uint8_t dummy_byte; /**< Flash send dummy byte, default 0*/ +#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */ +#define SPI_NBITS_DUAL 0x02 /* 2bit transfer */ +#define SPI_NBITS_QUAD 0x04 /* 4bit transfer */ + uint8_t bits_per_word; /**< transfer bit_per_word */ +} hal_spi_master_transfer_t; + +typedef enum spi_mode_type +{ + SGLE_HALF_DUPLEX_RX, /* single mode, half duplex read */ + SGLE_HALF_DUPLEX_TX, /* single mode, half duplex write */ + SINGLE_FULL_DUPLEX_RX_TX, /* single mode, full duplex read and write */ + DUAL_HALF_DUPLEX_RX, /* dual mode, half duplex read */ + DUAL_HALF_DUPLEX_TX, /* dual mode, half duplex write */ + QUAD_HALF_DUPLEX_RX, /* quad mode, half duplex read */ + QUAD_HALF_DUPLEX_TX, /* quad mode, half duplex write */ + FULL_DUPLEX_TX_RX, /* full duplex read and write */ + MODE_TYPE_NULL, +} spi_mode_type_t; + +typedef struct spi_dma +{ + struct dma_slave_config config; + struct sunxi_dma_chan *chan; +} spi_dma_t; + +typedef enum +{ + SPI_MASTER_ERROR = -6, /**< SPI master function error occurred. */ + SPI_MASTER_ERROR_NOMEM = -5, /**< SPI master request mem failed. */ + SPI_MASTER_ERROR_TIMEOUT = -4, /**< SPI master xfer timeout. */ + SPI_MASTER_ERROR_BUSY = -3, /**< SPI master is busy. */ + SPI_MASTER_ERROR_PORT = -2, /**< SPI master invalid port. */ + SPI_MASTER_INVALID_PARAMETER = + -1, /**< SPI master invalid input parameter. */ + SPI_MASTER_OK = 0 /**< SPI master operation completed successfully. */ +} spi_master_status_t; + +/** @brief selection of spi slave device connected to which cs pin of spi master +*/ +typedef enum +{ + HAL_SPI_MASTER_SLAVE_0 = + 0, /**< spi slave device connect to spi master cs0 pin */ + HAL_SPI_MASTER_SLAVE_1 = + 1, /**< spi slave device connect to spi master cs1 pin */ + HAL_SPI_MASTER_SLAVE_MAX /**< spi master max cs pin number\ */ +} hal_spi_master_slave_port_t; + +/** @brief SPI master clock polarity definition */ +typedef enum +{ + HAL_SPI_MASTER_CLOCK_POLARITY0 = 0, /**< Clock polarity is 0 */ + HAL_SPI_MASTER_CLOCK_POLARITY1 = 2 /**< Clock polarity is 1 */ +} hal_spi_master_clock_polarity_t; + +/** @brief SPI master clock format definition */ +typedef enum +{ + HAL_SPI_MASTER_CLOCK_PHASE0 = 0, /**< Clock format is 0 */ + HAL_SPI_MASTER_CLOCK_PHASE1 = 1 /**< Clock format is 1 */ +} hal_spi_master_clock_phase_t; + +/** @brief SPI master transaction bit order definition */ +typedef enum +{ + HAL_SPI_MASTER_LSB_FIRST = + 0, /**< Both send and receive data transfer LSB first */ + HAL_SPI_MASTER_MSB_FIRST = + 1 /**< Both send and receive data transfer MSB first */ +} hal_spi_master_bit_order_t; + +/** @brief SPI master status. */ +typedef enum +{ + HAL_SPI_MASTER_STATUS_ERROR = + -6, /**< SPI master function error occurred. */ + HAL_SPI_MASTER_STATUS_ERROR_NOMEM = + -5, /**< SPI master request mem failed. */ + HAL_SPI_MASTER_STATUS_ERROR_TIMEOUT = + -4, /**< SPI master xfer timeout. */ + HAL_SPI_MASTER_STATUS_ERROR_BUSY = -3, /**< SPI master is busy. */ + HAL_SPI_MASTER_STATUS_ERROR_PORT = -2, /**< SPI master invalid port. */ + HAL_SPI_MASTER_STATUS_INVALID_PARAMETER = + -1, /**< SPI master invalid input parameter. */ + HAL_SPI_MASTER_STATUS_OK = + 0 /**< SPI master operation completed successfully. */ +} hal_spi_master_status_t; + +/** @brief SPI master running status. */ +typedef enum +{ + HAL_SPI_MASTER_IDLE = 0, /**< SPI master is idle. */ + HAL_SPI_MASTER_BUSY = 1 /**< SPI master is busy. */ +} hal_spi_master_running_status_t; + +typedef struct +{ + uint32_t clock_frequency; /**< SPI master clock frequency setting. */ + hal_spi_master_slave_port_t + slave_port; /**< SPI slave device selection. */ + hal_spi_master_bit_order_t + bit_order; /**< SPI master bit order setting. 0:MSB first 1:LSB + first*/ + hal_spi_master_clock_polarity_t + cpol; /**< SPI master clock polarity setting. 0:Active high + polarity(0 = Idle) 1:Active low polarity(1 = Idle) */ + hal_spi_master_clock_phase_t + cpha; /**< SPI master clock phase setting. 0: Phase 0(Leading edge + for sample data) 1: Phase 1(Leading edge for setup data) + */ + uint32_t sip; + uint32_t flash; +} hal_spi_master_config_t; + +typedef struct sunxi_spi +{ + int8_t result : 2; +#define SPI_XFER_READY 0 +#define SPI_XFER_OK 1 +#define SPI_XFER_FAILED -1 + + bool sem; + uint16_t irqnum; + unsigned long base; + spi_mode_type_t mode_type; + + hal_clk_t pclk; /* PLL clock */ + hal_clk_t bus_clk; /* BUS clock */ + hal_clk_t mclk; /* spi module clock */ + struct reset_control *reset; + + spi_dma_t dma_rx; + spi_dma_t dma_tx; + + char *align_dma_buf; +#define ALIGN_DMA_BUF_SIZE (4096 + 64) + + hal_sem_t xSemaphore_tx; + hal_sem_t xSemaphore_rx; + + hal_spi_master_port_t port; + hal_spi_master_config_t config; + hal_spi_master_transfer_t *transfer; + +#ifdef CONFIG_COMPONENTS_PM + struct pm_device pm; + struct wakelock wl; +#endif + bool used; +} sunxi_spi_t; + +struct hal_spi_master { + hal_spi_master_port_t port; + hal_spi_master_config_t cfg; +}; + +typedef enum +{ + SPI_WRITE_READ = 0, /**< SPI master is busy. */ + SPI_CONFIG = 1 /**< SPI master is idle. */ +} hal_spi_transfer_cmd_t; + +spi_master_status_t hal_spi_init(hal_spi_master_port_t port, hal_spi_master_config_t *cfg); +spi_master_status_t hal_spi_write(hal_spi_master_port_t port, void *buf, uint32_t size); +spi_master_status_t hal_spi_deinit(hal_spi_master_port_t port); +spi_master_status_t hal_spi_read(hal_spi_master_port_t port, void *buf, uint32_t size); +spi_master_status_t hal_spi_xfer(hal_spi_master_port_t port, hal_spi_master_transfer_t *transfer); +spi_master_status_t hal_spi_hw_config(hal_spi_master_port_t port, hal_spi_master_config_t *spi_config); +#ifdef CONFIG_DRIVERS_SPI_PANIC_TRANSFER +spi_master_status_t hal_spi_panic_xfer(hal_spi_master_port_t port, hal_spi_master_transfer_t *transfer); +#endif + +#endif diff --git a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_twi.h b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_twi.h index a84b5668..53fc509b 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_twi.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/hal/sunxi_hal_twi.h @@ -2,13 +2,19 @@ #define SUNXI_HAL_TWI_H #include "hal_sem.h" -#include "hal_clk.h" +#include +#include #include "sunxi_hal_common.h" #include "hal_gpio.h" #include "sunxi_hal_regulator.h" #include #include +#ifdef CONFIG_COMPONENTS_PM +#include +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -22,6 +28,7 @@ extern "C" { #endif #define TWI_ERR(fmt, arg...) hal_log_err(fmt, ##arg) +#define TWI_WARN(fmt, arg...) hal_log_warn(fmt, ##arg) typedef enum { @@ -96,10 +103,13 @@ typedef struct sunxi_twi uint32_t msgs_ptr; unsigned long base_addr; uint32_t irqnum; + char irqname[32]; struct regulator_dev regulator; + struct reset_control *reset; hal_clk_t pclk; hal_clk_t mclk; + hal_clk_t clk; twi_frequency_t freq; uint32_t pinmux; @@ -110,6 +120,11 @@ typedef struct sunxi_twi struct sunxi_dma_chan *dma_chan; hal_sem_t dma_complete; + +#ifdef CONFIG_COMPONENTS_PM + struct pm_device pm; + struct wakelock wl; +#endif } hal_twi_t; typedef enum diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_atomic.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_atomic.h index 1533f7b6..2c25fe63 100644 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_atomic.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_atomic.h @@ -33,6 +33,8 @@ void hal_spin_unlock_irqrestore(hal_spinlock_t *lock, uint32_t __cpsr); int hal_spin_lock_init(hal_spinlock_t *lock); int hal_spin_lock_deinit(hal_spinlock_t *lock); +void hal_enter_critical(void); +void hal_exit_critical(void); #ifdef __cplusplus } diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_cfg.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_cfg.h index b9a41346..ee88fd6c 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_cfg.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_cfg.h @@ -1,35 +1,38 @@ -#ifndef SUNXI_HAL_CFG_H -#define SUNXI_HAL_CFG_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -#ifdef CONFIG_KERNEL_FREERTOS -#include -#include -#include -int32_t Hal_Cfg_GetGPIOSecKeyCount(char *GPIOSecName); -int32_t Hal_Cfg_GetGPIOSecData(char *GPIOSecName, void *pGPIOCfg, int32_t GPIONum); -#elif defined(CONFIG_OS_MELIS) -#include -#include -#include -#include -int32_t Hal_Cfg_Init(uint8_t *CfgVAddr, uint32_t size); -int32_t Hal_Cfg_Exit(void); -int32_t Hal_Cfg_GetKeyValue(char *SecName, char *KeyName, int32_t Value[], int32_t Count); -int32_t Hal_Cfg_GetSecKeyCount(char *SecName); -int32_t Hal_Cfg_GetSecCount(void); -int32_t Hal_Cfg_GetGPIOSecKeyCount(char *GPIOSecName); -int32_t Hal_Cfg_GetGPIOSecData(char *GPIOSecName, void *pGPIOCfg, int32_t GPIONum); -#else -#error "can not support unknown platform" -#endif - -#ifdef __cplusplus -} -#endif - -#endif +#ifndef SUNXI_HAL_CFG_H +#define SUNXI_HAL_CFG_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef CONFIG_KERNEL_FREERTOS +#include +#include +#include +int32_t Hal_Cfg_Init(void); + +#elif defined(CONFIG_OS_MELIS) +#include +#include +#include +#include +int32_t Hal_Cfg_Init(uint8_t *CfgVAddr, uint32_t size); + +#else +#error "can not support unknown platform" +#endif + +int32_t Hal_Cfg_Exit(void); +int32_t Hal_Cfg_GetSubKeyValue(char *MainKeyName, char *SubKeyName, void *value, int32_t type); +int32_t Hal_Cfg_GetKeyValue(char *SecName, char *KeyName, int32_t Value[], int32_t Count); +int32_t Hal_Cfg_GetSecKeyCount(char *SecName); +int32_t Hal_Cfg_GetSecCount(void); +int32_t Hal_Cfg_GetGPIOSecKeyCount(char *GPIOSecName); +int32_t Hal_Cfg_GetGPIOSecData(char *GPIOSecName, void *pGPIOCfg, int32_t GPIONum); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_event.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_event.h new file mode 100644 index 00000000..7d35d6b3 --- /dev/null +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_event.h @@ -0,0 +1,78 @@ +#ifndef SUNXI_HAL_EVENT_H +#define SUNXI_HAL_EVENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifdef CONFIG_KERNEL_FREERTOS +#include +#include +#include + +#define HAL_EVENT_OPTION_CLEAR (1 << 0) +#define HAL_EVENT_OPTION_AND (1 << 1) +#define HAL_EVENT_OPTION_OR (1 << 2) + +typedef StaticEventGroup_t hal_event; +typedef EventGroupHandle_t hal_event_t; +typedef EventBits_t hal_event_bits_t; + + +#elif defined(CONFIG_RTTKERNEL) +#include +#include + +#define HAL_EVENT_OPTION_CLEAR RT_EVENT_FLAG_CLEAR +#define HAL_EVENT_OPTION_AND RT_EVENT_FLAG_AND +#define HAL_EVENT_OPTION_OR RT_EVENT_FLAG_OR + +typedef rt_event_t hal_event_t; +typedef rt_uint32_t hal_event_bits_t; + +#else +#error "can not support the RTOS!!" +#endif + +int hal_event_init(hal_event_t ev); +int hal_event_datach(hal_event_t ev); + +hal_event_t hal_event_create(void); +hal_event_t hal_event_create_initvalue(int init_value); +int hal_event_delete(hal_event_t ev); + +/* + * wait for events + * @ev: hal_event_t handler + * @evs: events + * @option: it can be HAL_EVENT_OPTION_* + * @timeout:wait time(ms) + * + * @return: return new events value if success,otherwise return negative value + */ +hal_event_bits_t hal_event_wait(hal_event_t ev, hal_event_bits_t evs, uint8_t option, unsigned long timeout); + +#define hal_ev_wait_all(ev, evs, timeout) hal_event_wait(ev, evs, HAL_EVENT_OPTION_CLEAR | HAL_EVENT_OPTION_AND, timeout) +#define hal_ev_wait_any(ev, evs, timeout) hal_event_wait(ev, evs, HAL_EVENT_OPTION_CLEAR | HAL_EVENT_OPTION_OR, timeout) +#define hal_ev_wait_all_no_clear(ev, evs, timeout) hal_event_wait(ev, evs, HAL_EVENT_OPTION_AND, timeout) +#define hal_ev_wait_any_no_clear(ev, evs, timeout) hal_event_wait(ev, evs, HAL_EVENT_OPTION_OR, timeout) + +/* + * set event bit + * @ev: hal_event_t handler + * @evs: event bit to set + * + * @return: return 0 if success + */ +int hal_event_set_bits(hal_event_t ev, hal_event_bits_t evs); + +hal_event_bits_t hal_event_get(hal_event_t ev); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_interrupt.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_interrupt.h index cf0d09cc..a2e8a1f9 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_interrupt.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_interrupt.h @@ -42,6 +42,9 @@ void hal_interrupt_clear_pending(int32_t irq); int32_t hal_interrupt_is_pending(int32_t irq); void hal_interrupt_set_pending(int32_t irq); +void hal_interrupt_enter(void); +void hal_interrupt_leave(void); + #ifdef __cplusplus } #endif diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mem.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mem.h index 3c0b300a..cdf3c481 100644 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mem.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mem.h @@ -9,6 +9,8 @@ extern "C" #include #include +void *hal_realloc(void *ptr, uint32_t size); +void *hal_calloc(uint32_t numb, uint32_t size); void *hal_malloc(uint32_t size); void hal_free(void *p); diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mutex.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mutex.h index 0a1c2705..bf3e5240 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mutex.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_mutex.h @@ -9,9 +9,11 @@ extern "C" #ifdef CONFIG_KERNEL_FREERTOS #include #include +typedef struct QueueDefinition hal_mutex; typedef SemaphoreHandle_t hal_mutex_t; #elif defined(CONFIG_RTTKERNEL) #include +typedef struct rt_mutex hal_mutex; typedef rt_mutex_t hal_mutex_t; #else #error "can not support the RTOS!!" @@ -20,6 +22,8 @@ typedef rt_mutex_t hal_mutex_t; #include #include +int hal_mutex_init(hal_mutex *mutex); +int hal_mutex_detach(hal_mutex *mutex); hal_mutex_t hal_mutex_create(void); int hal_mutex_delete(hal_mutex_t mutex); int hal_mutex_lock(hal_mutex_t mutex); diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_thread.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_thread.h index dcf618a3..7c803adc 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_thread.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_thread.h @@ -24,9 +24,14 @@ typedef struct rt_thread hal_thread; void *kthread_create(void (*threadfn)(void *data), void *data, const char *namefmt, int stacksize, int priority); int kthread_stop(void *thread); int kthread_start(void *thread); +void *kthread_self(void); int kthread_wakeup(void *thread); int kthread_suspend(void *thread); -int kthread_mdelay(int ms); +int kthread_msleep(int ms); +int kthread_sleep(int tick); +int kthread_scheduler_is_running(void); +int kthread_in_critical_context(void); +void kthread_tick_increase(void); #define kthread_run(threadfn, data, namefmt, ...) \ ({ \ diff --git a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_time.h b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_time.h index 2129019c..dbabe848 100755 --- a/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_time.h +++ b/Software/BSP/e907_rtos/rtos-hal/include/osal/hal_time.h @@ -17,6 +17,7 @@ extern "C" #ifdef CONFIG_KERNEL_FREERTOS #include +#include #include #undef HAL_WAIT_FOREVER