]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
08d6300a PM |
2 | /* |
3 | * Copyright (C) 2015 Samsung Electronics | |
4 | * Przemyslaw Marczak <[email protected]> | |
08d6300a | 5 | */ |
d678a59d | 6 | #include <common.h> |
08d6300a PM |
7 | #include <errno.h> |
8 | #include <dm.h> | |
9 | #include <adc.h> | |
10 | #include <sandbox-adc.h> | |
1e94b46f | 11 | #include <linux/printk.h> |
08d6300a PM |
12 | |
13 | /** | |
14 | * struct sandbox_adc_priv - sandbox ADC device's operation status and data | |
15 | * | |
16 | * @conversion_status - conversion status: ACTIVE (started) / INACTIVE (stopped) | |
17 | * @conversion_mode - conversion mode: single or multi-channel | |
18 | * @active_channel - active channel number, valid for single channel mode | |
19 | * data[] - channels data | |
20 | */ | |
21 | struct sandbox_adc_priv { | |
22 | int conversion_status; | |
23 | int conversion_mode; | |
24 | int active_channel_mask; | |
25 | unsigned int data[4]; | |
26 | }; | |
27 | ||
28 | int sandbox_adc_start_channel(struct udevice *dev, int channel) | |
29 | { | |
30 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
31 | ||
32 | /* Set single-channel mode */ | |
33 | priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL; | |
34 | /* Select channel */ | |
35 | priv->active_channel_mask = 1 << channel; | |
36 | /* Start conversion */ | |
37 | priv->conversion_status = SANDBOX_ADC_ACTIVE; | |
38 | ||
39 | return 0; | |
40 | } | |
41 | ||
42 | int sandbox_adc_start_channels(struct udevice *dev, unsigned int channel_mask) | |
43 | { | |
44 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
45 | ||
46 | /* Set single-channel mode */ | |
47 | priv->conversion_mode = SANDBOX_ADC_MODE_MULTI_CHANNEL; | |
48 | /* Select channel */ | |
49 | priv->active_channel_mask = channel_mask; | |
50 | /* Start conversion */ | |
51 | priv->conversion_status = SANDBOX_ADC_ACTIVE; | |
52 | ||
53 | return 0; | |
54 | } | |
55 | ||
56 | int sandbox_adc_channel_data(struct udevice *dev, int channel, | |
57 | unsigned int *data) | |
58 | { | |
59 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
60 | ||
61 | /* For single-channel conversion mode, check if channel was selected */ | |
62 | if ((priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) && | |
63 | !(priv->active_channel_mask & (1 << channel))) { | |
9b643e31 | 64 | pr_err("Request for an inactive channel!"); |
08d6300a PM |
65 | return -EINVAL; |
66 | } | |
67 | ||
68 | /* The conversion must be started before reading the data */ | |
69 | if (priv->conversion_status == SANDBOX_ADC_INACTIVE) | |
70 | return -EIO; | |
71 | ||
72 | *data = priv->data[channel]; | |
73 | ||
74 | return 0; | |
75 | } | |
76 | ||
77 | int sandbox_adc_channels_data(struct udevice *dev, unsigned int channel_mask, | |
78 | struct adc_channel *channels) | |
79 | { | |
80 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
81 | int i; | |
82 | ||
83 | /* Return error for single-channel conversion mode */ | |
84 | if (priv->conversion_mode == SANDBOX_ADC_MODE_SINGLE_CHANNEL) { | |
9b643e31 | 85 | pr_err("ADC in single-channel mode!"); |
08d6300a PM |
86 | return -EPERM; |
87 | } | |
88 | /* Check channel selection */ | |
89 | if (!(priv->active_channel_mask & channel_mask)) { | |
9b643e31 | 90 | pr_err("Request for an inactive channel!"); |
08d6300a PM |
91 | return -EINVAL; |
92 | } | |
93 | /* The conversion must be started before reading the data */ | |
94 | if (priv->conversion_status == SANDBOX_ADC_INACTIVE) | |
95 | return -EIO; | |
96 | ||
97 | for (i = 0; i < SANDBOX_ADC_CHANNELS; i++) { | |
98 | if (!((channel_mask >> i) & 0x1)) | |
99 | continue; | |
100 | ||
101 | channels->data = priv->data[i]; | |
102 | channels->id = i; | |
103 | channels++; | |
104 | } | |
105 | ||
106 | return 0; | |
107 | } | |
108 | ||
109 | int sandbox_adc_stop(struct udevice *dev) | |
110 | { | |
111 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
112 | ||
113 | /* Start conversion */ | |
114 | priv->conversion_status = SANDBOX_ADC_INACTIVE; | |
115 | ||
116 | return 0; | |
117 | } | |
118 | ||
119 | int sandbox_adc_probe(struct udevice *dev) | |
120 | { | |
121 | struct sandbox_adc_priv *priv = dev_get_priv(dev); | |
122 | ||
123 | /* Stop conversion */ | |
124 | priv->conversion_status = SANDBOX_ADC_INACTIVE; | |
125 | /* Set single-channel mode */ | |
126 | priv->conversion_mode = SANDBOX_ADC_MODE_SINGLE_CHANNEL; | |
127 | /* Deselect all channels */ | |
128 | priv->active_channel_mask = 0; | |
129 | ||
130 | /* Set sandbox test data */ | |
131 | priv->data[0] = SANDBOX_ADC_CHANNEL0_DATA; | |
132 | priv->data[1] = SANDBOX_ADC_CHANNEL1_DATA; | |
133 | priv->data[2] = SANDBOX_ADC_CHANNEL2_DATA; | |
134 | priv->data[3] = SANDBOX_ADC_CHANNEL3_DATA; | |
135 | ||
136 | return 0; | |
137 | } | |
138 | ||
d1998a9f | 139 | int sandbox_adc_of_to_plat(struct udevice *dev) |
08d6300a | 140 | { |
caa4daa2 | 141 | struct adc_uclass_plat *uc_pdata = dev_get_uclass_plat(dev); |
08d6300a PM |
142 | |
143 | uc_pdata->data_mask = SANDBOX_ADC_DATA_MASK; | |
144 | uc_pdata->data_format = ADC_DATA_FORMAT_BIN; | |
145 | uc_pdata->data_timeout_us = 0; | |
146 | ||
147 | /* Mask available channel bits: [0:3] */ | |
148 | uc_pdata->channel_mask = (1 << SANDBOX_ADC_CHANNELS) - 1; | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | static const struct adc_ops sandbox_adc_ops = { | |
154 | .start_channel = sandbox_adc_start_channel, | |
155 | .start_channels = sandbox_adc_start_channels, | |
156 | .channel_data = sandbox_adc_channel_data, | |
157 | .channels_data = sandbox_adc_channels_data, | |
158 | .stop = sandbox_adc_stop, | |
159 | }; | |
160 | ||
161 | static const struct udevice_id sandbox_adc_ids[] = { | |
162 | { .compatible = "sandbox,adc" }, | |
163 | { } | |
164 | }; | |
165 | ||
166 | U_BOOT_DRIVER(sandbox_adc) = { | |
167 | .name = "sandbox-adc", | |
168 | .id = UCLASS_ADC, | |
169 | .of_match = sandbox_adc_ids, | |
170 | .ops = &sandbox_adc_ops, | |
171 | .probe = sandbox_adc_probe, | |
d1998a9f | 172 | .of_to_plat = sandbox_adc_of_to_plat, |
41575d8e | 173 | .priv_auto = sizeof(struct sandbox_adc_priv), |
08d6300a | 174 | }; |