123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989 |
- /*
- * Copyright (c) 2021 Actions Semiconductor Co., Ltd
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * @file
- * @brief Actions PMU ADC implementation
- */
- #include <kernel.h>
- #include <device.h>
- #include <string.h>
- #include <errno.h>
- #include <soc.h>
- #include <soc_atp.h>
- #include <board_cfg.h>
- #include <sys/util.h>
- #include <sys/byteorder.h>
- #include <drivers/adc.h>
- #include <logging/log.h>
- LOG_MODULE_REGISTER(pmuadc0, CONFIG_ADC_LOG_LEVEL);
- /***************************************************************************************************
- * PMUADC_CTL
- */
- #define PMUADC_CTL_REG_SENSOR_EFUSE_SHIFT (26)
- #define PMUADC_CTL_REG_SENSOR_EFUSE_MASK (0x3F << PMUADC_CTL_REG_SENSOR_EFUSE_SHIFT)
- #define PMUADC_CTL_EN_TEST_SEN_CURR BIT(25)
- #define ADC_SEL BIT(24)
- #define PMUADC_CTL_PMUADC_EN BIT(23)
- #define PMUADC_CTL_REG_IBIAS_BUF_SHIFT (21)
- #define PMUADC_CTL_REG_IBIAS_BUF_MASK (0x3 << PMUADC_CTL_REG_IBIAS_BUF_SHIFT)
- #define PMUADC_CTL_REG_IBIAS_BUF(x) ((x) << PMUADC_CTL_REG_IBIAS_BUF_SHIFT)
- #define PMUADC_CTL_REG_IBIAS_ADC_SHIFT (19)
- #define PMUADC_CTL_REG_IBIAS_ADC_MASK (0x3 << PMUADC_CTL_REG_IBIAS_ADC_SHIFT)
- #define PMUADC_CTL_REG_IBIAS_ADC(x) ((x) << PMUADC_CTL_REG_IBIAS_ADC_SHIFT)
- #define PMUADC_CTL_TEST_SARAD BIT(18)
- #define PMUADC_CTL_LRADC6_SCAL BIT(17)
- #define PMUADC_CTL_LRADC5_SCAL BIT(16)
- #define PMUADC_CTL_LRADC4_SCAL BIT(15)
- #define PMUADC_CTL_LRADC3_SCAL BIT(14)
- #define PMUADC_CTL_LRADC2_SCAL BIT(13)
- #define PMUADC_CTL_SCAN_MODE BIT(12)
- #define PMUADC_CTL_LRADC6_CHEN BIT(11)
- #define PMUADC_CTL_LRADC5_CHEN BIT(10)
- #define PMUADC_CTL_LRADC4_CHEN BIT(9)
- #define PMUADC_CTL_LRADC3_CHEN BIT(8)
- #define PMUADC_CTL_LRADC2_CHEN BIT(7)
- #define PMUADC_CTL_VCCI_CHEN BIT(6)
- #define PMUADC_CTL_LRADC1_CHEN BIT(5)
- #define PMUADC_CTL_SVCC_CHEN BIT(4)
- #define PMUADC_CTL_SENSOR_CHEN BIT(3)
- #define PMUADC_CTL_DC5V_CHEN BIT(2)
- #define PMUADC_CTL_BATV_CHEN BIT(1)
- #define PMUADC_CTL_CHARGI_CHEN BIT(0)
- /***************************************************************************************************
- * PMUADC_INTMASK
- */
- #define PMUADC_INTMASK_LRADC6_INTEN BIT(11)
- #define PMUADC_INTMASK_LRADC5_INTEN BIT(10)
- #define PMUADC_INTMASK_LRADC4_INTEN BIT(9)
- #define PMUADC_INTMASK_LRADC3_INTEN BIT(8)
- #define PMUADC_INTMASK_LRADC2_INTEN BIT(7)
- #define PMUADC_INTMASK_VCCI_INTEN BIT(6)
- #define PMUADC_INTMASK_LRADC1_INTEN BIT(5)
- #define PMUADC_INTMASK_SVCC_INTEN BIT(4)
- #define PMUADC_INTMASK_SENSOR_INTEN BIT(3)
- #define PMUADC_INTMASK_DC5V_INTEN BIT(2)
- #define PMUADC_INTMASK_BATV_INTEN BIT(1)
- #define PMUADC_INTMASK_CHARGI_INTEN BIT(0)
- /***************************************************************************************************
- * PMUADC_PD
- */
- #define PMUADC_PD_LRADC6_PD BIT(11)
- #define PMUADC_PD_LRADC5_PD BIT(10)
- #define PMUADC_PD_LRADC4_PD BIT(9)
- #define PMUADC_PD_LRADC3_PD BIT(8)
- #define PMUADC_PD_LRADC2_PD BIT(7)
- #define PMUADC_PD_VCCI_PD BIT(6)
- #define PMUADC_PD_LRADC1_PD BIT(5)
- #define PMUADC_PD_SVCC_PD BIT(4)
- #define PMUADC_PD_SENSOR_PD BIT(3)
- #define PMUADC_PD_DC5V_PD BIT(2)
- #define PMUADC_PD_BATV_PD BIT(1)
- #define PMUADC_PD_CHARGI_PD BIT(0)
- /***************************************************************************************************
- * CHARGI_DATA
- */
- #define CHARGI_DATA_CHARGI_SHIFT (0)
- #define CHARGI_DATA_CHARGI_MASK (0x1FFF << CHARGI_DATA_CHARGI_SHIFT)
- /***************************************************************************************************
- * BATADC_DATA
- */
- #define BATADC_DATA_BATV_SHIFT (0)
- #define BATADC_DATA_BATV_MASK (0x3FFF << BATADC_DATA_BATV_SHIFT)
- /***************************************************************************************************
- * DC5VADC_DATA
- */
- #define DC5VADC_DATA_DC5V_SHIFT (0)
- #define DC5VADC_DATA_DC5V_MASK (0xFFF << DC5VADC_DATA_DC5V_SHIFT)
- /***************************************************************************************************
- * SENSADC_DATA
- */
- #define SENSADC_DATA_SENSOR_SHIFT (0)
- #define SENSADC_DATA_SENSOR_MASK (0xFFF << SENSADC_DATA_SENSOR_SHIFT)
- /***************************************************************************************************
- * SVCCADC_DATA
- */
- #define SVCCADC_DATA_SVCC_SHIFT (0)
- #define SVCCADC_DATA_SVCC_MASK (0xFFF << SVCCADC_DATA_SVCC_SHIFT)
- /***************************************************************************************************
- * VCCI_DATA
- */
- #define VCCIADC_DATA_VCCI_SHIFT (0)
- #define VCCIADC_DATA_VCCI_MASK (0x1FFF << VCCIADC_DATA_VCCI_SHIFT)
- /***************************************************************************************************
- * LRADC_DATA
- */
- #define LRADC_DATA_LRADC_SHIFT (0)
- #define LRADC_DATA_LRADC_MASK (0x3FFF << LRADC_DATA_LRADC_SHIFT)
- /***************************************************************************************************
- * PMUADCDIG_CTL
- */
- #define PMUADCDIG_CTL_LRADC6_AVG_SHIFT (30)
- #define PMUADCDIG_CTL_LRADC6_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC6_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC6_AVG(x) ((x) << PMUADCDIG_CTL_LRADC6_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC5_AVG_SHIFT (28)
- #define PMUADCDIG_CTL_LRADC5_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC5_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC5_AVG(x) ((x) << PMUADCDIG_CTL_LRADC5_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC4_AVG_SHIFT (26)
- #define PMUADCDIG_CTL_LRADC4_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC4_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC4_AVG(x) ((x) << PMUADCDIG_CTL_LRADC4_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC3_AVG_SHIFT (24)
- #define PMUADCDIG_CTL_LRADC3_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC3_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC3_AVG(x) ((x) << PMUADCDIG_CTL_LRADC3_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC2_AVG_SHIFT (22)
- #define PMUADCDIG_CTL_LRADC2_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC2_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC2_AVG(x) ((x) << PMUADCDIG_CTL_LRADC2_AVG_SHIFT)
- #define PMUADCDIG_CTL_VCCI_AVG_SHIFT (20)
- #define PMUADCDIG_CTL_VCCI_AVG_MASK (0x3 << PMUADCDIG_CTL_VCCI_AVG_SHIFT)
- #define PMUADCDIG_CTL_VCCI_AVG(x) ((x) << PMUADCDIG_CTL_VCCI_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC1_AVG_SHIFT (18)
- #define PMUADCDIG_CTL_LRADC1_AVG_MASK (0x3 << PMUADCDIG_CTL_LRADC1_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC1_AVG(x) ((x) << PMUADCDIG_CTL_LRADC1_AVG_SHIFT)
- #define PMUADCDIG_CTL_SVCCADC_AVG_SHIFT (16)
- #define PMUADCDIG_CTL_SVCCADC_AVG_MASK (0x3 << PMUADCDIG_CTL_SVCCADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_SVCCADC_AVG(x) ((x) << PMUADCDIG_CTL_SVCCADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_SESADC_AVG_SHIFT (14)
- #define PMUADCDIG_CTL_SESADC_AVG_MASK (0x3 << PMUADCDIG_CTL_SESADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_SESADC_AVG(x) ((x) << PMUADCDIG_CTL_SESADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_DC5VADC_AVG_SHIFT (12)
- #define PMUADCDIG_CTL_DC5VADC_AVG_MASK (0x3 << PMUADCDIG_CTL_DC5VADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_DC5VADC_AVG(x) ((x) << PMUADCDIG_CTL_DC5VADC_AVG_SHIFT)
- #define PMUADCDIG_CTL_BAT_AVG_SHIFT (10)
- #define PMUADCDIG_CTL_BAT_AVG_MASK (0x3 << PMUADCDIG_CTL_BAT_AVG_SHIFT)
- #define PMUADCDIG_CTL_BAT_AVG(x) ((x) << PMUADCDIG_CTL_BAT_AVG_SHIFT)
- #define PMUADCDIG_CTL_CHARGI_AVG_SHIFT (8)
- #define PMUADCDIG_CTL_CHARGI_AVG_MASK (0x3 << PMUADCDIG_CTL_CHARGI_AVG_SHIFT)
- #define PMUADCDIG_CTL_CHARGI_AVG(x) ((x) << PMUADCDIG_CTL_CHARGI_AVG_SHIFT)
- #define PMUADCDIG_CTL_LRADC2_R_SEL BIT(5)
- #define PMUADCDIG_CTL_RVALUE_SEL_SHIFT (0)
- #define PMUADCDIG_CTL_RVALUE_SEL_MASK (0x1f << PMUADCDIG_CTL_RVALUE_SEL_SHIFT)
- #define PMUADCDIG_CTL_RVALUE_SEL(x) ((x) << PMUADCDIG_CTL_RVALUE_SEL_SHIFT)
- #define PMUADC_MAX_CHANNEL_ID (11) /* MAX valid channel ID */
- #define PMUADC_WAIT_TIMEOUT_MS (50) /* Timeout to wait for PMU ADC sampling */
- #define PMUADC_WAIT_OVER_SAMPLE_US (3000) //(1000)
- #if (CONFIG_PMUADC_LRADC1_AVG == 0)
- #define LRADCx_PENDING(ch, n) \
- if ((ch) & PMUADC_PD_LRADC##n##_PD) { \
- data->mdata.v.lradc##n##_voltage = pmuadc_reg->lradc##n##_data & LRADC_DATA_LRADC_MASK; \
- if (n == 1) \
- data->channels &= ~(BIT(n + 4)); \
- else \
- data->channels &= ~(BIT(n + 5)); \
- LOG_DBG("New LRADC%d voltage: 0x%x", n, data->mdata.v.lradc##n##_voltage); \
- }
- #else
- #define LRADCx_PENDING(ch, n) \
- if ((ch) & PMUADC_PD_LRADC##n##_PD) { \
- ret = pmuadc_wait_sample_complete(dev, ch); \
- if (ret) \
- return ret; \
- data->mdata.v.lradc##n##_voltage = pmuadc_reg->lradc##n##_data & LRADC_DATA_LRADC_MASK; \
- if (n == 1) \
- data->channels &= ~(BIT(n + 4)); \
- else \
- data->channels &= ~(BIT(n + 5)); \
- LOG_DBG("New LRADC%d voltage: 0x%x", n, data->mdata.v.lradc##n##_voltage); \
- }
- #endif
- #define LRADCx_PENDING_ALL(x) \
- { \
- LRADCx_PENDING(x, 1); \
- LRADCx_PENDING(x, 2); \
- LRADCx_PENDING(x, 3); \
- LRADCx_PENDING(x, 4); \
- LRADCx_PENDING(x, 5); \
- LRADCx_PENDING(x, 6); \
- }
- /*
- * @struct acts_pmu_adc
- * @brief Actions PMU ADC controller hardware register
- */
- struct acts_pmu_adc {
- volatile uint32_t ctl; /* PMUADC control */
- volatile uint32_t intmask; /* PMUADC sample interrupt set */
- volatile uint32_t pending; /* PMUADC sample pending */
- volatile uint32_t dig_ctl; /* PMUADC digital control */
- volatile uint32_t charge_data; /* Measure charging current */
- volatile uint32_t bat_data; /* Measure battery voltage */
- volatile uint32_t dc5v_data; /* Measure DC5V voltage */
- volatile uint32_t sensor_data; /* IC temperature sensor */
- volatile uint32_t svcc_data; /* Measure SVCC voltage */
- volatile uint32_t lradc1_data; /* Measure LRADC1 IO voltage */
- volatile uint32_t vcci_data; /* Measure BAT to VCC current voltage */
- volatile uint32_t lradc2_data; /* Measure LRADC2 IO voltage */
- volatile uint32_t lradc3_data; /* Measure LRADC3 IO voltage */
- volatile uint32_t lradc4_data; /* Measure LRADC4 IO voltage */
- volatile uint32_t lradc5_data; /* Measure LRADC5 IO voltage */
- volatile uint32_t lradc6_data; /* Measure LRADC6 IO voltage */
- };
- /**
- * struct pmuadc_measure_data
- * @brief The measure result data from PMU ADC sampling.
- */
- union pmuadc_measure_data {
- uint16_t data[PMUADC_MAX_CHANNEL_ID + 1];
- struct {
- uint16_t charging_current;
- uint16_t battery_voltage;
- //uint16_t charging_current;
- uint16_t dc5v_voltage;
- uint16_t sensor_temperature;
- uint16_t svcc_voltage;
- uint16_t lradc1_voltage;
- uint16_t vcci_voltage;
- uint16_t lradc2_voltage;
- uint16_t lradc3_voltage;
- uint16_t lradc4_voltage;
- uint16_t lradc5_voltage;
- uint16_t lradc6_voltage;
- } v;
- };
- /**
- * struct pmuadc_drv_data
- * @brief The meta data which related to Actions PMU ADC.
- */
- struct pmuadc_drv_data {
- uint16_t channel_bitmap;
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- bool b_always_on;
- struct k_sem completion; /* ADC sample synchronization completion semaphare */
- //#endif
- struct k_sem lock; /* ADC read lock */
- union pmuadc_measure_data mdata; /* measuared data */
- uint16_t channels; /* active channels */
- uint16_t sample_cnt; /* sample counter */
- };
- /**
- * struct pmuadc_config_data
- * @brief The hardware data that related to Actions PMU ADC
- */
- struct pmuadc_config_data {
- uint32_t reg_base; /* PMU ADC controller register base address */
- uint8_t clk_id; /* LRADC devclk id */
- uint8_t clk_src; /* LRADC clock source */
- uint8_t clk_div; /* LRADC clock divisor */
- uint8_t debounce; /* PMU ADC debounce as the first sample data is not correct */
- void (*irq_config)(void); /* IRQ configuration function */
- };
- /* @brief get the base address of PMU ADC register */
- static inline struct acts_pmu_adc *get_pmuadc_reg_base(const struct device *dev)
- {
- const struct pmuadc_config_data *cfg = dev->config;
- return (struct acts_pmu_adc *)cfg->reg_base;
- }
- /* @brief dump pmu dac controller register */
- void pmudac_dump_register(const struct device *dev)
- {
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- LOG_INF("** pmudac contoller regster **");
- LOG_INF(" BASE: %08x", (uint32_t)pmuadc_reg);
- LOG_INF(" CTL: %08x", pmuadc_reg->ctl);
- LOG_INF(" INTMASK: %08x", pmuadc_reg->intmask);
- LOG_INF(" PENDING: %08x", pmuadc_reg->pending);
- LOG_INF(" DIG_CTL: %08x", pmuadc_reg->dig_ctl);
- LOG_INF(" CHARGE_DATA: %08x", pmuadc_reg->charge_data);
- LOG_INF(" BAT_DATA: %08x", pmuadc_reg->bat_data);
- LOG_INF(" DC5V_DATA: %08x", pmuadc_reg->dc5v_data);
- LOG_INF(" SENSOR_DATA: %08x", pmuadc_reg->sensor_data);
- LOG_INF(" SVCC_DATA: %08x", pmuadc_reg->svcc_data);
- LOG_INF(" VCCI_DATA: %08x", pmuadc_reg->vcci_data);
- LOG_INF(" LRADC1_DATA: %08x", pmuadc_reg->lradc1_data);
- LOG_INF(" LRADC2_DATA: %08x", pmuadc_reg->lradc2_data);
- LOG_INF(" LRADC3_DATA: %08x", pmuadc_reg->lradc3_data);
- LOG_INF(" LRADC4_DATA: %08x", pmuadc_reg->lradc4_data);
- LOG_INF(" LRADC5_DATA: %08x", pmuadc_reg->lradc5_data);
- LOG_INF(" LRADC6_DATA: %08x", pmuadc_reg->lradc6_data);
- LOG_INF(" CMU_LRADCCLK: %08x", sys_read32(CMU_LRADCCLK));
- }
- static s16_t adc_sensor_offset, adc_dc5v_offset, adc_bat_offset;
- /* @brief PMU ADC channel lock */
- static inline void pmuadc_lock(const struct device *dev)
- {
- struct pmuadc_drv_data *data = dev->data;
- k_sem_take(&data->lock, K_FOREVER);
- }
- /* @brief PMU ADC channel unlock */
- static inline void pmuadc_unlock(const struct device *dev)
- {
- struct pmuadc_drv_data *data = dev->data;
- k_sem_give(&data->lock);
- }
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- /* @brief wait for PMU ADC sample IRQ completion */
- static inline int pmuadc_wait_for_completion(const struct device *dev)
- {
- struct pmuadc_drv_data *data = dev->data;
- return k_sem_take(&data->completion, K_MSEC(PMUADC_WAIT_TIMEOUT_MS));
- }
- /* @brief signal that PMU ADC sample data completly */
- static inline void pmuadc_complete(const struct device *dev)
- {
- struct pmuadc_drv_data *data = dev->data;
- k_sem_give(&data->completion);
- }
- //#endif
- /* @brief check the buffer size */
- static int check_buffer_size(const struct adc_sequence *sequence,
- uint8_t active_channels)
- {
- uint32_t needed_buffer_size;
- needed_buffer_size = active_channels * sizeof(uint16_t);
- if (sequence->buffer_size < needed_buffer_size) {
- LOG_ERR("Provided buffer is too small (%u/%u)",
- sequence->buffer_size, needed_buffer_size);
- return -ENOMEM;
- }
- return 0;
- }
- /* @brief validate the selected PMU ADC channels */
- static int pmuadc_check_channels(const struct device *dev,
- const struct adc_sequence *sequence)
- {
- struct pmuadc_drv_data *data = dev->data;
- uint32_t channels = sequence->channels;
- uint8_t i, active_channels = 0;
- if (!channels) {
- LOG_ERR("null channels");
- return -EINVAL;
- }
- for (i = 0; i <= PMUADC_MAX_CHANNEL_ID; i++) {
- if (channels & BIT(i)) {
- if (!(data->channel_bitmap & BIT(i))) {
- LOG_ERR("ADC channel@%d has not setuped yet", i);
- return -ENXIO;
- } else {
- ++active_channels;
- }
- }
- }
- return check_buffer_size(sequence, active_channels);
- }
- /* @brief enable specified PMU ADC channels to sample data */
- static int pmuadc_enable_channels(const struct device *dev, uint16_t channels)
- {
- struct pmuadc_drv_data *data = dev->data;
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- uint8_t i;
- uint32_t ctl = 0;
- data->channels = channels;
- data->sample_cnt = 0;
- /* enable lradc clk */
- acts_clock_peripheral_enable(CLOCK_ID_LRADC);
- LOG_DBG("Active channels:0x%x", data->channels);
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- if(data->b_always_on) {
- /* If enable new channels, need to disable PMUADC and then enable */
- if (pmuadc_reg->ctl & PMUADC_CTL_PMUADC_EN) {
- pmuadc_reg->ctl &= ~PMUADC_CTL_PMUADC_EN;
- //k_busy_wait(300);
- }
- }
- //#endif
- /* enable PMU ADC channles */
- for (i = 0; i <= PMUADC_MAX_CHANNEL_ID; i++) {
- if (channels & BIT(i))
- ctl |= BIT(i);
- }
- pmuadc_reg->ctl |= ctl;
- /* enable PMU ADC function */
- pmuadc_reg->ctl |= PMUADC_CTL_PMUADC_EN;
- pmuadc_reg->pending = pmuadc_reg->pending;
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- if(!data->b_always_on) {
- uint16_t intmask = 0;
- /* enable channels interrupts */
- for (i = 0; i <= PMUADC_MAX_CHANNEL_ID; i++) {
- if (channels & BIT(i)) {
- intmask |= BIT(i);
- }
- }
- pmuadc_reg->intmask = intmask;
- }
- //#endif
- return 0;
- }
- /* @brief disable all PMU ADC channels */
- static int pmuadc_disable_channels(const struct device *dev)
- {
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- /* disable all ADC channels */
- pmuadc_reg->intmask = 0;
- pmuadc_reg->pending = pmuadc_reg->pending;
- pmuadc_reg->ctl &= ~(PMUADC_CTL_PMUADC_EN | 0x7FF);
- //k_busy_wait(300);
- /* disable lradc clk */
- acts_clock_peripheral_disable(CLOCK_ID_LRADC);
- return 0;
- }
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- static int pmuadc_wait_sample_complete(const struct device *dev, uint8_t ch_index)
- {
- uint32_t timestamp = k_cycle_get_32();
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- while(!(ch_index & pmuadc_reg->pending)) {
- if (k_cyc_to_us_floor32(k_cycle_get_32() - timestamp)
- > PMUADC_WAIT_OVER_SAMPLE_US) {
- LOG_ERR("failed to get ADC channel:%d PD:0x%x CTL:0x%x", ch_index, pmuadc_reg->pending, pmuadc_reg->ctl);
- return -ETIMEDOUT;
- }
- }
- LOG_DBG("pmuadc wait channel:%d use %dus", ch_index,
- k_cyc_to_us_floor32(k_cycle_get_32() - timestamp));
- return 0;
- }
- //#endif
- /* @brief Implementation of the ADC driver API function: adc_channel_setup. */
- static int pmuadc_channel_setup(const struct device *dev,
- const struct adc_channel_cfg *channel_cfg)
- {
- struct pmuadc_drv_data *data = dev->data;
- uint8_t channel_id = channel_cfg->channel_id;
- if (channel_id > PMUADC_MAX_CHANNEL_ID) {
- LOG_ERR("Invalid channel id %d", channel_id);
- return -EINVAL;
- }
- pmuadc_lock(dev);
- if (!(data->channel_bitmap & BIT(channel_id))) {
- data->channel_bitmap |= BIT(channel_id);
- LOG_INF("Enable PMU ADC channel@%d", channel_id);
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- if(data->b_always_on) {
- pmuadc_enable_channels(dev, BIT(channel_id));
- #if (CONFIG_PMUADC_BAT_WAIT_AVG_COMPLETE == 0) && (CONFIG_PMUADC_BAT_AVG_CNT == 2)
- /* Ignore the first BAT Voltage sample data */
- if (channel_id == PMUADC_ID_BATV)
- pmuadc_wait_sample_complete(dev, BIT(PMUADC_ID_BATV));
- #endif
- //k_busy_wait(300);
- }
- //#endif
- }
- pmuadc_unlock(dev);
- return 0;
- }
- static u16_t pmu_adc_cal(int32_t adcval, int32_t offset)
- {
- adcval = adcval + offset;
- return (u16_t)adcval;
- }
- /* @brief start to read the PMU ADC measure data */
- static int pmuadc_start_read(const struct device *dev,
- const struct adc_sequence *sequence)
- {
- struct pmuadc_drv_data *data = dev->data;
- int ret = 0;
- uint32_t channels = sequence->channels;
- uint8_t i;
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- if(data->b_always_on) {
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- /* clear all channels pending */
- pmuadc_reg->pending = pmuadc_reg->pending;
- if (channels & PMUADC_PD_BATV_PD) {
- #if (CONFIG_PMUADC_BAT_WAIT_AVG_COMPLETE == 1) && (CONFIG_PMUADC_BAT_AVG_CNT == 2)
- ret = pmuadc_wait_sample_complete(dev, BIT(PMUADC_ID_BATV));
- if (ret)
- return ret;
- #endif
- data->mdata.v.battery_voltage = pmuadc_reg->bat_data & BATADC_DATA_BATV_MASK;
- data->mdata.v.battery_voltage = pmu_adc_cal(data->mdata.v.battery_voltage, adc_bat_offset);
- }
- if (channels & PMUADC_PD_CHARGI_PD)
- data->mdata.v.charging_current = pmuadc_reg->charge_data & CHARGI_DATA_CHARGI_MASK;
- if (channels & PMUADC_PD_DC5V_PD){
- data->mdata.v.dc5v_voltage = pmuadc_reg->dc5v_data & DC5VADC_DATA_DC5V_MASK;
- data->mdata.v.dc5v_voltage = pmu_adc_cal(data->mdata.v.dc5v_voltage, adc_dc5v_offset);
- }
- if (channels & PMUADC_PD_SENSOR_PD){
- data->mdata.v.sensor_temperature = pmuadc_reg->sensor_data & SENSADC_DATA_SENSOR_MASK;
- data->mdata.v.sensor_temperature = pmu_adc_cal(data->mdata.v.sensor_temperature, adc_sensor_offset);
- }
- if (channels & PMUADC_PD_SVCC_PD)
- data->mdata.v.svcc_voltage = pmuadc_reg->svcc_data & SVCCADC_DATA_SVCC_MASK;
- if (channels & PMUADC_PD_VCCI_PD)
- data->mdata.v.vcci_voltage = pmuadc_reg->vcci_data & VCCIADC_DATA_VCCI_MASK;
- LRADCx_PENDING_ALL(channels);
- }else{
- //#else
- //uint32_t timestamp = k_cycle_get_32();
- ret = pmuadc_enable_channels(dev, channels);
- if (ret)
- return ret;
- ret = pmuadc_wait_for_completion(dev);
- /*LOG_DBG("pmuadc wait channel:%d use %dus", channels,
- k_cyc_to_us_floor32(k_cycle_get_32() - timestamp));*/
- }
- //#endif /* CONFIG_ADC_ACTS_ALWAYS_ON */
- if (!ret) {
- for (i = 0; i <= PMUADC_MAX_CHANNEL_ID; i++) {
- if (channels & BIT(i)) {
- sys_put_le16(data->mdata.data[i], sequence->buffer);
- }
- }
- }
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- if(!data->b_always_on){
- pmuadc_disable_channels(dev);
- }
- //#endif
- return ret;
- }
- /* @brief Implementation of the ADC driver API function: adc_read. */
- static int pmuadc_read(const struct device *dev,
- const struct adc_sequence *sequence)
- {
- int ret;
- ret = pmuadc_check_channels(dev, sequence);
- if (ret)
- return ret;
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- pmuadc_lock(dev);
- //#endif
- ret = pmuadc_start_read(dev, sequence);
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- pmuadc_unlock(dev);
- //#endif
- return ret;
- }
- #ifdef CONFIG_ADC_ASYNC
- /* @brief Implementation of the ADC driver API function: adc_read_sync. */
- static int pmuadc_read_async(const struct device *dev,
- const struct adc_sequence *sequence,
- struct k_poll_signal *async)
- {
- return -ENOTSUP;
- }
- #endif /* CONFIG_ADC_ASYNC */
- static const struct adc_driver_api pmuadc_driver_api = {
- .channel_setup = pmuadc_channel_setup,
- .read = pmuadc_read,
- #ifdef CONFIG_ADC_ASYNC
- .read_async = pmuadc_read_async,
- #endif
- };
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- static void pmuadc_isr(void *arg)
- {
- struct device *dev = (struct device *)arg;
- struct pmuadc_drv_data *data = dev->data;
- const struct pmuadc_config_data *cfg = dev->config;
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- uint32_t pending = pmuadc_reg->pending;
- uint32_t val;
- LOG_DBG("ctl:0x%x mask:0x%x pending:0x%x channels:0x%x",
- pmuadc_reg->ctl, pmuadc_reg->intmask, pending, data->channels);
- if (pending & PMUADC_PD_CHARGI_PD) {
- val = pmuadc_reg->charge_data & CHARGI_DATA_CHARGI_MASK;
- data->mdata.v.charging_current = val;
- data->channels &= ~BIT(0);
- LOG_DBG("New charging current: 0x%x", val);
- }
- if (pending & PMUADC_PD_BATV_PD) {
- val = pmuadc_reg->bat_data & BATADC_DATA_BATV_MASK;
- data->mdata.v.battery_voltage = pmu_adc_cal(val, adc_bat_offset);
- data->channels &= ~BIT(1);
- LOG_DBG("New battery voltage: 0x%x", val);
- }
- if (pending & PMUADC_PD_DC5V_PD) {
- val = pmuadc_reg->dc5v_data & DC5VADC_DATA_DC5V_MASK;
- data->mdata.v.dc5v_voltage = pmu_adc_cal(val, adc_dc5v_offset);
- data->channels &= ~BIT(2);
- LOG_DBG("New DC5V voltage: 0x%x", val);
- }
- if (pending & PMUADC_PD_SENSOR_PD) {
- val = pmuadc_reg->sensor_data & SENSADC_DATA_SENSOR_MASK;
- data->mdata.v.sensor_temperature = pmu_adc_cal(val, adc_sensor_offset);;
- data->channels &= ~BIT(3);
- LOG_DBG("New sensor temperature: 0x%x", val);
- }
- if (pending & PMUADC_PD_SVCC_PD) {
- val = pmuadc_reg->svcc_data & SVCCADC_DATA_SVCC_MASK;
- data->mdata.v.svcc_voltage = val;
- data->channels &= ~BIT(4);
- LOG_DBG("New SVCC voltage: 0x%x", val);
- }
- if (pending & PMUADC_PD_VCCI_PD) {
- val = pmuadc_reg->vcci_data & VCCIADC_DATA_VCCI_MASK;
- data->mdata.v.vcci_voltage = val;
- data->channels &= ~BIT(6);
- LOG_DBG("New SVCC voltage: 0x%x", val);
- }
- LRADCx_PENDING_ALL(pending);
- pmuadc_reg->pending = pending;
- if ((!data->channels) && (++data->sample_cnt > cfg->debounce)) {
- LOG_DBG("complete");
- pmuadc_reg->intmask = 0;
- pmuadc_complete(dev);
- }
- }
- //#endif
- /* @brief set the LRADC clock source and divisor */
- static int pmuadc_clk_source_set(const struct device *dev)
- {
- const struct pmuadc_config_data *cfg = dev->config;
- sys_write32(((cfg->clk_src & 0x7) << 4) | ((cfg->clk_div & 0x3)), CMU_LRADCCLK);
- LOG_DBG("LRADCCLK:0x%08x", sys_read32(CMU_LRADCCLK));
- return 0;
- }
- /* @brief ADC core current bias setting */
- static int pmuadc_bias_setting(const struct device *dev)
- {
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- uint32_t reg = pmuadc_reg->ctl;
- reg &= ~PMUADC_CTL_REG_IBIAS_BUF_MASK;
- reg |= PMUADC_CTL_REG_IBIAS_BUF(CONFIG_PMUADC_IBIAS_BUF_SEL);
- reg &= ~PMUADC_CTL_REG_IBIAS_ADC_MASK;
- reg |= PMUADC_CTL_REG_IBIAS_ADC(CONFIG_PMUADC_IBIAS_ADC_SEL);
- pmuadc_reg->ctl = reg;
- return 0;
- }
- /* @brief ADC channels over sampling times setting */
- static int pmuadc_digital_setting(const struct device *dev)
- {
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- uint32_t reg = pmuadc_reg->dig_ctl;
- reg &= ~PMUADCDIG_CTL_BAT_AVG_MASK;
- reg |= PMUADCDIG_CTL_BAT_AVG(CONFIG_PMUADC_BAT_AVG_CNT);
- reg &= ~PMUADCDIG_CTL_LRADC1_AVG_MASK;
- reg |= PMUADCDIG_CTL_LRADC1_AVG(CONFIG_PMUADC_LRADC1_AVG);
- pmuadc_reg->dig_ctl = reg;
- return 0;
- }
- static void adc_cal_init(void)
- {
- unsigned int offset;
- adc_bat_offset = 0;
- adc_sensor_offset = 0;
- adc_dc5v_offset = 0;
- if (!soc_atp_get_pmu_calib(4, &offset)){
- LOG_DBG("get batadc cal=0x%x\n", offset);
- if(offset & 0x10) //转换成adc 校准值
- adc_bat_offset = -(0x20-offset)*16;
- else
- adc_bat_offset = offset*16;
- }
- /*
- if(sensor_efuse & 0x10)
- efuse_temp = - (0x20-sensor_efuse)*10;//offset校准按摄氏度,补码 0.1度
- else
- efuse_temp = sensor_efuse*10;
- adc_temp = 4532 - ((adc_val*7004)/4096);//单位0.1度 sd 算法
- -> 4532-((adc_val*1751)/1024)
- sensor_temp = adc_temp + efuse_temp
- = 4532-((adc_val*1751)/1024) + efuse_temp
- = 4532 -((adc_val*1751)/1024 - efuse_temp)
- = 4532 -(adc_val - efuse_temp*1024/1751)*1751/1024
- */
- if (!soc_atp_get_pmu_calib(5, &offset)){ //offset校准按摄氏度,补码 单位0.1度
- LOG_DBG("get sensoradc cal=0x%x\n", offset);
- if(offset & 0x10)
- adc_sensor_offset = -(0x20-offset)*10;
- else
- adc_sensor_offset = offset*10;
- /*把校准值转成adc 值*/
- adc_sensor_offset = -adc_sensor_offset*1024/1751;
- }
- if (!soc_atp_get_pmu_calib(7, &offset)){
- LOG_DBG("get dv5v cal=0x%x\n", offset);
- if(offset & 0x10)
- adc_dc5v_offset = -(0x20-offset)*4;
- else
- adc_dc5v_offset = offset*4;
- }
- LOG_DBG("adc:bat=%d,sensor=%d,dc5v=%d\n", adc_bat_offset, adc_sensor_offset, adc_dc5v_offset);
- }
- /* @brief PMU ADC initialization */
- static int pmuadc_init(const struct device *dev)
- {
- const struct pmuadc_config_data *cfg = dev->config;
- struct pmuadc_drv_data *data = dev->data;
- struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(dev);
- adc_cal_init();
- /* configure the LRADC clock source */
- pmuadc_clk_source_set(dev);
- acts_clock_peripheral_enable(cfg->clk_id);
- /* disable all ADC channels */
- pmuadc_reg->intmask = 0;
- pmuadc_reg->pending = pmuadc_reg->pending;
- pmuadc_reg->ctl &= ~0x3FFFFFF;
- /* set scan mode, scan one channel each time */
- pmuadc_reg->ctl |= PMUADC_CTL_SCAN_MODE;
- pmuadc_bias_setting(dev);
- pmuadc_digital_setting(dev);
- k_busy_wait(300);
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- k_sem_init(&data->completion, 0, 1);
- //#endif
- k_sem_init(&data->lock, 1, 1);
- if (cfg->irq_config)
- cfg->irq_config();
- #ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- data->b_always_on = true;
- irq_disable(IRQ_ID_LRADC);
- #else
- data->b_always_on = false;
- #endif
- return 0;
- }
- int pmuadc_mode_switch(bool always_on)
- {
- struct pmuadc_drv_data *data;
- const struct device *dev = device_get_binding(CONFIG_PMUADC_NAME);
- if (dev == NULL) {
- printk("ADC device not found\n");
- return -ENODEV;
- }
- data = dev->data;
- pmuadc_lock(dev);
- if(always_on){
- if(!data->b_always_on){
- printk("adc setto alwayson=0x%x\n", data->channel_bitmap);
- data->b_always_on = always_on;
- irq_disable(IRQ_ID_LRADC);
- pmuadc_enable_channels(dev, data->channel_bitmap);
- #if (CONFIG_PMUADC_BAT_AVG_CNT == 2)
- pmuadc_wait_sample_complete(dev, BIT(PMUADC_ID_BATV));
- #endif
- }
- }else{
- if(data->b_always_on){
- printk("adc setto not alwayson=0x%x\n", data->channel_bitmap);
- data->b_always_on = always_on;
- pmuadc_disable_channels(dev);
- irq_enable(IRQ_ID_LRADC);
- }
- }
- pmuadc_unlock(dev);
- return 0;
- }
- #ifdef CONFIG_PM_DEVICE
- int adc_pm_control(const struct device *device, enum pm_device_action action)
- {
- //int ret;
- //const struct pmuadc_config_data *cfg = device->config;
- struct pmuadc_drv_data *data = device->data;
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- // static uint32_t pmuadc_ctl_bak;
- // struct acts_pmu_adc *pmuadc_reg = get_pmuadc_reg_base(device);
- //#endif
- switch (action) {
- case PM_DEVICE_ACTION_RESUME:
- sl_dbg("adc wakeup\n");
- if(data->b_always_on){
- //acts_clock_peripheral_enable(cfg->clk_id);
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- //pmuadc_reg->ctl = (pmuadc_ctl_bak & ~PMUADC_CTL_PMUADC_EN);
- //LOG_DBG("%d PMUADC_CTL:0x%x", __LINE__, pmuadc_reg->ctl);
- //k_busy_wait(300);
- //pmuadc_reg->ctl |= PMUADC_CTL_PMUADC_EN;
- //LOG_DBG("%d PMUADC_CTL:0x%x", __LINE__, pmuadc_reg->ctl);
- //k_busy_wait(300);
- pmuadc_enable_channels(device, data->channel_bitmap);
- }else{
- //#else
- irq_enable(IRQ_ID_LRADC);
- //#endif
- }
- break;
- case PM_DEVICE_ACTION_SUSPEND:
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- if (!k_sem_count_get(&data->lock)) {
- printk("adc busy, not suspend\n");
- return -EINVAL;
- }
- //#endif
- sl_dbg("adc sleep\n");
- //#ifdef CONFIG_ADC_ACTS_ALWAYS_ON
- if(data->b_always_on){
- //pmuadc_ctl_bak = pmuadc_reg->ctl;
- pmuadc_disable_channels(device);
- //acts_clock_peripheral_disable(cfg->clk_id);
- }else{
- //#else
- irq_disable(IRQ_ID_LRADC);
- }
- //#endif
- break;
- case PM_DEVICE_ACTION_EARLY_SUSPEND:
- break;
- case PM_DEVICE_ACTION_LATE_RESUME:
- break;
- default:
- break;
- //ret = -EINVAL;
- }
- return 0;
- }
- #else
- #define adc_pm_control NULL
- #endif
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- static void pmuadc_irq_config(void);
- //#endif
- /* pmu adc driver data */
- static struct pmuadc_drv_data pmuadc_drv_data0;
- /* pmu adc config data */
- static const struct pmuadc_config_data pmuadc_config_data0 = {
- .reg_base = PMUADC_CTL,
- .clk_id = CLOCK_ID_LRADC,
- .clk_src = CONFIG_PMUADC_CLOCK_SOURCE,
- .clk_div = CONFIG_PMUADC_CLOCK_DIV,
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- .debounce = CONFIG_PMUADC_DEBOUNCE,
- .irq_config = pmuadc_irq_config,
- //#endif
- };
- DEVICE_DEFINE(pmuadc0, CONFIG_PMUADC_NAME, pmuadc_init, adc_pm_control,
- &pmuadc_drv_data0, &pmuadc_config_data0,
- PRE_KERNEL_2, CONFIG_KERNEL_INIT_PRIORITY_OBJECTS, &pmuadc_driver_api);
- //#ifndef CONFIG_ADC_ACTS_ALWAYS_ON
- static void pmuadc_irq_config(void)
- {
- IRQ_CONNECT(IRQ_ID_LRADC, CONFIG_PMUADC_IRQ_PRI,
- pmuadc_isr,
- DEVICE_GET(pmuadc0), 0);
- irq_enable(IRQ_ID_LRADC);
- }
- //#endif
|