This patch is used to handle the difference between ast2600
and previous versions.

Signed-off-by: Billy Tsai <billy_t...@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 129 ++++++++++++++++++++++++++---------
 1 file changed, 95 insertions(+), 34 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index ae400c4d6d40..fc4bbccf9348 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Aspeed AST2400/2500 ADC
+ * Aspeed AST2400/2500/2600 ADC
  *
  * Copyright (C) 2017 Google, Inc.
  */
@@ -81,6 +81,7 @@ struct aspeed_adc_model_data {
        unsigned int max_sampling_rate; // Hz
        unsigned int vref_voltage;      // mV
        bool wait_init_sequence;
+       int num_channels;
 };
 
 struct aspeed_adc_data {
@@ -90,6 +91,7 @@ struct aspeed_adc_data {
        struct clk_hw           *clk_prescaler;
        struct clk_hw           *clk_scaler;
        struct reset_control    *rst;
+       unsigned int vref_voltage;      // mV
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {                    \
@@ -126,8 +128,6 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
                               int *val, int *val2, long mask)
 {
        struct aspeed_adc_data *data = iio_priv(indio_dev);
-       const struct aspeed_adc_model_data *model_data =
-                       of_device_get_match_data(data->dev);
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
@@ -135,7 +135,7 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
-               *val = model_data->vref_voltage;
+               *val = data->vref_voltage;
                *val2 = ASPEED_RESOLUTION_BITS;
                return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -208,8 +208,13 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        struct aspeed_adc_data *data;
        const struct aspeed_adc_model_data *model_data;
        const char *clk_parent_name;
+       char prescaler_clk_name[32];
+       char scaler_clk_name[32];
        int ret;
        u32 adc_engine_control_reg_val;
+       u32 ref_voltage_cfg = 0;
+
+       model_data = of_device_get_match_data(&pdev->dev);
 
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
        if (!indio_dev)
@@ -225,29 +230,75 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        /* Register ADC clock prescaler with source specified by device tree. */
        spin_lock_init(&data->clk_lock);
        clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
+       snprintf(prescaler_clk_name, sizeof(prescaler_clk_name),
+                       "prescaler-%s", pdev->name);
+       snprintf(scaler_clk_name, sizeof(scaler_clk_name),
+                       "scaler-%s", pdev->name);
+       if (!strcmp(model_data->model_name, "ast2400-adc") ||
+           !strcmp(model_data->model_name, "ast2500-adc")) {
+               /* Divider config */
+               data->clk_prescaler = clk_hw_register_divider(
+                               &pdev->dev, prescaler_clk_name, clk_parent_name,
+                               0,
+                               data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15,
+                               CLK_DIVIDER_ONE_BASED, &data->clk_lock);
+               if (IS_ERR(data->clk_prescaler))
+                       return PTR_ERR(data->clk_prescaler);
 
-       data->clk_prescaler = clk_hw_register_divider(
-                               &pdev->dev, "prescaler", clk_parent_name, 0,
-                               data->base + ASPEED_REG_CLOCK_CONTROL,
-                               17, 15, 0, &data->clk_lock);
-       if (IS_ERR(data->clk_prescaler))
-               return PTR_ERR(data->clk_prescaler);
-
-       /*
-        * Register ADC clock scaler downstream from the prescaler. Allow rate
-        * setting to adjust the prescaler as well.
-        */
-       data->clk_scaler = clk_hw_register_divider(
-                               &pdev->dev, "scaler", "prescaler",
-                               CLK_SET_RATE_PARENT,
-                               data->base + ASPEED_REG_CLOCK_CONTROL,
-                               0, 10, 0, &data->clk_lock);
-       if (IS_ERR(data->clk_scaler)) {
-               ret = PTR_ERR(data->clk_scaler);
-               goto scaler_error;
+               /*
+                * Register ADC clock scaler downstream from the prescaler. 
Allow rate
+                * setting to adjust the prescaler as well.
+                */
+               data->clk_scaler = clk_hw_register_divider(
+                                       &pdev->dev, scaler_clk_name, 
prescaler_clk_name,
+                                       CLK_SET_RATE_PARENT,
+                                       data->base + ASPEED_REG_CLOCK_CONTROL, 
0, 10,
+                                       CLK_DIVIDER_ONE_BASED, &data->clk_lock);
+               if (IS_ERR(data->clk_scaler)) {
+                       ret = PTR_ERR(data->clk_scaler);
+                       goto scaler_error;
+               }
+               /* Get ref_voltage */
+               data->vref_voltage = model_data->vref_voltage;
+       } else if (!strcmp(model_data->model_name, "ast2600-adc")) {
+               /* Divider config */
+               data->clk_scaler = clk_hw_register_divider(
+                       &pdev->dev, scaler_clk_name, clk_parent_name,
+                       CLK_SET_RATE_UNGATE,
+                       data->base + ASPEED_REG_CLOCK_CONTROL, 0, 16,
+                       CLK_DIVIDER_ONE_BASED, &data->clk_lock);
+               if (IS_ERR(data->clk_scaler))
+                       return PTR_ERR(data->clk_scaler);
+               /*
+                * Get ref_voltage:
+                * If reference voltage is between 1550~1650mv, we can set
+                * fields either ASPEED_REF_VOLTAGE_EXT_HIGH or 
ASPEED_REF_VOLTAGE_EXT_LOW.
+                * In this place, we select ASPEED_REF_VOLTAGE_EXT_HIGH as 
higher priority.
+                */
+               if (!of_property_read_u32(pdev->dev.of_node, "ref_voltage",
+                                         &data->vref_voltage)) {
+                       if (data->vref_voltage == 2500)
+                               ref_voltage_cfg = ASPEED_REF_VOLTAGE_2500mV;
+                       else if (data->vref_voltage == 1200)
+                               ref_voltage_cfg = ASPEED_REF_VOLTAGE_1200mV;
+                       else if ((data->vref_voltage >= 1550) &&
+                                       (data->vref_voltage <= 2700))
+                               ref_voltage_cfg = ASPEED_REF_VOLTAGE_EXT_HIGH;
+                       else if ((data->vref_voltage >= 900) &&
+                                       (data->vref_voltage <= 1650))
+                               ref_voltage_cfg = ASPEED_REF_VOLTAGE_EXT_LOW;
+                       else {
+                               dev_err(&pdev->dev, "ref_voltage property is 
out of range: %d\n",
+                                       data->vref_voltage);
+                               return -EINVAL;
+                       }
+               } else {
+                       dev_err(&pdev->dev, "Couldn't read ref_voltage 
property\n");
+                       return -EINVAL;
+               }
        }
 
-       data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+       data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
        if (IS_ERR(data->rst)) {
                dev_err(&pdev->dev,
                        "invalid or missing reset controller device tree 
entry");
@@ -256,13 +307,14 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        }
        reset_control_deassert(data->rst);
 
-       model_data = of_device_get_match_data(&pdev->dev);
+       adc_engine_control_reg_val = readl(data->base + 
ASPEED_REG_ENGINE_CONTROL);
+       /* Enable engine in normal mode and set ref_voltage */
+       adc_engine_control_reg_val |= (ASPEED_OPERATION_MODE_NORMAL |
+                               ASPEED_ENGINE_ENABLE | ref_voltage_cfg);
+       writel(adc_engine_control_reg_val,
+                       data->base + ASPEED_REG_ENGINE_CONTROL);
 
        if (model_data->wait_init_sequence) {
-               /* Enable engine in normal mode. */
-               writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
-                      data->base + ASPEED_REG_ENGINE_CONTROL);
-
                /* Wait for initial sequence complete. */
                ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
                                         adc_engine_control_reg_val,
@@ -279,18 +331,16 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        if (ret)
                goto clk_enable_error;
 
-       adc_engine_control_reg_val = GENMASK(31, 16) |
-               ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+       adc_engine_control_reg_val |= ASPEED_ADC_CTRL_CH_EN_ALL;
        writel(adc_engine_control_reg_val,
                data->base + ASPEED_REG_ENGINE_CONTROL);
 
-       model_data = of_device_get_match_data(&pdev->dev);
        indio_dev->name = model_data->model_name;
        indio_dev->dev.parent = &pdev->dev;
        indio_dev->info = &aspeed_adc_iio_info;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->channels = aspeed_adc_iio_channels;
-       indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels);
+       indio_dev->num_channels = model_data->num_channels;
 
        ret = iio_device_register(indio_dev);
        if (ret)
@@ -333,6 +383,7 @@ static const struct aspeed_adc_model_data 
ast2400_model_data = {
        .vref_voltage = 2500, // mV
        .min_sampling_rate = 10000,
        .max_sampling_rate = 500000,
+       .num_channels = 16,
 };
 
 static const struct aspeed_adc_model_data ast2500_model_data = {
@@ -341,11 +392,21 @@ static const struct aspeed_adc_model_data 
ast2500_model_data = {
        .min_sampling_rate = 1,
        .max_sampling_rate = 1000000,
        .wait_init_sequence = true,
+       .num_channels = 16,
+};
+
+static const struct aspeed_adc_model_data ast2600_model_data = {
+       .model_name = "ast2600-adc",
+       .min_sampling_rate = 1,
+       .max_sampling_rate = 1000000,
+       .wait_init_sequence = true,
+       .num_channels = 8,
 };
 
 static const struct of_device_id aspeed_adc_matches[] = {
        { .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
        { .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
+       { .compatible = "aspeed,ast2600-adc", .data = &ast2600_model_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
@@ -362,5 +423,5 @@ static struct platform_driver aspeed_adc_driver = {
 module_platform_driver(aspeed_adc_driver);
 
 MODULE_AUTHOR("Rick Altherr <ralth...@google.com>");
-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
+MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
 MODULE_LICENSE("GPL");
-- 
2.17.1

Reply via email to