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