123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494 |
- /* 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 <hal_interrupt.h>
- #include <hal_clk.h>
- #include <sunxi_hal_gpadc.h>
- #include <hal_reset.h>
- hal_gpadc_t hal_gpadc;
- #if defined(CONFIG_SOC_SUN20IW1)
- 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_clk_t mclk;
- hal_reset_type_t reset_type = HAL_SUNXI_RESET;
- hal_reset_id_t gpadc_reset_id = gpadc->rst_clk;
- struct reset_control *reset;
- mclk = hal_clock_get(clk_type, gpadc_clk_id);
- if(hal_clock_enable(mclk))
- {
- GPADC_ERR("gpadc clk enable failed!\n");
- return GPADC_ERROR;
- }
- gpadc->mbus_clk = mclk;
- reset = hal_reset_control_get(reset_type, gpadc_reset_id);
- if (hal_reset_control_deassert(reset))
- {
- GPADC_ERR("gpadc reset deassert failed!\n");
- return GPADC_ERROR;
- }
- hal_reset_control_put(reset);
- 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 int gpadc_channel_check_valid(hal_gpadc_channel_t channal)
- {
- hal_gpadc_t *gpadc = &hal_gpadc;
- 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);
- }
- 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);
- }
- 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);
- }
- /* 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;
- }
- int hal_gpadc_callback(uint32_t data_type, uint32_t data)
- {
- GPADC_INFO("gpadc interrupt, data_type is %ld", data_type);
- return 0;
- }
- static irqreturn_t gpadc_handler(int irq, 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);
- 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 void 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)
- gpadc->bus_clk = CLK_BUS_GPADC;
- gpadc->rst_clk = RST_BUS_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;
- }
- };
- int hal_gpadc_init(void)
- {
- hal_gpadc_t *gpadc = &hal_gpadc;
- hal_gpadc_setup(gpadc);
- if (hal_gpadc_clk_init(gpadc))
- {
- GPADC_ERR("gpadc init clk error");
- return GPADC_CLK_ERROR;
- }
- GPADC_INFO("gpadc set sample rate");
- gpadc_sample_rate_set(gpadc->reg_base, OSC_24MHZ, gpadc->sample_rate);
- if (request_irq(gpadc->irq_num, gpadc_handler, IRQF_NO_SUSPEND, "gpadc", gpadc))
- {
- return GPADC_IRQ_ERROR;
- }
- enable_irq(gpadc->irq_num);
- GPADC_INFO("gpadc enable calibration");
- gpadc_calibration_enable(gpadc->reg_base);
- gpadc_mode_select(gpadc->reg_base, gpadc->mode);
- gpadc_enable(gpadc->reg_base);
- return GPADC_OK;
- }
- hal_gpadc_status_t hal_gpadc_deinit(void)
- {
- disable_irq(hal_gpadc.irq_num);
- #if defined(CONFIG_SOC_SUN20IW1)
- hal_clock_disable(hal_gpadc.mbus_clk);
- #else
- hal_clock_disable(hal_gpadc.mclk);
- #endif
- return GPADC_OK;
- }
- //device_initcall(hal_gpadc_init);
|