diff options
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.patch | 271 |
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..8f1e14b86 --- /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 8ed59cc252af9a87d2d7b3e45a949030d91761b7 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 + |