Merge branch 'master' of git://git.denx.de/u-boot
[platform/kernel/u-boot.git] / drivers / adc / exynos-adc.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2015 Samsung Electronics
4  * Przemyslaw Marczak <p.marczak@samsung.com>
5  */
6 #include <common.h>
7 #include <errno.h>
8 #include <dm.h>
9 #include <adc.h>
10 #include <asm/arch/adc.h>
11
12 struct exynos_adc_priv {
13         int active_channel;
14         struct exynos_adc_v2 *regs;
15 };
16
17 int exynos_adc_channel_data(struct udevice *dev, int channel,
18                             unsigned int *data)
19 {
20         struct exynos_adc_priv *priv = dev_get_priv(dev);
21         struct exynos_adc_v2 *regs = priv->regs;
22
23         if (channel != priv->active_channel) {
24                 pr_err("Requested channel is not active!");
25                 return -EINVAL;
26         }
27
28         if (ADC_V2_GET_STATUS_FLAG(readl(&regs->status)) != FLAG_CONV_END)
29                 return -EBUSY;
30
31         *data = readl(&regs->dat) & ADC_V2_DAT_MASK;
32
33         return 0;
34 }
35
36 int exynos_adc_start_channel(struct udevice *dev, int channel)
37 {
38         struct exynos_adc_priv *priv = dev_get_priv(dev);
39         struct exynos_adc_v2 *regs = priv->regs;
40         unsigned int cfg;
41
42         /* Choose channel */
43         cfg = readl(&regs->con2);
44         cfg &= ~ADC_V2_CON2_CHAN_SEL_MASK;
45         cfg |= ADC_V2_CON2_CHAN_SEL(channel);
46         writel(cfg, &regs->con2);
47
48         /* Start conversion */
49         cfg = readl(&regs->con1);
50         writel(cfg | ADC_V2_CON1_STC_EN, &regs->con1);
51
52         priv->active_channel = channel;
53
54         return 0;
55 }
56
57 int exynos_adc_stop(struct udevice *dev)
58 {
59         struct exynos_adc_priv *priv = dev_get_priv(dev);
60         struct exynos_adc_v2 *regs = priv->regs;
61         unsigned int cfg;
62
63         /* Stop conversion */
64         cfg = readl(&regs->con1);
65         cfg &= ~ADC_V2_CON1_STC_EN;
66
67         writel(cfg, &regs->con1);
68
69         priv->active_channel = -1;
70
71         return 0;
72 }
73
74 int exynos_adc_probe(struct udevice *dev)
75 {
76         struct exynos_adc_priv *priv = dev_get_priv(dev);
77         struct exynos_adc_v2 *regs = priv->regs;
78         unsigned int cfg;
79
80         /* Check HW version */
81         if (readl(&regs->version) != ADC_V2_VERSION) {
82                 pr_err("This driver supports only ADC v2!");
83                 return -ENXIO;
84         }
85
86         /* ADC Reset */
87         writel(ADC_V2_CON1_SOFT_RESET, &regs->con1);
88
89         /* Disable INT - will read status only */
90         writel(0x0, &regs->int_en);
91
92         /* CON2 - set conversion parameters */
93         cfg = ADC_V2_CON2_C_TIME(3); /* Conversion times: (1 << 3) = 8 */
94         cfg |= ADC_V2_CON2_OSEL(OSEL_BINARY);
95         cfg |= ADC_V2_CON2_ESEL(ESEL_ADC_EVAL_TIME_20CLK);
96         cfg |= ADC_V2_CON2_HIGHF(HIGHF_CONV_RATE_600KSPS);
97         writel(cfg, &regs->con2);
98
99         priv->active_channel = -1;
100
101         return 0;
102 }
103
104 int exynos_adc_ofdata_to_platdata(struct udevice *dev)
105 {
106         struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev);
107         struct exynos_adc_priv *priv = dev_get_priv(dev);
108
109         priv->regs = (struct exynos_adc_v2 *)devfdt_get_addr(dev);
110         if (priv->regs == (struct exynos_adc_v2 *)FDT_ADDR_T_NONE) {
111                 pr_err("Dev: %s - can't get address!", dev->name);
112                 return -ENODATA;
113         }
114
115         uc_pdata->data_mask = ADC_V2_DAT_MASK;
116         uc_pdata->data_format = ADC_DATA_FORMAT_BIN;
117         uc_pdata->data_timeout_us = ADC_V2_CONV_TIMEOUT_US;
118
119         /* Mask available channel bits: [0:9] */
120         uc_pdata->channel_mask = (2 << ADC_V2_MAX_CHANNEL) - 1;
121
122         return 0;
123 }
124
125 static const struct adc_ops exynos_adc_ops = {
126         .start_channel = exynos_adc_start_channel,
127         .channel_data = exynos_adc_channel_data,
128         .stop = exynos_adc_stop,
129 };
130
131 static const struct udevice_id exynos_adc_ids[] = {
132         { .compatible = "samsung,exynos-adc-v2" },
133         { }
134 };
135
136 U_BOOT_DRIVER(exynos_adc) = {
137         .name           = "exynos-adc",
138         .id             = UCLASS_ADC,
139         .of_match       = exynos_adc_ids,
140         .ops            = &exynos_adc_ops,
141         .probe          = exynos_adc_probe,
142         .ofdata_to_platdata = exynos_adc_ofdata_to_platdata,
143         .priv_auto_alloc_size = sizeof(struct exynos_adc_priv),
144 };