summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch271
1 files changed, 271 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
new file mode 100644
index 000000000..63b683826
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
@@ -0,0 +1,271 @@
+From 14a4e77c801be8adbfc0726667a8051957e7a7dd Mon Sep 17 00:00:00 2001
+From: Chen Yugang <yugang.chen@linux.intel.com>
+Date: Tue, 3 Dec 2019 13:41:37 +0800
+Subject: [PATCH] ADC linux driver for AST2600
+
+Tested:
+it's tested with DC input.
+
+Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
+---
+ arch/arm/boot/dts/aspeed-g6.dtsi | 14 +++++-
+ drivers/iio/adc/aspeed_adc.c | 99 +++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 99 insertions(+), 14 deletions(-)
+
+diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
+index 34281b1..4e8d25f 100644
+--- a/arch/arm/boot/dts/aspeed-g6.dtsi
++++ b/arch/arm/boot/dts/aspeed-g6.dtsi
+@@ -320,12 +320,22 @@
+ interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+- adc: adc@1e6e9000 {
+- compatible = "aspeed,ast2500-adc";
++ adc0: adc@1e6e9000 {
++ compatible = "aspeed,ast2600-adc";
+ reg = <0x1e6e9000 0x100>;
+ clocks = <&syscon ASPEED_CLK_APB2>;
++ resets = <&syscon ASPEED_RESET_ADC>;
+ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
++ #io-channel-cells = <1>;
++ status = "disabled";
++ };
++
++ adc1: adc@1e6e9100 {
++ compatible = "aspeed,ast2600-adc";
++ reg = <0x1e6e9100 0x100>;
++ clocks = <&syscon ASPEED_CLK_APB2>;
+ resets = <&syscon ASPEED_RESET_ADC>;
++ interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+ #io-channel-cells = <1>;
+ status = "disabled";
+ };
+diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
+index d3fc39d..1dd5a97 100644
+--- a/drivers/iio/adc/aspeed_adc.c
++++ b/drivers/iio/adc/aspeed_adc.c
+@@ -1,8 +1,12 @@
+-// SPDX-License-Identifier: GPL-2.0-only
+ /*
+- * Aspeed AST2400/2500 ADC
++ * Aspeed AST2400/2500/2600 ADC
+ *
+ * Copyright (C) 2017 Google, Inc.
++ * Copyright (C) ASPEED Technology Inc.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms and conditions of the GNU General Public License,
++ * version 2, as published by the Free Software Foundation.
++ *
+ */
+
+ #include <linux/clk.h>
+@@ -30,6 +34,14 @@
+ #define ASPEED_REG_CLOCK_CONTROL 0x0C
+ #define ASPEED_REG_MAX 0xC0
+
++/* ast2600 */
++#define REF_VLOTAGE_2500mV 0
++#define REF_VLOTAGE_1200mV GENMASK(6, 6)
++#define REF_VLOTAGE_1550mV GENMASK(7, 7)
++#define REF_VLOTAGE_900mV GENMASK(7, 6)
++
++#define ASPEED_AUTOPENSATING BIT(5)
++
+ #define ASPEED_OPERATION_MODE_POWER_DOWN (0x0 << 1)
+ #define ASPEED_OPERATION_MODE_STANDBY (0x1 << 1)
+ #define ASPEED_OPERATION_MODE_NORMAL (0x7 << 1)
+@@ -45,8 +57,10 @@ struct aspeed_adc_model_data {
+ const char *model_name;
+ unsigned int min_sampling_rate; // Hz
+ unsigned int max_sampling_rate; // Hz
+- unsigned int vref_voltage; // mV
++ u32 vref_voltage; // mV
+ bool wait_init_sequence;
++ struct iio_chan_spec const *channels;
++ int num_channels;
+ };
+
+ struct aspeed_adc_data {
+@@ -56,6 +70,7 @@ struct aspeed_adc_data {
+ struct clk_hw *clk_prescaler;
+ struct clk_hw *clk_scaler;
+ struct reset_control *rst;
++ int cv;
+ };
+
+ #define ASPEED_CHAN(_idx, _data_reg_addr) { \
+@@ -87,6 +102,17 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
+ ASPEED_CHAN(15, 0x2E),
+ };
+
++static const struct iio_chan_spec ast2600_adc_iio_channels[] = {
++ ASPEED_CHAN(0, 0x10),
++ ASPEED_CHAN(1, 0x12),
++ ASPEED_CHAN(2, 0x14),
++ ASPEED_CHAN(3, 0x16),
++ ASPEED_CHAN(4, 0x18),
++ ASPEED_CHAN(5, 0x1A),
++ ASPEED_CHAN(6, 0x1C),
++ ASPEED_CHAN(7, 0x1E),
++};
++
+ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+@@ -175,7 +201,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ const struct aspeed_adc_model_data *model_data;
+ struct resource *res;
+ const char *clk_parent_name;
++ char prescaler_clk_name[32];
++ char scaler_clk_name[32];
+ int ret;
++ u32 eng_ctrl = 0;
+ u32 adc_engine_control_reg_val;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
+@@ -194,19 +223,21 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ 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);
+ data->clk_prescaler = clk_hw_register_divider(
+- &pdev->dev, "prescaler", clk_parent_name, 0,
++ &pdev->dev, prescaler_clk_name, 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);
+
++ snprintf(scaler_clk_name, sizeof(scaler_clk_name), "scaler-%s", pdev->name);
+ /*
+ * 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",
++ &pdev->dev, scaler_clk_name, prescaler_clk_name,
+ CLK_SET_RATE_PARENT,
+ data->base + ASPEED_REG_CLOCK_CONTROL,
+ 0, 10, 0, &data->clk_lock);
+@@ -215,7 +246,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ goto scaler_error;
+ }
+
+- 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");
+@@ -225,11 +256,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ reset_control_deassert(data->rst);
+
+ model_data = of_device_get_match_data(&pdev->dev);
++ if (!of_property_read_u32(pdev->dev.of_node, "ref_voltage", (u32 *)&model_data->vref_voltage)) {
++ if (model_data->vref_voltage == 2500)
++ eng_ctrl = REF_VLOTAGE_2500mV;
++ else if (model_data->vref_voltage == 1200)
++ eng_ctrl = REF_VLOTAGE_1200mV;
++ else if ((model_data->vref_voltage >= 1550) && (model_data->vref_voltage <= 2700))
++ eng_ctrl = REF_VLOTAGE_1550mV;
++ else if ((model_data->vref_voltage >= 900) && (model_data->vref_voltage <= 1650))
++ eng_ctrl = REF_VLOTAGE_900mV;
++ else {
++ printk("error ref voltage %d \n", model_data->vref_voltage);
++ eng_ctrl = 0;
++ }
++ } else
++ eng_ctrl = 0;
+
+ 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);
++ eng_ctrl |= ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
++ writel(eng_ctrl, data->base + ASPEED_REG_ENGINE_CONTROL);
+
+ /* Wait for initial sequence complete. */
+ ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
+@@ -242,12 +288,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ goto poll_timeout_error;
+ }
+
++ /* do compensating calculation use ch 0 */
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | BIT(16) |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++ mdelay(1);
++
++ data->cv = 0x200 - (readl(data->base + 0x10) & GENMASK(9, 0));
++
++ writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
++ ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
++ printk(KERN_INFO "aspeed_adc: cv %d \n", data->cv);
++
+ /* Start all channels in normal mode. */
+ ret = clk_prepare_enable(data->clk_scaler->clk);
+ if (ret)
+ goto clk_enable_error;
+
+- adc_engine_control_reg_val = GENMASK(31, 16) |
++ adc_engine_control_reg_val = eng_ctrl | GENMASK(31, 16) |
+ ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+ writel(adc_engine_control_reg_val,
+ data->base + ASPEED_REG_ENGINE_CONTROL);
+@@ -257,8 +317,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
+ 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->channels = model_data->channels;
++ indio_dev->num_channels = model_data->num_channels;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+@@ -301,6 +361,8 @@ static const struct aspeed_adc_model_data ast2400_model_data = {
+ .vref_voltage = 2500, // mV
+ .min_sampling_rate = 10000,
+ .max_sampling_rate = 500000,
++ .channels = aspeed_adc_iio_channels,
++ .num_channels = 16,
+ };
+
+ static const struct aspeed_adc_model_data ast2500_model_data = {
+@@ -309,11 +371,24 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
+ .min_sampling_rate = 1,
+ .max_sampling_rate = 1000000,
+ .wait_init_sequence = true,
++ .channels = aspeed_adc_iio_channels,
++ .num_channels = 16,
++};
++
++static const struct aspeed_adc_model_data ast2600_model_data = {
++ .model_name = "ast2500-adc",
++ .vref_voltage = 1800, /* mV --> can be 1.2v or 2.5 or ext 1.55~2.7v, 0.9v ~1.65v */
++ .min_sampling_rate = 1,
++ .max_sampling_rate = 1000000,
++ .wait_init_sequence = true,
++ .channels = ast2600_adc_iio_channels,
++ .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);
+@@ -330,5 +405,5 @@ static struct platform_driver aspeed_adc_driver = {
+ module_platform_driver(aspeed_adc_driver);
+
+ MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
+-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
++MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
+ MODULE_LICENSE("GPL");
+--
+2.7.4
+