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