uboot/drivers/adc/stm32-adc.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.c.
   7 */
   8
   9#include <common.h>
  10#include <adc.h>
  11#include <dm.h>
  12#include <asm/io.h>
  13#include <dm/device_compat.h>
  14#include <linux/bitops.h>
  15#include <linux/delay.h>
  16#include <linux/iopoll.h>
  17#include "stm32-adc-core.h"
  18
  19/* STM32H7 - Registers for each ADC instance */
  20#define STM32H7_ADC_ISR                 0x00
  21#define STM32H7_ADC_CR                  0x08
  22#define STM32H7_ADC_CFGR                0x0C
  23#define STM32H7_ADC_SMPR1               0x14
  24#define STM32H7_ADC_SMPR2               0x18
  25#define STM32H7_ADC_PCSEL               0x1C
  26#define STM32H7_ADC_SQR1                0x30
  27#define STM32H7_ADC_DR                  0x40
  28#define STM32H7_ADC_DIFSEL              0xC0
  29
  30/* STM32H7_ADC_ISR - bit fields */
  31#define STM32MP1_VREGREADY              BIT(12)
  32#define STM32H7_EOC                     BIT(2)
  33#define STM32H7_ADRDY                   BIT(0)
  34
  35/* STM32H7_ADC_CR - bit fields */
  36#define STM32H7_DEEPPWD                 BIT(29)
  37#define STM32H7_ADVREGEN                BIT(28)
  38#define STM32H7_BOOST                   BIT(8)
  39#define STM32H7_ADSTART                 BIT(2)
  40#define STM32H7_ADDIS                   BIT(1)
  41#define STM32H7_ADEN                    BIT(0)
  42
  43/* STM32H7_ADC_CFGR bit fields */
  44#define STM32H7_EXTEN                   GENMASK(11, 10)
  45#define STM32H7_DMNGT                   GENMASK(1, 0)
  46
  47/* STM32H7_ADC_SQR1 - bit fields */
  48#define STM32H7_SQ1_SHIFT               6
  49
  50/* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */
  51#define STM32H7_BOOST_CLKRATE           20000000UL
  52
  53#define STM32_ADC_CH_MAX                20      /* max number of channels */
  54#define STM32_ADC_TIMEOUT_US            100000
  55
  56struct stm32_adc_cfg {
  57        unsigned int max_channels;
  58        unsigned int num_bits;
  59        bool has_vregready;
  60};
  61
  62struct stm32_adc {
  63        void __iomem *regs;
  64        int active_channel;
  65        const struct stm32_adc_cfg *cfg;
  66};
  67
  68static int stm32_adc_stop(struct udevice *dev)
  69{
  70        struct stm32_adc *adc = dev_get_priv(dev);
  71
  72        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADDIS);
  73        clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
  74        /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */
  75        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
  76        adc->active_channel = -1;
  77
  78        return 0;
  79}
  80
  81static int stm32_adc_start_channel(struct udevice *dev, int channel)
  82{
  83        struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
  84        struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
  85        struct stm32_adc *adc = dev_get_priv(dev);
  86        int ret;
  87        u32 val;
  88
  89        /* Exit deep power down, then enable ADC voltage regulator */
  90        clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD);
  91        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN);
  92        if (common->rate > STM32H7_BOOST_CLKRATE)
  93                setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST);
  94
  95        /* Wait for startup time */
  96        if (!adc->cfg->has_vregready) {
  97                udelay(20);
  98        } else {
  99                ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
 100                                         val & STM32MP1_VREGREADY,
 101                                         STM32_ADC_TIMEOUT_US);
 102                if (ret < 0) {
 103                        stm32_adc_stop(dev);
 104                        dev_err(dev, "Failed to enable vreg: %d\n", ret);
 105                        return ret;
 106                }
 107        }
 108
 109        /* Only use single ended channels */
 110        writel(0, adc->regs + STM32H7_ADC_DIFSEL);
 111
 112        /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */
 113        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN);
 114        ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
 115                                 val & STM32H7_ADRDY, STM32_ADC_TIMEOUT_US);
 116        if (ret < 0) {
 117                stm32_adc_stop(dev);
 118                dev_err(dev, "Failed to enable ADC: %d\n", ret);
 119                return ret;
 120        }
 121
 122        /* Preselect channels */
 123        writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL);
 124
 125        /* Set sampling time to max value by default */
 126        writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1);
 127        writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR2);
 128
 129        /* Program regular sequence: chan in SQ1 & len = 0 for one channel */
 130        writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1);
 131
 132        /* Trigger detection disabled (conversion can be launched in SW) */
 133        clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN |
 134                     STM32H7_DMNGT);
 135        adc->active_channel = channel;
 136
 137        return 0;
 138}
 139
 140static int stm32_adc_channel_data(struct udevice *dev, int channel,
 141                                  unsigned int *data)
 142{
 143        struct stm32_adc *adc = dev_get_priv(dev);
 144        int ret;
 145        u32 val;
 146
 147        if (channel != adc->active_channel) {
 148                dev_err(dev, "Requested channel is not active!\n");
 149                return -EINVAL;
 150        }
 151
 152        setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADSTART);
 153        ret = readl_poll_timeout(adc->regs + STM32H7_ADC_ISR, val,
 154                                 val & STM32H7_EOC, STM32_ADC_TIMEOUT_US);
 155        if (ret < 0) {
 156                dev_err(dev, "conversion timed out: %d\n", ret);
 157                return ret;
 158        }
 159
 160        *data = readl(adc->regs + STM32H7_ADC_DR);
 161
 162        return 0;
 163}
 164
 165static int stm32_adc_chan_of_init(struct udevice *dev)
 166{
 167        struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
 168        struct stm32_adc *adc = dev_get_priv(dev);
 169        u32 chans[STM32_ADC_CH_MAX];
 170        unsigned int i, num_channels;
 171        int ret;
 172
 173        /* Retrieve single ended channels listed in device tree */
 174        ret = dev_read_size(dev, "st,adc-channels");
 175        if (ret < 0) {
 176                dev_err(dev, "can't get st,adc-channels: %d\n", ret);
 177                return ret;
 178        }
 179        num_channels = ret / sizeof(u32);
 180
 181        if (num_channels > adc->cfg->max_channels) {
 182                dev_err(dev, "too many st,adc-channels: %d\n", num_channels);
 183                return -EINVAL;
 184        }
 185
 186        ret = dev_read_u32_array(dev, "st,adc-channels", chans, num_channels);
 187        if (ret < 0) {
 188                dev_err(dev, "can't read st,adc-channels: %d\n", ret);
 189                return ret;
 190        }
 191
 192        for (i = 0; i < num_channels; i++) {
 193                if (chans[i] >= adc->cfg->max_channels) {
 194                        dev_err(dev, "bad channel %u\n", chans[i]);
 195                        return -EINVAL;
 196                }
 197                uc_pdata->channel_mask |= 1 << chans[i];
 198        }
 199
 200        uc_pdata->data_mask = (1 << adc->cfg->num_bits) - 1;
 201        uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
 202        uc_pdata->data_timeout_us = 100000;
 203
 204        return 0;
 205}
 206
 207static int stm32_adc_probe(struct udevice *dev)
 208{
 209        struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev);
 210        struct stm32_adc_common *common = dev_get_priv(dev_get_parent(dev));
 211        struct stm32_adc *adc = dev_get_priv(dev);
 212        int offset;
 213
 214        offset = dev_read_u32_default(dev, "reg", -ENODATA);
 215        if (offset < 0) {
 216                dev_err(dev, "Can't read reg property\n");
 217                return offset;
 218        }
 219        adc->regs = common->base + offset;
 220        adc->cfg = (const struct stm32_adc_cfg *)dev_get_driver_data(dev);
 221
 222        /* VDD supplied by common vref pin */
 223        uc_pdata->vdd_supply = common->vref;
 224        uc_pdata->vdd_microvolts = common->vref_uv;
 225        uc_pdata->vss_microvolts = 0;
 226
 227        return stm32_adc_chan_of_init(dev);
 228}
 229
 230static const struct adc_ops stm32_adc_ops = {
 231        .start_channel = stm32_adc_start_channel,
 232        .channel_data = stm32_adc_channel_data,
 233        .stop = stm32_adc_stop,
 234};
 235
 236static const struct stm32_adc_cfg stm32h7_adc_cfg = {
 237        .num_bits = 16,
 238        .max_channels = STM32_ADC_CH_MAX,
 239};
 240
 241static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
 242        .num_bits = 16,
 243        .max_channels = STM32_ADC_CH_MAX,
 244        .has_vregready = true,
 245};
 246
 247static const struct udevice_id stm32_adc_ids[] = {
 248        { .compatible = "st,stm32h7-adc",
 249          .data = (ulong)&stm32h7_adc_cfg },
 250        { .compatible = "st,stm32mp1-adc",
 251          .data = (ulong)&stm32mp1_adc_cfg },
 252        {}
 253};
 254
 255U_BOOT_DRIVER(stm32_adc) = {
 256        .name  = "stm32-adc",
 257        .id = UCLASS_ADC,
 258        .of_match = stm32_adc_ids,
 259        .probe = stm32_adc_probe,
 260        .ops = &stm32_adc_ops,
 261        .priv_auto      = sizeof(struct stm32_adc),
 262};
 263