block_am335x_adc.c 9.34 KB
Newer Older
Jeroen Vreeken's avatar
Jeroen Vreeken committed
1
/*
2
	Copyright Jeroen Vreeken (jeroen@vreeken.net), 2014, 2015
Jeroen Vreeken's avatar
Jeroen Vreeken committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

Jeroen Vreeken's avatar
Jeroen Vreeken committed
19
#include "am335x.h"
Jeroen Vreeken's avatar
Jeroen Vreeken committed
20

Jeroen Vreeken's avatar
Jeroen Vreeken committed
21
#include <controller/controller_block.h>
22
#include <controller/controller_time.h>
Jeroen Vreeken's avatar
Jeroen Vreeken committed
23
24
#include <log/log.h>

Jeroen Vreeken's avatar
Jeroen Vreeken committed
25
26

struct controller_block_private {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
27
28
29
30
31
32
	float ain[8];

	float gain[8];
	float offset[8];
	
	void *base;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
33
34
35
36
};

static void adc_calculate(struct controller_block *adc)
{
Jeroen Vreeken's avatar
Jeroen Vreeken committed
37
38
39
40
41
42
	struct controller_block_private *priv = adc->private;
	void *base = priv->base;
	uint32_t data;
	uint32_t count;
	
	do {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
43
		count = am335x_read32(base, AM335X_ADC_REG_FIFO0COUNT);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
44
45
46
47
48
	} while (count != 8);
	
	for (; count; count--) {
		int id;
		
Jeroen Vreeken's avatar
Jeroen Vreeken committed
49
		data = am335x_read32(base, AM335X_ADC_REG_FIFO0DATA);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
50
51
52
53
54
55
56
		id = AM335X_ADC_FIFODATA_ID_GET(data);
		
		priv->ain[id] = 
		    AM335X_ADC_FIFODATA_DATA_GET(data) * priv->gain[id] +
		    priv->offset[id];
	}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
57
	am335x_write32(base, AM335X_ADC_REG_STEPENABLE, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
58
59
60
61
	    AM335X_ADC_STEPENABLE_STEP1 | AM335X_ADC_STEPENABLE_STEP2 |
	    AM335X_ADC_STEPENABLE_STEP3 | AM335X_ADC_STEPENABLE_STEP4 |
	    AM335X_ADC_STEPENABLE_STEP5 | AM335X_ADC_STEPENABLE_STEP6 |
	    AM335X_ADC_STEPENABLE_STEP7 | AM335X_ADC_STEPENABLE_STEP8 );
Jeroen Vreeken's avatar
Jeroen Vreeken committed
62
63
64
}

static struct controller_block_outterm_list outterms[] = {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
65
66
67
68
69
70
71
72
	{ "ain0", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[0]) },
	{ "ain1", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[1]) },
	{ "ain2", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[2]) },
	{ "ain3", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[3]) },
	{ "ain4", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[4]) },
	{ "ain5", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[5]) },
	{ "ain6", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[6]) },
	{ "ain7", CONTROLLER_BLOCK_TERM_FLOAT, offsetof(struct controller_block_private, ain[7]) },
Jeroen Vreeken's avatar
Jeroen Vreeken committed
73
74
75
	{ NULL }
};

76
77
78
79
80
81
82
static int param_set_gain(struct controller_block *adc, char *param, int argc,
    va_list val)
{
	adc->private->gain[param[4]-'0'] = va_arg(val, double) * AM335X_ADC_FACTOR;
	return 0;
}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
83
static int param_set_offset(struct controller_block *adc, char *param, int argc,
84
85
86
87
88
89
    va_list val)
{
	adc->private->offset[param[6]-'0'] = va_arg(val, double);
	return 0;
}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
90
static struct controller_block_param_list params[] = {
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
	{ "gain0", false, param_set_gain, .args = { "double", NULL } },
	{ "gain1", false, param_set_gain, .args = { "double", NULL } },
	{ "gain2", false, param_set_gain, .args = { "double", NULL } },
	{ "gain3", false, param_set_gain, .args = { "double", NULL } },
	{ "gain4", false, param_set_gain, .args = { "double", NULL } },
	{ "gain5", false, param_set_gain, .args = { "double", NULL } },
	{ "gain6", false, param_set_gain, .args = { "double", NULL } },
	{ "gain7", false, param_set_gain, .args = { "double", NULL } },
	{ "offset0", false, param_set_offset, .args = { "double", NULL } },
	{ "offset1", false, param_set_offset, .args = { "double", NULL } },
	{ "offset2", false, param_set_offset, .args = { "double", NULL } },
	{ "offset3", false, param_set_offset, .args = { "double", NULL } },
	{ "offset4", false, param_set_offset, .args = { "double", NULL } },
	{ "offset5", false, param_set_offset, .args = { "double", NULL } },
	{ "offset6", false, param_set_offset, .args = { "double", NULL } },
	{ "offset7", false, param_set_offset, .args = { "double", NULL } },
Jeroen Vreeken's avatar
Jeroen Vreeken committed
107
108
109
110
	{ NULL },
};


Jeroen Vreeken's avatar
Jeroen Vreeken committed
111
static struct controller_block * block_am335x_adc_create(char *name, int argc, va_list val)
Jeroen Vreeken's avatar
Jeroen Vreeken committed
112
113
{
	struct controller_block *adc;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
114
115
	void *base;
	uint32_t reg;
116
117
118
	double frequency;
	int factor;
	uint32_t avg;
119
120
121
122
123
124

	if (am335x_cm_enable(AM335X_CM_WKUP_ADC_TSC_CLKCTRL)) {
		log_send(LOG_T_ERROR, "%s: Enabling module failed", name);
		return NULL;
	}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
125
	base = am335x_mem(AM335X_ADC_BASE, AM335X_ADC_SIZE);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
126
	if (!base) {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
127
		log_send(LOG_T_ERROR, "%s: Mapping ADC failed", name);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
128
129
130
131
		return NULL;
	}
	log_send(LOG_T_DEBUG, "%s: ADC mapped @ %p", name, base);
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
132
	reg = am335x_read32(base, AM335X_ADC_REG_REVISION);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
133
134
135
136
137
138
139
140
141
142
	log_send(LOG_T_DEBUG, 
	    "%s: REVISION: 0x%" PRIx32 ": func: 0x%03x rev: %d.%d",
	    name, reg, AM335X_ADC_REVISION_FUNC_GET(reg),
	    AM335X_ADC_REVISION_X_MAJOR_GET(reg),
	    AM335X_ADC_REVISION_Y_MINOR_GET(reg));
	if (AM335X_ADC_REVISION_FUNC_GET(reg) != AM335X_ADC_REVISION_FUNC) {
		log_send(LOG_T_ERROR, "Unexpected functional number");
		goto err_rev;
	}

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
	if (!(adc = controller_block_alloc("am355x_adc", name, sizeof(struct controller_block_private))))
		goto err_alloc;

	if (controller_block_outterm_list_init(adc, outterms))
		goto err_outterm;

	adc->private->base = base;

	adc->private->gain[0] = AM335X_ADC_FACTOR;
	adc->private->gain[1] = AM335X_ADC_FACTOR;
	adc->private->gain[2] = AM335X_ADC_FACTOR;
	adc->private->gain[3] = AM335X_ADC_FACTOR;
	adc->private->gain[4] = AM335X_ADC_FACTOR;
	adc->private->gain[5] = AM335X_ADC_FACTOR;
	adc->private->gain[6] = AM335X_ADC_FACTOR;
	adc->private->gain[7] = AM335X_ADC_FACTOR;

	adc->calculate = adc_calculate;

	if (controller_block_param_list_add(adc, params))
		goto err_param;

	if (controller_block_add(adc))
		goto err_add;
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
168
	am335x_write32(base, AM335X_ADC_REG_CTRL, AM335X_ADC_CTRL_SC_WP_N);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
169

Jeroen Vreeken's avatar
Jeroen Vreeken committed
170
	am335x_write32(base, AM335X_ADC_REG_IRQENABLE_CLR, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
171
172
	    AM335X_ADC_IRQENABLE_CLR_ALL);

Jeroen Vreeken's avatar
Jeroen Vreeken committed
173
	am335x_write32(base, AM335X_ADC_REG_DMAENABLE_CLR, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
174
175
	    AM335X_ADC_DMAENABLE_CLR_ALL);

176
177
178
179
180
181
182
183
184
185
186
187
188
189
	frequency = controller_time_frequency_get(adc->time);
	factor = 200000 / frequency;
	if (factor > 16) {
		avg = AM335X_ADC_STEPCONFIG_AVERAGE_16;
	} else if (factor > 8) {
		avg = AM335X_ADC_STEPCONFIG_AVERAGE_8;
	} else if (factor > 4) {
		avg = AM335X_ADC_STEPCONFIG_AVERAGE_4;
	} else if (factor > 2) {
		avg = AM335X_ADC_STEPCONFIG_AVERAGE_2;
	} else {
		avg = AM335X_ADC_STEPCONFIG_AVERAGE_1;
	}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
190
	am335x_write32(base, AM335X_ADC_REG_ADC_CLKDIV, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
191

Jeroen Vreeken's avatar
Jeroen Vreeken committed
192
193
	am335x_write32(base, AM335X_ADC_REG_IDLECONFIG, 0);
	am335x_write32(base, AM335X_ADC_REG_TS_CHARGE_DELAY, 1);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
194

Jeroen Vreeken's avatar
Jeroen Vreeken committed
195
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG1, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
196
197
198
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(0) |
199
200
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
201
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY1, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
202

Jeroen Vreeken's avatar
Jeroen Vreeken committed
203
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG2, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
204
205
206
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(1) |
207
208
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
209
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY2, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
210

Jeroen Vreeken's avatar
Jeroen Vreeken committed
211
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG3, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
212
213
214
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(2) |
215
216
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
217
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY3, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
218

Jeroen Vreeken's avatar
Jeroen Vreeken committed
219
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG4, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
220
221
222
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(3) |
223
224
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
225
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY4, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
226

Jeroen Vreeken's avatar
Jeroen Vreeken committed
227
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG5, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
228
229
230
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(4) |
231
232
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
233
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY5, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
234

Jeroen Vreeken's avatar
Jeroen Vreeken committed
235
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG6, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
236
237
238
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(5) |
239
240
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
241
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY6, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
242

Jeroen Vreeken's avatar
Jeroen Vreeken committed
243
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG7, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
244
245
246
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(6) |
247
248
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
249
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY7, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
250

Jeroen Vreeken's avatar
Jeroen Vreeken committed
251
	am335x_write32(base, AM335X_ADC_REG_STEPCONFIG8, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
252
253
254
	    AM335X_ADC_STEPCONFIG_SEL_RFP_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_RFM_SET(0) |
	    AM335X_ADC_STEPCONFIG_SEL_INP_SET(7) |
255
256
	    AM335X_ADC_STEPCONFIG_SEL_INM_SET(8) |
	    avg);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
257
	am335x_write32(base, AM335X_ADC_REG_STEPDELAY8, 0);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
258

Jeroen Vreeken's avatar
Jeroen Vreeken committed
259
	am335x_write32(base, AM335X_ADC_REG_CTRL, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
260
261
262
263
	    AM335X_ADC_CTRL_SC_WP_N |
	    AM335X_ADC_CTRL_SID |
	    AM335X_ADC_CTRL_ENABLE);

Jeroen Vreeken's avatar
Jeroen Vreeken committed
264
	am335x_write32(base, AM335X_ADC_REG_STEPENABLE, 
Jeroen Vreeken's avatar
Jeroen Vreeken committed
265
266
267
268
269
	    AM335X_ADC_STEPENABLE_STEP1 | AM335X_ADC_STEPENABLE_STEP2 |
	    AM335X_ADC_STEPENABLE_STEP3 | AM335X_ADC_STEPENABLE_STEP4 |
	    AM335X_ADC_STEPENABLE_STEP5 | AM335X_ADC_STEPENABLE_STEP6 |
	    AM335X_ADC_STEPENABLE_STEP7 | AM335X_ADC_STEPENABLE_STEP8 );

Jeroen Vreeken's avatar
Jeroen Vreeken committed
270
271
	return adc;

272
err_add:
Jeroen Vreeken's avatar
Jeroen Vreeken committed
273
274
err_param:
err_outterm:
Jeroen Vreeken's avatar
Jeroen Vreeken committed
275
	controller_block_free(adc);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
276
277
err_alloc:
err_rev:
Jeroen Vreeken's avatar
Jeroen Vreeken committed
278
279
	return NULL;
}
280
281
282
283
284

BLOCK_CREATE(am335x_adc) = {
	.create = block_am335x_adc_create,
	.args = { NULL },
};