uboot/drivers/adc/stm32-adc-core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2018, STMicroelectronics - All Rights Reserved
   4 * Author: Fabrice Gasnier <fabrice.gasnier@st.com>
   5 *
   6 * Originally based on the Linux kernel v4.18 drivers/iio/adc/stm32-adc-core.c.
   7 */
   8
   9#include <common.h>
  10#include <dm.h>
  11#include <asm/io.h>
  12#include <dm/device_compat.h>
  13#include <linux/bitops.h>
  14#include <power/regulator.h>
  15#include "stm32-adc-core.h"
  16
  17/* STM32H7 - common registers for all ADC instances */
  18#define STM32H7_ADC_CCR                 (STM32_ADCX_COMN_OFFSET + 0x08)
  19
  20/* STM32H7_ADC_CCR - bit fields */
  21#define STM32H7_PRESC_SHIFT             18
  22#define STM32H7_PRESC_MASK              GENMASK(21, 18)
  23#define STM32H7_CKMODE_SHIFT            16
  24#define STM32H7_CKMODE_MASK             GENMASK(17, 16)
  25
  26/* STM32 H7 maximum analog clock rate (from datasheet) */
  27#define STM32H7_ADC_MAX_CLK_RATE        36000000
  28
  29/**
  30 * struct stm32h7_adc_ck_spec - specification for stm32h7 adc clock
  31 * @ckmode: ADC clock mode, Async or sync with prescaler.
  32 * @presc: prescaler bitfield for async clock mode
  33 * @div: prescaler division ratio
  34 */
  35struct stm32h7_adc_ck_spec {
  36        u32 ckmode;
  37        u32 presc;
  38        int div;
  39};
  40
  41static const struct stm32h7_adc_ck_spec stm32h7_adc_ckmodes_spec[] = {
  42        /* 00: CK_ADC[1..3]: Asynchronous clock modes */
  43        { 0, 0, 1 },
  44        { 0, 1, 2 },
  45        { 0, 2, 4 },
  46        { 0, 3, 6 },
  47        { 0, 4, 8 },
  48        { 0, 5, 10 },
  49        { 0, 6, 12 },
  50        { 0, 7, 16 },
  51        { 0, 8, 32 },
  52        { 0, 9, 64 },
  53        { 0, 10, 128 },
  54        { 0, 11, 256 },
  55        /* HCLK used: Synchronous clock modes (1, 2 or 4 prescaler) */
  56        { 1, 0, 1 },
  57        { 2, 0, 2 },
  58        { 3, 0, 4 },
  59};
  60
  61static int stm32h7_adc_clk_sel(struct udevice *dev,
  62                               struct stm32_adc_common *common)
  63{
  64        u32 ckmode, presc;
  65        unsigned long rate;
  66        unsigned int i;
  67        int div;
  68
  69        /* stm32h7 bus clock is common for all ADC instances (mandatory) */
  70        if (!clk_valid(&common->bclk)) {
  71                dev_err(dev, "No bclk clock found\n");
  72                return -ENOENT;
  73        }
  74
  75        /*
  76         * stm32h7 can use either 'bus' or 'adc' clock for analog circuitry.
  77         * So, choice is to have bus clock mandatory and adc clock optional.
  78         * If optional 'adc' clock has been found, then try to use it first.
  79         */
  80        if (clk_valid(&common->aclk)) {
  81                /*
  82                 * Asynchronous clock modes (e.g. ckmode == 0)
  83                 * From spec: PLL output musn't exceed max rate
  84                 */
  85                rate = clk_get_rate(&common->aclk);
  86                if (!rate) {
  87                        dev_err(dev, "Invalid aclk rate: 0\n");
  88                        return -EINVAL;
  89                }
  90
  91                for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
  92                        ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
  93                        presc = stm32h7_adc_ckmodes_spec[i].presc;
  94                        div = stm32h7_adc_ckmodes_spec[i].div;
  95
  96                        if (ckmode)
  97                                continue;
  98
  99                        if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
 100                                goto out;
 101                }
 102        }
 103
 104        /* Synchronous clock modes (e.g. ckmode is 1, 2 or 3) */
 105        rate = clk_get_rate(&common->bclk);
 106        if (!rate) {
 107                dev_err(dev, "Invalid bus clock rate: 0\n");
 108                return -EINVAL;
 109        }
 110
 111        for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
 112                ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
 113                presc = stm32h7_adc_ckmodes_spec[i].presc;
 114                div = stm32h7_adc_ckmodes_spec[i].div;
 115
 116                if (!ckmode)
 117                        continue;
 118
 119                if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE)
 120                        goto out;
 121        }
 122
 123        dev_err(dev, "clk selection failed\n");
 124        return -EINVAL;
 125
 126out:
 127        /* rate used later by each ADC instance to control BOOST mode */
 128        common->rate = rate / div;
 129
 130        /* Set common clock mode and prescaler */
 131        clrsetbits_le32(common->base + STM32H7_ADC_CCR,
 132                        STM32H7_CKMODE_MASK | STM32H7_PRESC_MASK,
 133                        ckmode << STM32H7_CKMODE_SHIFT |
 134                        presc << STM32H7_PRESC_SHIFT);
 135
 136        dev_dbg(dev, "Using %s clock/%d source at %ld kHz\n",
 137                ckmode ? "bus" : "adc", div, common->rate / 1000);
 138
 139        return 0;
 140}
 141
 142static int stm32_adc_core_probe(struct udevice *dev)
 143{
 144        struct stm32_adc_common *common = dev_get_priv(dev);
 145        int ret;
 146
 147        common->base = dev_read_addr_ptr(dev);
 148        if (!common->base) {
 149                dev_err(dev, "can't get address\n");
 150                return -ENOENT;
 151        }
 152
 153        ret = device_get_supply_regulator(dev, "vref-supply", &common->vref);
 154        if (ret) {
 155                dev_err(dev, "can't get vref-supply: %d\n", ret);
 156                return ret;
 157        }
 158
 159        ret = regulator_get_value(common->vref);
 160        if (ret < 0) {
 161                dev_err(dev, "can't get vref-supply value: %d\n", ret);
 162                return ret;
 163        }
 164        common->vref_uv = ret;
 165
 166        ret = clk_get_by_name(dev, "adc", &common->aclk);
 167        if (!ret) {
 168                ret = clk_enable(&common->aclk);
 169                if (ret) {
 170                        dev_err(dev, "Can't enable aclk: %d\n", ret);
 171                        return ret;
 172                }
 173        }
 174
 175        ret = clk_get_by_name(dev, "bus", &common->bclk);
 176        if (!ret) {
 177                ret = clk_enable(&common->bclk);
 178                if (ret) {
 179                        dev_err(dev, "Can't enable bclk: %d\n", ret);
 180                        goto err_aclk_disable;
 181                }
 182        }
 183
 184        ret = stm32h7_adc_clk_sel(dev, common);
 185        if (ret)
 186                goto err_bclk_disable;
 187
 188        return ret;
 189
 190err_bclk_disable:
 191        if (clk_valid(&common->bclk))
 192                clk_disable(&common->bclk);
 193
 194err_aclk_disable:
 195        if (clk_valid(&common->aclk))
 196                clk_disable(&common->aclk);
 197
 198        return ret;
 199}
 200
 201static const struct udevice_id stm32_adc_core_ids[] = {
 202        { .compatible = "st,stm32h7-adc-core" },
 203        { .compatible = "st,stm32mp1-adc-core" },
 204        {}
 205};
 206
 207U_BOOT_DRIVER(stm32_adc_core) = {
 208        .name  = "stm32-adc-core",
 209        .id = UCLASS_SIMPLE_BUS,
 210        .of_match = stm32_adc_core_ids,
 211        .probe = stm32_adc_core_probe,
 212        .priv_auto_alloc_size = sizeof(struct stm32_adc_common),
 213};
 214