summaryrefslogtreecommitdiff
path: root/drivers/iio/adc/rockchip_saradc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/rockchip_saradc.c')
-rw-r--r--drivers/iio/adc/rockchip_saradc.c246
1 files changed, 155 insertions, 91 deletions
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 79448c5ffc2a..4b011f7eddec 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -4,6 +4,7 @@
* Copyright (C) 2014 ROCKCHIP, Inc.
*/
+#include <linux/bitfield.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
@@ -38,10 +39,31 @@
#define SARADC_TIMEOUT msecs_to_jiffies(100)
#define SARADC_MAX_CHANNELS 8
+/* v2 registers */
+#define SARADC2_CONV_CON 0x000
+#define SARADC_T_PD_SOC 0x004
+#define SARADC_T_DAS_SOC 0x00c
+#define SARADC2_END_INT_EN 0x104
+#define SARADC2_ST_CON 0x108
+#define SARADC2_STATUS 0x10c
+#define SARADC2_END_INT_ST 0x110
+#define SARADC2_DATA_BASE 0x120
+
+#define SARADC2_EN_END_INT BIT(0)
+#define SARADC2_START BIT(4)
+#define SARADC2_SINGLE_MODE BIT(5)
+
+#define SARADC2_CONV_CHANNELS GENMASK(15, 0)
+
+struct rockchip_saradc;
+
struct rockchip_saradc_data {
const struct iio_chan_spec *channels;
int num_channels;
unsigned long clk_rate;
+ void (*start)(struct rockchip_saradc *info, int chn);
+ int (*read)(struct rockchip_saradc *info);
+ void (*power_down)(struct rockchip_saradc *info);
};
struct rockchip_saradc {
@@ -60,27 +82,81 @@ struct rockchip_saradc {
struct notifier_block nb;
};
-static void rockchip_saradc_power_down(struct rockchip_saradc *info)
+static void rockchip_saradc_reset_controller(struct reset_control *reset);
+
+static void rockchip_saradc_start_v1(struct rockchip_saradc *info, int chn)
+{
+ /* 8 clock periods as delay between power up and start cmd */
+ writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
+ /* Select the channel to be used and trigger conversion */
+ writel(SARADC_CTRL_POWER_CTRL | (chn & SARADC_CTRL_CHN_MASK) |
+ SARADC_CTRL_IRQ_ENABLE, info->regs + SARADC_CTRL);
+}
+
+static void rockchip_saradc_start_v2(struct rockchip_saradc *info, int chn)
+{
+ int val;
+
+ if (info->reset)
+ rockchip_saradc_reset_controller(info->reset);
+
+ writel_relaxed(0xc, info->regs + SARADC_T_DAS_SOC);
+ writel_relaxed(0x20, info->regs + SARADC_T_PD_SOC);
+ val = FIELD_PREP(SARADC2_EN_END_INT, 1);
+ val |= val << 16;
+ writel_relaxed(val, info->regs + SARADC2_END_INT_EN);
+ val = FIELD_PREP(SARADC2_START, 1) |
+ FIELD_PREP(SARADC2_SINGLE_MODE, 1) |
+ FIELD_PREP(SARADC2_CONV_CHANNELS, chn);
+ val |= val << 16;
+ writel(val, info->regs + SARADC2_CONV_CON);
+}
+
+static void rockchip_saradc_start(struct rockchip_saradc *info, int chn)
+{
+ info->data->start(info, chn);
+}
+
+static int rockchip_saradc_read_v1(struct rockchip_saradc *info)
+{
+ return readl_relaxed(info->regs + SARADC_DATA);
+}
+
+static int rockchip_saradc_read_v2(struct rockchip_saradc *info)
+{
+ int offset;
+
+ /* Clear irq */
+ writel_relaxed(0x1, info->regs + SARADC2_END_INT_ST);
+
+ offset = SARADC2_DATA_BASE + info->last_chan->channel * 0x4;
+
+ return readl_relaxed(info->regs + offset);
+}
+
+static int rockchip_saradc_read(struct rockchip_saradc *info)
+{
+ return info->data->read(info);
+}
+
+static void rockchip_saradc_power_down_v1(struct rockchip_saradc *info)
{
- /* Clear irq & power down adc */
writel_relaxed(0, info->regs + SARADC_CTRL);
}
+static void rockchip_saradc_power_down(struct rockchip_saradc *info)
+{
+ if (info->data->power_down)
+ info->data->power_down(info);
+}
+
static int rockchip_saradc_conversion(struct rockchip_saradc *info,
- struct iio_chan_spec const *chan)
+ struct iio_chan_spec const *chan)
{
reinit_completion(&info->completion);
- /* 8 clock periods as delay between power up and start cmd */
- writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC);
-
info->last_chan = chan;
-
- /* Select the channel to be used and trigger conversion */
- writel(SARADC_CTRL_POWER_CTRL
- | (chan->channel & SARADC_CTRL_CHN_MASK)
- | SARADC_CTRL_IRQ_ENABLE,
- info->regs + SARADC_CTRL);
+ rockchip_saradc_start(info, chan->channel);
if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT))
return -ETIMEDOUT;
@@ -123,7 +199,7 @@ static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id)
struct rockchip_saradc *info = dev_id;
/* Read value */
- info->last_val = readl_relaxed(info->regs + SARADC_DATA);
+ info->last_val = rockchip_saradc_read(info);
info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0);
rockchip_saradc_power_down(info);
@@ -163,6 +239,9 @@ static const struct rockchip_saradc_data saradc_data = {
.channels = rockchip_saradc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels),
.clk_rate = 1000000,
+ .start = rockchip_saradc_start_v1,
+ .read = rockchip_saradc_read_v1,
+ .power_down = rockchip_saradc_power_down_v1,
};
static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = {
@@ -174,6 +253,9 @@ static const struct rockchip_saradc_data rk3066_tsadc_data = {
.channels = rockchip_rk3066_tsadc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels),
.clk_rate = 50000,
+ .start = rockchip_saradc_start_v1,
+ .read = rockchip_saradc_read_v1,
+ .power_down = rockchip_saradc_power_down_v1,
};
static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = {
@@ -189,6 +271,9 @@ static const struct rockchip_saradc_data rk3399_saradc_data = {
.channels = rockchip_rk3399_saradc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels),
.clk_rate = 1000000,
+ .start = rockchip_saradc_start_v1,
+ .read = rockchip_saradc_read_v1,
+ .power_down = rockchip_saradc_power_down_v1,
};
static const struct iio_chan_spec rockchip_rk3568_saradc_iio_channels[] = {
@@ -206,6 +291,28 @@ static const struct rockchip_saradc_data rk3568_saradc_data = {
.channels = rockchip_rk3568_saradc_iio_channels,
.num_channels = ARRAY_SIZE(rockchip_rk3568_saradc_iio_channels),
.clk_rate = 1000000,
+ .start = rockchip_saradc_start_v1,
+ .read = rockchip_saradc_read_v1,
+ .power_down = rockchip_saradc_power_down_v1,
+};
+
+static const struct iio_chan_spec rockchip_rk3588_saradc_iio_channels[] = {
+ SARADC_CHANNEL(0, "adc0", 12),
+ SARADC_CHANNEL(1, "adc1", 12),
+ SARADC_CHANNEL(2, "adc2", 12),
+ SARADC_CHANNEL(3, "adc3", 12),
+ SARADC_CHANNEL(4, "adc4", 12),
+ SARADC_CHANNEL(5, "adc5", 12),
+ SARADC_CHANNEL(6, "adc6", 12),
+ SARADC_CHANNEL(7, "adc7", 12),
+};
+
+static const struct rockchip_saradc_data rk3588_saradc_data = {
+ .channels = rockchip_rk3588_saradc_iio_channels,
+ .num_channels = ARRAY_SIZE(rockchip_rk3588_saradc_iio_channels),
+ .clk_rate = 1000000,
+ .start = rockchip_saradc_start_v2,
+ .read = rockchip_saradc_read_v2,
};
static const struct of_device_id rockchip_saradc_match[] = {
@@ -221,6 +328,9 @@ static const struct of_device_id rockchip_saradc_match[] = {
}, {
.compatible = "rockchip,rk3568-saradc",
.data = &rk3568_saradc_data,
+ }, {
+ .compatible = "rockchip,rk3588-saradc",
+ .data = &rk3588_saradc_data,
},
{},
};
@@ -236,20 +346,6 @@ static void rockchip_saradc_reset_controller(struct reset_control *reset)
reset_control_deassert(reset);
}
-static void rockchip_saradc_clk_disable(void *data)
-{
- struct rockchip_saradc *info = data;
-
- clk_disable_unprepare(info->clk);
-}
-
-static void rockchip_saradc_pclk_disable(void *data)
-{
- struct rockchip_saradc *info = data;
-
- clk_disable_unprepare(info->pclk);
-}
-
static void rockchip_saradc_regulator_disable(void *data)
{
struct rockchip_saradc *info = data;
@@ -298,8 +394,7 @@ out:
}
static int rockchip_saradc_volt_notify(struct notifier_block *nb,
- unsigned long event,
- void *data)
+ unsigned long event, void *data)
{
struct rockchip_saradc *info =
container_of(nb, struct rockchip_saradc, nb);
@@ -319,10 +414,10 @@ static void rockchip_saradc_regulator_unreg_notifier(void *data)
static int rockchip_saradc_probe(struct platform_device *pdev)
{
+ const struct rockchip_saradc_data *match_data;
struct rockchip_saradc *info = NULL;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
- const struct of_device_id *match;
int ret;
int irq;
@@ -330,25 +425,23 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
return -ENODEV;
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
- if (!indio_dev) {
- dev_err(&pdev->dev, "failed allocating iio device\n");
- return -ENOMEM;
- }
+ if (!indio_dev)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "failed allocating iio device\n");
+
info = iio_priv(indio_dev);
- match = of_match_device(rockchip_saradc_match, &pdev->dev);
- if (!match) {
- dev_err(&pdev->dev, "failed to match device\n");
- return -ENODEV;
- }
+ match_data = of_device_get_match_data(&pdev->dev);
+ if (!match_data)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to match device\n");
- info->data = match->data;
+ info->data = match_data;
/* Sanity check for possible later IP variants with more channels */
- if (info->data->num_channels > SARADC_MAX_CHANNELS) {
- dev_err(&pdev->dev, "max channels exceeded");
- return -EINVAL;
- }
+ if (info->data->num_channels > SARADC_MAX_CHANNELS)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "max channels exceeded");
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
@@ -383,16 +476,6 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
return ret;
}
- info->pclk = devm_clk_get(&pdev->dev, "apb_pclk");
- if (IS_ERR(info->pclk))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
- "failed to get pclk\n");
-
- info->clk = devm_clk_get(&pdev->dev, "saradc");
- if (IS_ERR(info->clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
- "failed to get adc clock\n");
-
info->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(info->vref))
return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
@@ -406,23 +489,20 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
* This may become user-configurable in the future.
*/
ret = clk_set_rate(info->clk, info->data->clk_rate);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to set adc clk rate\n");
ret = regulator_enable(info->vref);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to enable vref regulator\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to enable vref regulator\n");
+
ret = devm_add_action_or_reset(&pdev->dev,
rockchip_saradc_regulator_disable, info);
- if (ret) {
- dev_err(&pdev->dev, "failed to register devm action, %d\n",
- ret);
- return ret;
- }
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "failed to register devm action\n");
ret = regulator_get_voltage(info->vref);
if (ret < 0)
@@ -430,31 +510,15 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
info->uv_vref = ret;
- ret = clk_prepare_enable(info->pclk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to enable pclk\n");
- return ret;
- }
- ret = devm_add_action_or_reset(&pdev->dev,
- rockchip_saradc_pclk_disable, info);
- if (ret) {
- dev_err(&pdev->dev, "failed to register devm action, %d\n",
- ret);
- return ret;
- }
+ info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
+ if (IS_ERR(info->pclk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
+ "failed to get pclk\n");
- ret = clk_prepare_enable(info->clk);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to enable converter clock\n");
- return ret;
- }
- ret = devm_add_action_or_reset(&pdev->dev,
- rockchip_saradc_clk_disable, info);
- if (ret) {
- dev_err(&pdev->dev, "failed to register devm action, %d\n",
- ret);
- return ret;
- }
+ info->clk = devm_clk_get_enabled(&pdev->dev, "saradc");
+ if (IS_ERR(info->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
+ "failed to get adc clock\n");
platform_set_drvdata(pdev, indio_dev);