blob: 303bd7ca41f95e7ce78649b4a7b0806bdfa8a6a8 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2018 Amlogic, Inc. All rights reserved.
* Author: Xingyu Chen <xingyu.chen@amlogic.com>
*
* Meson SARADC driver for U-Boot
*/
#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <asm/arch/saradc.h>
#include <asm/arch/secure_apb.h>
#define MESON_SAR_ADC_VDDA_VOLTAGE (1800000)
#define MESON_SAR_ADC_TIMEOUT (100 * 1000)
#define SAR_ADC_MAX_FIFO_SIZE 16
#define SAR_CLK_BASE AO_SAR_CLK
#define SAR_CLK_DIV_MASK GENMASK(7, 0)
#define SAR_CLK_DIV_SHIFT (0)
#define SAR_CLK_GATE BIT(8)
#define SAR_CLK_MUX_MASK GENMASK(10, 9)
#define SAR_ADC_REG0 0x00
#define SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28)
#define SAR_ADC_REG0_DELTA_BUSY BIT(30)
#define SAR_ADC_REG0_AVG_BUSY BIT(29)
#define SAR_ADC_REG0_SAMPLE_BUSY BIT(28)
#define SAR_ADC_REG0_FIFO_FULL BIT(27)
#define SAR_ADC_REG0_FIFO_EMPTY BIT(26)
#define SAR_ADC_REG0_FIFO_COUNT_SHIFT (21)
#define SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21)
#define SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16)
#define SAR_ADC_REG0_SAMPLING_STOP BIT(14)
#define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4)
#define SAR_ADC_REG0_FIFO_CNT_IRQ_SHIFT (4)
#define SAR_ADC_REG0_FIFO_IRQ_EN BIT(3)
#define SAR_ADC_REG0_SAMPLING_START BIT(2)
#define SAR_ADC_REG0_CONTINUOUS_EN BIT(1)
#define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0)
#define SAR_ADC_CHAN_LIST 0x04
#define SAR_ADC_CHAN_LIST_MAX_INDEX_SHIFT (24)
#define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24)
#define SAR_ADC_CHAN_LIST_ENTRY_SHIFT(_chan) (_chan * 3)
#define SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \
(GENMASK(2, 0) << ((_chan) * 3))
#define SAR_ADC_AVG_CNTL 0x08
#define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \
(16 + ((_chan) * 2))
#define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \
(GENMASK(17, 16) << ((_chan) * 2))
#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \
(0 + ((_chan) * 2))
#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \
(GENMASK(1, 0) << ((_chan) * 2))
#define SAR_ADC_REG3 0x0c
#define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27)
#define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26)
#define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23)
#define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_SHIFT (23)
#define SAR_ADC_REG3_ADC_EN BIT(21)
#define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8)
#define SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0)
#define SAR_ADC_DELAY 0x10
#define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24)
#define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16)
#define SAR_ADC_DELAY_BL30_BUSY BIT(15)
#define SAR_ADC_DELAY_KERNEL_BUSY BIT(14)
#define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8)
#define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0)
#define SAR_ADC_LAST_RD 0x14
#define SAR_ADC_FIFO_RD 0x18
#define SAR_ADC_FIFO_RD_CHAN_ID_SHIFT (12)
#define SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12)
#define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0)
#define SAR_ADC_AUX_SW 0x1c
#define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan) \
(GENMASK(10, 8) << (((_chan) - 2) * 3))
#define SAR_ADC_CHAN_10_SW 0x20
#define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23)
#define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7)
#define SAR_ADC_DETECT_IDLE_SW 0x24
#define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26)
#define SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23)
#define SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7)
#define SAR_ADC_DELTA_10 0x28
#define SAR_ADC_REG11 0x2c
#define SAR_ADC_REG11_VREF_SEL BIT(0)
#define SAR_ADC_REG11_VREF_EN BIT(5)
#define SAR_ADC_REG11_CMV_SEL BIT(6)
#define SAR_ADC_REG11_BANDGAP_EN BIT(13)
#define SAR_ADC_REG13 0x34
#define SAR_ADC_REG13_CALIB_FACTOR_MASK GENMASK(13, 8)
enum MESON_SARADC_AVG_MODE {
NO_AVERAGING = 0x0,
MEAN_AVERAGING = 0x1,
MEDIAN_AVERAGING = 0x2,
};
enum MESON_SARADC_NUM_SAMPLES {
ONE_SAMPLE = 0x0,
TWO_SAMPLES = 0x1,
FOUR_SAMPLES = 0x2,
EIGHT_SAMPLES = 0x3,
};
enum MESON_SARADC_RESOLUTION {
SARADC_10BIT = 10,
SARADC_12BIT = 12,
};
enum MESON_SARADC_BIT_STATE {
BIT_LOW = 0,
BIT_HIGH = 1,
};
/*
* struct meson_saradc_reg_diff - various information relative to registers
*
* @reg3_ring_counter_disable: to disable continuous ring counter.
* gxl and later: 1; others(gxtvbb etc): 0
* @reg11_vref_en: g12a and later: 0; others(axg etc): 1
* @reg11_cmv_sel: g12a and later: 0; others(axg etc): 1
*/
struct meson_saradc_reg_diff {
bool reg3_ring_counter_disable;
bool reg11_vref_en;
bool reg11_cmv_sel;
};
/*
* struct meson_saradc_data - describe the differences of different platform
*
* @has_bl30_integration:
* @num_channels: the number of adc channels
* @self_test_channel: channel of self-test
* @resolution: gxl and later: 12bit; others(gxtvbb etc): 10bit
* @regs_diff: to describe the differences of the registers
*/
struct meson_saradc_data {
bool has_bl30_integration;
unsigned char self_test_channel;
unsigned char num_channels;
unsigned int resolution;
struct meson_saradc_reg_diff regs_diff;
};
struct meson_saradc {
phys_addr_t base;
int active_channel;
struct meson_saradc_data *data;
};
static void meson_saradc_hw_init(struct meson_saradc *priv)
{
/* create association between logic and physical channel */
writel(0x03eb1a0c, priv->base + SAR_ADC_AUX_SW);
writel(0x008c000c, priv->base + SAR_ADC_CHAN_10_SW);
/* disable all channels by default */
writel(0x00000000, priv->base + SAR_ADC_CHAN_LIST);
/* delay between two input/samples = (10 + 1) * 1us */
writel(0x010a000a, priv->base + SAR_ADC_DELAY);
/*
* BIT[21]: disable the ADC by default
* BIT[23-25]: vdda*3/4 connect to channel-7 by default
* BIT[26]: select the sampling clock period: 0:3T, 1:5T
* BIT[27]: disable ring counter
*/
writel(0x0980000a, priv->base + SAR_ADC_REG3);
/* disable continuous sampling mode */
clrsetbits_le32(priv->base + SAR_ADC_REG0,
SAR_ADC_REG0_CONTINUOUS_EN, 0);
/* clock initialization: 1.2M=24M/(0x13 + 1) */
clrsetbits_le32(SAR_CLK_BASE, SAR_CLK_DIV_MASK,
0x13 << SAR_CLK_DIV_SHIFT);
}
static void meson_saradc_hw_enable(struct meson_saradc *priv)
{
clrsetbits_le32(priv->base + SAR_ADC_REG11,
SAR_ADC_REG11_CMV_SEL |
SAR_ADC_REG11_VREF_EN |
SAR_ADC_REG11_BANDGAP_EN,
(priv->data->regs_diff.reg11_cmv_sel ?
SAR_ADC_REG11_CMV_SEL : 0) |
(priv->data->regs_diff.reg11_vref_en ?
SAR_ADC_REG11_VREF_EN : 0) |
SAR_ADC_REG11_BANDGAP_EN);
clrsetbits_le32(SAR_CLK_BASE, SAR_CLK_GATE, SAR_CLK_GATE);
clrsetbits_le32(priv->base + SAR_ADC_REG0,
SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
clrsetbits_le32(priv->base + SAR_ADC_REG3,
SAR_ADC_REG3_ADC_EN,
SAR_ADC_REG3_ADC_EN);
}
static void meson_saradc_hw_disable(struct meson_saradc *priv)
{
clrsetbits_le32(priv->base + SAR_ADC_REG3,
SAR_ADC_REG3_ADC_EN, 0);
clrsetbits_le32(priv->base + SAR_ADC_REG0,
SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
clrsetbits_le32(SAR_CLK_BASE, SAR_CLK_GATE, 0);
}
static inline int meson_saradc_get_race_flag(struct meson_saradc *priv)
{
int val;
int timeout = 10000;
/* wait until BL30 releases it's lock (so we can use
* the SAR ADC)
*/
if (priv->data->has_bl30_integration)
{
do {
udelay(1);
val = readl(priv->base + SAR_ADC_DELAY);
} while ((val & SAR_ADC_DELAY_BL30_BUSY) && timeout--);
if (timeout < 0)
return -ETIMEDOUT;
/* prevent BL30 from using the SAR ADC while we are using it */
clrsetbits_le32(priv->base + SAR_ADC_DELAY,
SAR_ADC_DELAY_KERNEL_BUSY,
SAR_ADC_DELAY_KERNEL_BUSY);
udelay(1);
val = readl(priv->base + SAR_ADC_DELAY);
if (val & SAR_ADC_DELAY_BL30_BUSY) {
clrsetbits_le32(priv->base + SAR_ADC_DELAY,
SAR_ADC_DELAY_KERNEL_BUSY, 0);
return -ETIMEDOUT;
}
}
return 0;
}
static inline void meson_saradc_put_race_flag(struct meson_saradc *priv)
{
if (priv->data->has_bl30_integration)
clrsetbits_le32(priv->base + SAR_ADC_DELAY,
SAR_ADC_DELAY_KERNEL_BUSY, 0);
}
static inline void meson_saradc_enable_channel(struct meson_saradc *priv,
int ch, int idx)
{
clrsetbits_le32(priv->base + SAR_ADC_CHAN_LIST,
SAR_ADC_CHAN_LIST_MAX_INDEX_MASK,
idx << SAR_ADC_CHAN_LIST_MAX_INDEX_SHIFT);
clrsetbits_le32(priv->base + SAR_ADC_CHAN_LIST,
SAR_ADC_CHAN_LIST_ENTRY_MASK(idx),
ch << SAR_ADC_CHAN_LIST_ENTRY_SHIFT(idx));
}
static inline void meson_saradc_clear_fifo(struct meson_saradc *priv)
{
int i;
for (i = 0; i < 32; i++) {
if (!((readl(priv->base + SAR_ADC_REG0) >>
SAR_ADC_REG0_FIFO_COUNT_SHIFT) & 0x1f))
break;
readl(priv->base + SAR_ADC_FIFO_RD);
}
}
static inline void meson_saradc_start_sample(struct meson_saradc *priv)
{
clrsetbits_le32(priv->base + SAR_ADC_REG0,
SAR_ADC_REG0_SAMPLING_START |
SAR_ADC_REG0_SAMPLING_STOP,
SAR_ADC_REG0_SAMPLING_START);
}
static int meson_saradc_set_mode(struct udevice *dev, int ch, unsigned int mode)
{
struct meson_saradc *priv = dev_get_priv(dev);
if (mode & ADC_CAPACITY_AVERAGE) {
clrsetbits_le32(priv->base + SAR_ADC_AVG_CNTL,
SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(ch),
EIGHT_SAMPLES << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(ch));
clrsetbits_le32(priv->base + SAR_ADC_AVG_CNTL,
SAR_ADC_AVG_CNTL_AVG_MODE_MASK(ch),
MEDIAN_AVERAGING << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(ch));
} else {
clrsetbits_le32(priv->base + SAR_ADC_AVG_CNTL,
SAR_ADC_AVG_CNTL_AVG_MODE_MASK(ch),
NO_AVERAGING << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(ch));
}
/*
* the precision of internal voltage is approximately equal to 10mv,
* but the VDDA is approximately equal to 36mv(2% x 1800mv).
*/
if (mode & ADC_CAPACITY_HIGH_PRECISION_VREF) {
if (readl(priv->base + SAR_ADC_REG13) &
SAR_ADC_REG13_CALIB_FACTOR_MASK) {
/* select the internal voltage as reference voltage */
clrsetbits_le32(priv->base + SAR_ADC_REG11,
SAR_ADC_REG11_VREF_SEL, 0);
} else {
/* select the VDDA as reference voltage */
clrsetbits_le32(priv->base + SAR_ADC_REG11,
SAR_ADC_REG11_VREF_SEL,
SAR_ADC_REG11_VREF_SEL);
pr_notice("%s: calib factor is null, \
please set it in bl30 first\n",
dev->name);
}
} else {
/* select the VDDA as reference voltage */
clrsetbits_le32(priv->base + SAR_ADC_REG11,
SAR_ADC_REG11_VREF_SEL,
SAR_ADC_REG11_VREF_SEL);
}
return 0;
}
static int meson_saradc_start_channel(struct udevice *dev, int channel)
{
int ret;
struct meson_saradc *priv = dev_get_priv(dev);
ret = meson_saradc_get_race_flag(priv);
if (ret)
return ret;
meson_saradc_enable_channel(priv, channel, 0);
meson_saradc_clear_fifo(priv);
meson_saradc_start_sample(priv);
priv->active_channel = channel;
return 0;
}
static int meson_saradc_stop(struct udevice *dev)
{
/* current driver only support single sampling mode, the adc
* converter will stop automatically when one sampling is
* completed, so it is not necessary to stop sampling manually
* in current location. However, if the adc module working in
* continues sampling mode, we need to write REG0 bit[14] to
* stop sampling.
*/
return 0;
}
static int meson_saradc_channel_data(struct udevice *dev, int channel,
unsigned int *data)
{
int val;
int fifo_ch;
struct meson_saradc *priv = dev_get_priv(dev);
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
if (priv->active_channel != channel) {
pr_err("%s: requested channel is not active!\n", dev->name);
return -EINVAL;
}
if (readl(priv->base + SAR_ADC_REG0) & SAR_ADC_REG0_BUSY_MASK)
return -EBUSY;
val = readl(priv->base + SAR_ADC_FIFO_RD);
fifo_ch = (val >> SAR_ADC_FIFO_RD_CHAN_ID_SHIFT) & 0x7;
if (fifo_ch != channel) {
pr_err("%s: channel mismatch: exp[%d] - act[%d]\n",
dev->name, channel, fifo_ch);
return -EINVAL;
}
*data = val & uc_pdata->data_mask;
priv->active_channel = -1;
meson_saradc_put_race_flag(priv);
return 0;
}
static int meson_saradc_select_input_voltage(struct udevice *dev, int channel,
int mux)
{
struct meson_saradc *priv = dev_get_priv(dev);
if (channel != priv->data->self_test_channel) {
pr_err("%s: channel[%d] does not support self-test\n",
dev->name, channel);
return -EINVAL;
}
clrsetbits_le32(priv->base + SAR_ADC_REG3,
SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK,
(mux & 0x7) << SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_SHIFT);
return 0;
}
static const struct adc_ops meson_saradc_ops = {
.set_mode = meson_saradc_set_mode,
.start_channel = meson_saradc_start_channel,
.channel_data = meson_saradc_channel_data,
.stop = meson_saradc_stop,
.select_input_voltage = meson_saradc_select_input_voltage,
};
static int meson_saradc_probe(struct udevice *dev)
{
struct meson_saradc *priv = dev_get_priv(dev);
priv->base = devfdt_get_addr(dev);
if (priv->base == FDT_ADDR_T_NONE) {
pr_err("%s: cannot find saradc base address\n", dev->name);
return -EINVAL;
}
priv->active_channel = -1;
meson_saradc_hw_init(priv);
meson_saradc_hw_enable(priv);
return 0;
}
static int meson_saradc_remove(struct udevice *dev)
{
struct meson_saradc *priv = dev_get_priv(dev);
meson_saradc_hw_disable(priv);
return 0;
}
static int meson_saradc_ofdata_to_platdata(struct udevice *dev)
{
struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
struct meson_saradc *priv = dev_get_priv(dev);
priv->data = (struct meson_saradc_data *)dev_get_driver_data(dev);
uc_pdata->data_mask = (1 << priv->data->resolution) - 1;
uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
uc_pdata->data_timeout_us = MESON_SAR_ADC_TIMEOUT;
uc_pdata->channel_mask = (1 << priv->data->num_channels) - 1;
uc_pdata->vdd_microvolts = MESON_SAR_ADC_VDDA_VOLTAGE;
return 0;
}
static struct meson_saradc_data meson_saradc_g12a_data = {
.has_bl30_integration = true,
.self_test_channel = SARADC_CH_SELF_TEST,
.num_channels = MESON_SARADC_CH_MAX,
.resolution = SARADC_12BIT,
.regs_diff = {
.reg3_ring_counter_disable = BIT_HIGH,
.reg11_vref_en = BIT_LOW,
.reg11_cmv_sel = BIT_LOW,
},
};
static const struct udevice_id meson_saradc_ids[] = {
{
.compatible = "amlogic,meson-g12a-saradc",
.data = (ulong)&meson_saradc_g12a_data,
},
{ }
};
U_BOOT_DRIVER(meson_saradc) = {
.name = "meson_saradc",
.id = UCLASS_ADC,
.of_match = meson_saradc_ids,
.ops = &meson_saradc_ops,
.probe = meson_saradc_probe,
.remove = meson_saradc_remove,
.ofdata_to_platdata = meson_saradc_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct meson_saradc),
};