403 lines
12 KiB
Diff
403 lines
12 KiB
Diff
diff -rupN linux.orig/drivers/iio/adc/rockchip_saradc.c linux/drivers/iio/adc/rockchip_saradc.c
|
|
--- linux.orig/drivers/iio/adc/rockchip_saradc.c 2024-01-09 14:07:12.430393829 +0000
|
|
+++ linux/drivers/iio/adc/rockchip_saradc.c 2024-01-09 16:30:43.561613614 +0000
|
|
@@ -4,13 +4,13 @@
|
|
* Copyright (C) 2014 ROCKCHIP, Inc.
|
|
*/
|
|
|
|
-#include <linux/bitfield.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
+#include <linux/of_device.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/delay.h>
|
|
@@ -38,31 +38,10 @@
|
|
#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 {
|
|
@@ -81,81 +60,27 @@ struct rockchip_saradc {
|
|
struct notifier_block nb;
|
|
};
|
|
|
|
-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)
|
|
-{
|
|
- 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);
|
|
+ /* Clear irq & power down adc */
|
|
+ writel_relaxed(0, info->regs + SARADC_CTRL);
|
|
}
|
|
|
|
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;
|
|
- rockchip_saradc_start(info, chan->channel);
|
|
+
|
|
+ /* 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);
|
|
|
|
if (!wait_for_completion_timeout(&info->completion, SARADC_TIMEOUT))
|
|
return -ETIMEDOUT;
|
|
@@ -198,7 +123,7 @@ static irqreturn_t rockchip_saradc_isr(i
|
|
struct rockchip_saradc *info = dev_id;
|
|
|
|
/* Read value */
|
|
- info->last_val = rockchip_saradc_read(info);
|
|
+ info->last_val = readl_relaxed(info->regs + SARADC_DATA);
|
|
info->last_val &= GENMASK(info->last_chan->scan_type.realbits - 1, 0);
|
|
|
|
rockchip_saradc_power_down(info);
|
|
@@ -238,9 +163,6 @@ static const struct rockchip_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[] = {
|
|
@@ -252,9 +174,6 @@ static const struct rockchip_saradc_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[] = {
|
|
@@ -270,9 +189,6 @@ static const struct rockchip_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[] = {
|
|
@@ -290,28 +206,6 @@ static const struct rockchip_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[] = {
|
|
@@ -327,9 +221,6 @@ static const struct of_device_id rockchi
|
|
}, {
|
|
.compatible = "rockchip,rk3568-saradc",
|
|
.data = &rk3568_saradc_data,
|
|
- }, {
|
|
- .compatible = "rockchip,rk3588-saradc",
|
|
- .data = &rk3588_saradc_data,
|
|
},
|
|
{},
|
|
};
|
|
@@ -345,6 +236,20 @@ static void rockchip_saradc_reset_contro
|
|
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;
|
|
@@ -393,7 +298,8 @@ 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);
|
|
@@ -413,10 +319,10 @@ static void rockchip_saradc_regulator_un
|
|
|
|
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;
|
|
|
|
@@ -424,23 +330,25 @@ static int rockchip_saradc_probe(struct
|
|
return -ENODEV;
|
|
|
|
indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
|
|
- if (!indio_dev)
|
|
- return dev_err_probe(&pdev->dev, -ENOMEM,
|
|
- "failed allocating iio device\n");
|
|
-
|
|
+ if (!indio_dev) {
|
|
+ dev_err(&pdev->dev, "failed allocating iio device\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
info = iio_priv(indio_dev);
|
|
|
|
- match_data = of_device_get_match_data(&pdev->dev);
|
|
- if (!match_data)
|
|
- return dev_err_probe(&pdev->dev, -ENODEV,
|
|
- "failed to match device\n");
|
|
+ match = of_match_device(rockchip_saradc_match, &pdev->dev);
|
|
+ if (!match) {
|
|
+ dev_err(&pdev->dev, "failed to match device\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
|
|
- 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)
|
|
- return dev_err_probe(&pdev->dev, -EINVAL,
|
|
- "max channels exceeded");
|
|
+ if (info->data->num_channels > SARADC_MAX_CHANNELS) {
|
|
+ dev_err(&pdev->dev, "max channels exceeded");
|
|
+ return -EINVAL;
|
|
+ }
|
|
|
|
info->regs = devm_platform_ioremap_resource(pdev, 0);
|
|
if (IS_ERR(info->regs))
|
|
@@ -466,7 +374,7 @@ static int rockchip_saradc_probe(struct
|
|
|
|
irq = platform_get_irq(pdev, 0);
|
|
if (irq < 0)
|
|
- return irq;
|
|
+ return dev_err_probe(&pdev->dev, irq, "failed to get irq\n");
|
|
|
|
ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
|
|
0, dev_name(&pdev->dev), info);
|
|
@@ -475,6 +383,16 @@ static int rockchip_saradc_probe(struct
|
|
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),
|
|
@@ -488,20 +406,23 @@ static int rockchip_saradc_probe(struct
|
|
* This may become user-configurable in the future.
|
|
*/
|
|
ret = clk_set_rate(info->clk, info->data->clk_rate);
|
|
- if (ret < 0)
|
|
- return dev_err_probe(&pdev->dev, ret,
|
|
- "failed to set adc clk rate\n");
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
|
|
ret = regulator_enable(info->vref);
|
|
- if (ret < 0)
|
|
- return dev_err_probe(&pdev->dev, ret,
|
|
- "failed to enable vref regulator\n");
|
|
-
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "failed to enable vref regulator\n");
|
|
+ return ret;
|
|
+ }
|
|
ret = devm_add_action_or_reset(&pdev->dev,
|
|
rockchip_saradc_regulator_disable, info);
|
|
- if (ret)
|
|
- return dev_err_probe(&pdev->dev, ret,
|
|
- "failed to register devm action\n");
|
|
+ if (ret) {
|
|
+ dev_err(&pdev->dev, "failed to register devm action, %d\n",
|
|
+ ret);
|
|
+ return ret;
|
|
+ }
|
|
|
|
ret = regulator_get_voltage(info->vref);
|
|
if (ret < 0)
|
|
@@ -509,15 +430,31 @@ static int rockchip_saradc_probe(struct
|
|
|
|
info->uv_vref = 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->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->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");
|
|
+ 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;
|
|
+ }
|
|
|
|
platform_set_drvdata(pdev, indio_dev);
|
|
|