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