iio: adc: aspeed: Fix the calculate error of clock.
authorBilly Tsai <billy_tsai@aspeedtech.com>
Wed, 22 Sep 2021 08:15:16 +0000 (16:15 +0800)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Tue, 19 Oct 2021 07:27:32 +0000 (08:27 +0100)
The ADC clock formula is
ast2400/2500:
ADC clock period = PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
ast2600:
ADC clock period = PCLK * 2 * (ADC0C[15:0] + 1)
They all have one fixed divided 2 and the legacy driver didn't handle it.
This patch register the fixed factory clock device as the parent of ADC
clock scaler to fix this issue.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Link: https://lore.kernel.org/r/20210922081520.30580-8-billy_tsai@aspeedtech.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/aspeed_adc.c

index 846fead557dc9b18665e7cedbf50df1adff6a253..da530c420211bc368ac73eb6a07d46b5560f0e60 100644 (file)
@@ -4,6 +4,12 @@
  *
  * Copyright (C) 2017 Google, Inc.
  * Copyright (C) 2021 Aspeed Technology Inc.
+ *
+ * ADC clock formula:
+ * Ast2400/Ast2500:
+ * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
+ * Ast2600:
+ * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1)
  */
 
 #include <linux/clk.h>
@@ -85,6 +91,7 @@ struct aspeed_adc_data {
        struct regulator        *regulator;
        void __iomem            *base;
        spinlock_t              clk_lock;
+       struct clk_hw           *fixed_div_clk;
        struct clk_hw           *clk_prescaler;
        struct clk_hw           *clk_scaler;
        struct reset_control    *rst;
@@ -197,6 +204,13 @@ static const struct iio_info aspeed_adc_iio_info = {
        .debugfs_reg_access = aspeed_adc_reg_access,
 };
 
+static void aspeed_adc_unregister_fixed_divider(void *data)
+{
+       struct clk_hw *clk = data;
+
+       clk_hw_unregister_fixed_factor(clk);
+}
+
 static void aspeed_adc_reset_assert(void *data)
 {
        struct reset_control *rst = data;
@@ -320,6 +334,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
        spin_lock_init(&data->clk_lock);
        snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s",
                 of_clk_get_parent_name(pdev->dev.of_node, 0));
+       snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div",
+                data->model_data->model_name);
+       data->fixed_div_clk = clk_hw_register_fixed_factor(
+               &pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
+       if (IS_ERR(data->fixed_div_clk))
+               return PTR_ERR(data->fixed_div_clk);
+
+       ret = devm_add_action_or_reset(data->dev,
+                                      aspeed_adc_unregister_fixed_divider,
+                                      data->fixed_div_clk);
+       if (ret)
+               return ret;
+       snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), clk_name);
 
        if (data->model_data->need_prescaler) {
                snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler",