summaryrefslogtreecommitdiff
path: root/bsp/phytium/libraries/standalone/drivers/adc/fadc/fadc.c
blob: 83247b60e61002b4e00bc5d5032de9b2ee62819c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
/*
 * Copyright : (C) 2022 Phytium Information Technology, Inc.
 * All Rights Reserved.
 *
 * This program is OPEN SOURCE software: you can redistribute it and/or modify it
 * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
 * either version 1.0 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 Phytium Public License for more details.
 *
 *
 * FilePath: fadc.c
 * Date: 2022-02-10 14:53:42
 * LastEditTime: 2022-02-18 08:28:45
 * Description:  This files is for
 *
 * Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */
#include <string.h>
#include "fgeneric_timer.h"
#include "fkernel.h"
#include "ftypes.h"
#include "ferror_code.h"
#include "fdebug.h"
#include "fadc.h"
#include "fadc_hw.h"
#include "fparameters.h"
#include "fassert.h"
#include "fsleep.h"

#define FADC_DEBUG_TAG "FT_ADC"
#define FADC_DEBUG(format, ...)     FT_DEBUG_PRINT_D(FADC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FADC_INFO(format, ...)      FT_DEBUG_PRINT_I(FADC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FADC_WARN(format, ...)      FT_DEBUG_PRINT_W(FADC_DEBUG_TAG, format, ##__VA_ARGS__)
#define FADC_ERROR(format, ...)     FT_DEBUG_PRINT_E(FADC_DEBUG_TAG, format, ##__VA_ARGS__)

#define FADC_MAX_CLOCK_PRESC 16

#define FADC_MAX_THRESHOLD 0x400


/**
 * @name: FAdcPowerDownControl
 * @msg: Set power down signal
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {u8} power_state, this parameter must be enable or disable.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
static FError FAdcPowerDownControl(FAdcCtrl *pctrl, u8 power_state)
{

    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);
    if (power_state == FADC_CTRL_PD_ENABLE)
    {
        reg_val |= FADC_CTRL_REG_PD_EN;
    }
    else
    {
        reg_val &= ~(FADC_CTRL_REG_PD_EN);
    }

    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

    return FADC_SUCCESS;
}

/**
 * @name: FAdcChannelEnable
 * @msg: enable channel, corresponding to fix channel mode or multi channel mode.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {boolean} state, TRUE-enable, FALSE-disable
 * @return void
 */
void FAdcChannelEnable(FAdcCtrl *pctrl, FAdcChannel channel, boolean state)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    FASSERT(channel < FADC_CHANNEL_NUM);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);

    if (state == TRUE)
    {
        if (reg_val & FADC_CTRL_REG_FIX_CHANNEL)
        {
            reg_val &= ~(FADC_CTRL_REG_FIX_CHANNEL_NUM_MASK);
            reg_val |= FADC_CTRL_REG_FIX_CHANNEL_NUM(channel);
        }
        else
        {
            reg_val |= FADC_CTRL_REG_CHANNEL_EN(channel);
        }
    }
    else
    {
        /* fix channel mode, disable means stop convert */
        if (reg_val & FADC_CTRL_REG_FIX_CHANNEL)
        {
            reg_val &= ~(FADC_CTRL_REG_SOC_EN);

        }
        else
        {
            reg_val &= ~(FADC_CTRL_REG_CHANNEL_EN(channel));
        }
    }


    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

}

/**
 * @name: FAdcChannelThresholdSet
 * @msg: Set adc channel high_threshold and low_threshold.
 * you need use this function after FAdcConvertSet. If you want to use this function to
 * add other channel enable when the adc conversion is started, you need to restart the
 * adc convert start signal(adc_soc_en) after use to make the operation valid.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {FAdcThresholdConfig} *threshold_config, pointer to adc channel threshold value struct.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcChannelThresholdSet(FAdcCtrl *pctrl, FAdcChannel channel, FAdcThresholdConfig *threshold_config)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    FASSERT(channel < FADC_CHANNEL_NUM);

    u16 low_threshold = threshold_config->low_threshold;
    u16 high_threshold = threshold_config->high_threshold;

    FASSERT(high_threshold < FADC_MAX_THRESHOLD);
    FASSERT(low_threshold < high_threshold);

    uintptr base_addr = pctrl->config.base_addr;

    u32 threshold = (FADC_LEVEL_REG_HIGH_LEVEL(high_threshold)) |
                    (FADC_LEVEL_REG_LOW_LEVEL(low_threshold));
    FADC_WRITE_REG32(base_addr, (FADC_LEVEL_REG_OFFSET(channel)), threshold);

    return FADC_SUCCESS;
}

/**
 * @name: FAdcConvertSet
 * @msg: config adc convert parameters.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcConvertConfig} *convert_config, include convert mode,channel mode,
 *                            clock divider and convert_interval.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcConvertSet(FAdcCtrl *pctrl, FAdcConvertConfig *convert_config)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);

    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);

    /* clk_div config */
    u32 clk_div = convert_config->clk_div;
    FASSERT(clk_div < FADC_MAX_CLOCK_PRESC);
    if (clk_div % 2 == 1)
    {
        FADC_ERROR("clk_div is not even.");
        return FADC_ERR_INVAL_PARM;
    }
    reg_val &= (~FADC_CTRL_REG_CLK_DIV_MASK);
    reg_val |= FADC_CTRL_REG_CLK_DIV(clk_div);

    /* config convert mode */
    FAdcConvertMode convert_mode = convert_config->convert_mode;
    FASSERT(convert_mode < FADC_CONVERT_MODE_NUM);
    if (convert_mode == FADC_SINGLE_CONVERT)
    {
        reg_val |= FADC_CTRL_REG_SINGLE_CONVERT;
    }
    else
    {
        reg_val &= ~(FADC_CTRL_REG_SINGLE_CONVERT);
    }

    /* config channel mode */
    FAdcChannelMode channel_mode = convert_config->channel_mode;
    FASSERT(channel_mode < FADC_CHANNEL_MODE_NUM);

    if (channel_mode == FADC_FIXED_CHANNEL)
    {
        reg_val |= FADC_CTRL_REG_FIX_CHANNEL;
    }
    else
    {
        reg_val &= ~(FADC_CTRL_REG_FIX_CHANNEL);
    }
    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

    /* config time interval between two converts */
    FADC_WRITE_REG32(base_addr, FADC_INTER_REG_OFFSET, convert_config->convert_interval);

    return FADC_SUCCESS;
}


/**
 * @name: FAdcInterruptEnable
 * @msg: enable channel interrupt.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {FAdcIntrEvtType} event_type, interrupt event type
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcInterruptEnable(FAdcCtrl *pctrl, FAdcChannel channel, FAdcIntrEventType event_type)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);

    uintptr base_addr = pctrl->config.base_addr;
    u32 reg_val = 0;
    reg_val = FADC_READ_REG32(base_addr, FADC_INTRMASK_REG_OFFSET);
    switch (event_type)
    {
    case FADC_INTR_EVENT_COVFIN: /* enable channel convert complete irq */
        reg_val &= ~(FADC_INTRMASK_REG_COVFIN_MASK(channel));
        break;

    case FADC_INTR_EVENT_DLIMIT:
        reg_val &= ~(FADC_INTRMASK_REG_DLIMIT_MASK(channel));
        break;

    case FADC_INTR_EVENT_ULIMIT:
        reg_val &= ~(FADC_INTRMASK_REG_ULIMIT_MASK(channel));
        break;

    case FADC_INTR_EVENT_ERROR:
        reg_val &= ~(FADC_INTRMASK_REG_ERR_MASK);
        break;

    default:
        break;
    }

    FADC_WRITE_REG32(base_addr, FADC_INTRMASK_REG_OFFSET, reg_val);

    return FADC_SUCCESS;
}

/**
 * @name: FAdcInterruptDisable
 * @msg: disable channel interrupt.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {FAdcIntrEvtType} event_type, interrupt event type
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcInterruptDisable(FAdcCtrl *pctrl, FAdcChannel channel, FAdcIntrEventType event_type)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    FASSERT(channel < FADC_CHANNEL_NUM);

    uintptr base_addr = pctrl->config.base_addr;
    u32 reg_val = 0;
    reg_val = FADC_READ_REG32(base_addr, FADC_INTRMASK_REG_OFFSET);
    switch (event_type)
    {
    case FADC_INTR_EVENT_COVFIN: /* enable channel convert complete irq */
        reg_val |= (FADC_INTRMASK_REG_COVFIN_MASK(channel));
        break;

    case FADC_INTR_EVENT_DLIMIT:
        reg_val |= (FADC_INTRMASK_REG_DLIMIT_MASK(channel));
        break;

    case FADC_INTR_EVENT_ULIMIT:
        reg_val |= (FADC_INTRMASK_REG_ULIMIT_MASK(channel));
        break;

    case FADC_INTR_EVENT_ERROR:
        reg_val |= (FADC_INTRMASK_REG_ERR_MASK);
        break;

    default:
        break;
    }

    FADC_WRITE_REG32(base_addr, FADC_INTRMASK_REG_OFFSET, reg_val);

    return FADC_SUCCESS;
}

/**
 * @name: FAdcConvertStart
 * @msg: Start adc convert.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @return
 */
void FAdcConvertStart(FAdcCtrl *pctrl)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);
    reg_val |= FADC_CTRL_REG_SOC_EN;
    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

}

/**
 * @name: FAdcConvertStop
 * @msg: Stop adc convert.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @return
 */
void FAdcConvertStop(FAdcCtrl *pctrl)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);
    reg_val &= (~FADC_CTRL_REG_SOC_EN);
    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

}

/**
 * @name: FAdcInit
 * @msg: init adc variable configuration.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcConvertConfig} *convert_config, pointer to adc convert configuration
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcVariableConfig(FAdcCtrl *pctrl, FAdcConvertConfig *convert_config)
{
    FASSERT(pctrl != NULL);
    FASSERT(convert_config != NULL);

    FError ret = FADC_SUCCESS;

    /* disable power down signal */
    ret = FAdcPowerDownControl(pctrl, FADC_CTRL_PD_DISABLE);
    if (ret != FADC_SUCCESS)
    {
        FADC_ERROR("FAdcPowerDownControl failed.");
        return FADC_ERR_CMD_FAILED;
    }

    /* set time interval between two converts */
    ret = FAdcConvertSet(pctrl, convert_config);
    if (ret != FADC_SUCCESS)
    {
        FADC_ERROR("FAdcConvertSet failed.");
        return FADC_ERR_CMD_FAILED;
    }

    return ret;
}

/**
 * @name: FAdcSingleConvertEnable
 * @msg: Enable single convert signal, when convert mode is set to single conversion.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
static FError FAdcSingleConvertEnable(FAdcCtrl *pctrl)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;
    reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);
    reg_val |= FADC_CTRL_REG_SINGLE_CONVERT_EN;
    FADC_WRITE_REG32(base_addr, FADC_CTRL_REG_OFFSET, reg_val);

    return FADC_SUCCESS;
}

/**
 * @name: FAdcReadConvertResult
 * @msg: read adc channel convert result value.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {u16} *val, pointer to adc convert result value.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed.
 */
FError FAdcReadConvertResult(FAdcCtrl *pctrl, FAdcChannel channel, u16 *val)
{
    FASSERT(pctrl != NULL);
    FASSERT(channel < FADC_CHANNEL_NUM);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    int timeout = FADC_READ_DELAY;
    uintptr base_addr = pctrl->config.base_addr;

    u32 reg_val = FADC_READ_REG32(base_addr, FADC_CTRL_REG_OFFSET);
    /* single conversion */
    if (reg_val & FADC_CTRL_REG_SINGLE_CONVERT)
    {
        FAdcSingleConvertEnable(pctrl);
    }

    do
    {
        fsleep_millisec(10);
    }
    while ((!pctrl->convert_complete[channel]) && (0 <= --timeout));

    if (0 >= timeout)
    {
        FADC_ERROR("timeout when read adc data, convert is not completed.");
        *val = 0;
        return FADC_ERR_TIMEOUT;
    }

    FADC_CONVERT_UNCOMPLETE(pctrl->convert_complete[channel]);
    *val = pctrl->value[channel];

    return FADC_SUCCESS;
}

/**
 * @name: FAdcReadFinishCnt
 * @msg: read adc channel convert finish count.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {u32} *count, pointer to adc convert finish count.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed.
 */
FError FAdcReadFinishCnt(FAdcCtrl *pctrl, FAdcChannel channel, u32 *count)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);

    uintptr base_addr = pctrl->config.base_addr;
    *count = FADC_READ_REG32(base_addr, FADC_FINISH_CNT_REG_OFFSET(channel));
    return FADC_SUCCESS;
}

/**
 * @name: FAdcReadHisLimit
 * @msg: read adc channel history limit value, include upper limit and lower limit.
 * @param {FAdcCtrl} *pctrl, pointer to a FAdcCtrl structure that contains
 *                the configuration information for the specified adc module.
 * @param {FAdcChannel} channel, adc channel number.
 * @param {u16} *u_his_limit, pointer to adc convert history upper limit value.
 * @param {u16} *d_his_limit, pointer to adc convert history lower limit value.
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed.
 */
FError FAdcReadHisLimit(FAdcCtrl *pctrl, FAdcChannel channel, u16 *u_his_limit, u16 *d_his_limit)
{
    FASSERT(pctrl != NULL);
    FASSERT(FT_COMPONENT_IS_READY == pctrl->is_ready);
    u32 reg_val = 0;
    uintptr base_addr = pctrl->config.base_addr;

    reg_val = FADC_READ_REG32(base_addr, FADC_HIS_LIMIT_REG_OFFSET(channel));

    *u_his_limit = (reg_val & FADC_HIS_LIMIT_REG_UMASK) >> 16;
    *d_his_limit = (reg_val & FADC_HIS_LIMIT_REG_DMASK) ;

    return FADC_SUCCESS;
}

/**
 * @name: FAdcDeInitialize
 * @msg: DeInitialization function for the device instance
 * @param {FAdcCtrl} *pctrl, instance of FADC controller
 * @return {*}
 */
void FAdcDeInitialize(FAdcCtrl *pctrl)
{
    FASSERT(pctrl);

    pctrl->is_ready = 0;
    memset(pctrl, 0, sizeof(*pctrl));

    return;
}

/**
 * @name: FAdcCfgInitialize
 * @msg:  Initializes a specific instance such that it is ready to be used.
 * @param {FAdcCtrl} *pctrl, instance of FADC controller
 * @param {FAdcConfig} *input_config_p, Default configuration parameters of FADC
 * @return err code information, FADC_SUCCESS indicates success,others indicates failed
 */
FError FAdcCfgInitialize(FAdcCtrl *pctrl, const FAdcConfig *input_config_p)
{
    FASSERT(pctrl && input_config_p);

    FError ret = FADC_SUCCESS;
    /*
    * If the device is started, disallow the initialize and return a Status
    * indicating it is started.  This allows the user to de-initialize the device
    * and reinitialize, but prevents a user from inadvertently
    * initializing.
    */
    if (FT_COMPONENT_IS_READY == pctrl->is_ready)
    {
        FADC_WARN("device is already initialized!!!");
    }

    /*Set default values and configuration data */
    FAdcDeInitialize(pctrl);

    pctrl->config = *input_config_p;

    pctrl->is_ready = FT_COMPONENT_IS_READY;

    return ret;
}