237 lines
5.2 KiB
C
237 lines
5.2 KiB
C
/* adc-ti-adc108s102.c - TI's ADC 108s102 driver implementation */
|
|
|
|
/*
|
|
* Copyright (c) 2015 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <errno.h>
|
|
|
|
#include <kernel.h>
|
|
#include <misc/util.h>
|
|
#define SYS_LOG_NO_NEWLINE
|
|
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_ADC_LEVEL
|
|
#include <logging/sys_log.h>
|
|
#include <string.h>
|
|
#include <init.h>
|
|
|
|
#include "adc_ti_adc108s102.h"
|
|
|
|
static inline int _ti_adc108s102_sampling(struct device *dev)
|
|
{
|
|
struct ti_adc108s102_data *adc = dev->driver_data;
|
|
|
|
SYS_LOG_DBG("Sampling!\n");
|
|
|
|
/* SPI deals with u8_t buffers so multiplying by 2 the length */
|
|
return spi_transceive(adc->spi, adc->cmd_buffer,
|
|
adc->cmd_buf_len * 2,
|
|
adc->sampling_buffer,
|
|
adc->sampling_buf_len * 2);
|
|
}
|
|
|
|
static inline void _ti_adc108s102_handle_result(struct device *dev)
|
|
{
|
|
struct ti_adc108s102_data *adc = dev->driver_data;
|
|
struct adc_seq_table *seq_table = adc->seq_table;
|
|
struct ti_adc108s102_chan *chan;
|
|
struct adc_seq_entry *entry;
|
|
u32_t s_i, i;
|
|
|
|
SYS_LOG_DBG("_ti_adc108s102_handle_result()");
|
|
|
|
for (i = 0, s_i = 1; i < seq_table->num_entries; i++, s_i++) {
|
|
entry = &seq_table->entries[i];
|
|
chan = &adc->chans[entry->channel_id];
|
|
|
|
if (entry->buffer_length - chan->buf_idx == 0) {
|
|
continue;
|
|
}
|
|
|
|
*((u16_t *)(entry->buffer+chan->buf_idx)) =
|
|
ADC108S102_RESULT(adc->sampling_buffer[s_i]);
|
|
|
|
chan->buf_idx += 2;
|
|
}
|
|
}
|
|
|
|
static inline s32_t _ti_adc108s102_prepare(struct device *dev)
|
|
{
|
|
struct ti_adc108s102_data *adc = dev->driver_data;
|
|
struct adc_seq_table *seq_table = adc->seq_table;
|
|
struct ti_adc108s102_chan *chan;
|
|
s32_t sampling_delay = 0;
|
|
u32_t i;
|
|
|
|
adc->cmd_buf_len = 0;
|
|
adc->sampling_buf_len = 1; /* Counting the dummy byte */
|
|
|
|
for (i = 0; i < seq_table->num_entries; i++) {
|
|
struct adc_seq_entry *entry = &seq_table->entries[i];
|
|
|
|
/* No more space in the buffer? */
|
|
chan = &adc->chans[entry->channel_id];
|
|
if (entry->buffer_length - chan->buf_idx == 0) {
|
|
continue;
|
|
}
|
|
|
|
SYS_LOG_DBG("Requesting channel %d\n", entry->channel_id);
|
|
adc->cmd_buffer[adc->cmd_buf_len] =
|
|
ADC108S102_CHANNEL_CMD(entry->channel_id);
|
|
|
|
adc->cmd_buf_len++;
|
|
adc->sampling_buf_len++;
|
|
|
|
sampling_delay = entry->sampling_delay;
|
|
}
|
|
|
|
if (adc->cmd_buf_len == 0) {
|
|
return ADC108S102_DONE;
|
|
}
|
|
|
|
/* dummy cmd byte */
|
|
adc->cmd_buffer[adc->cmd_buf_len] = 0;
|
|
adc->cmd_buf_len++;
|
|
|
|
SYS_LOG_DBG("ADC108S102 is prepared...");
|
|
|
|
return sampling_delay;
|
|
}
|
|
|
|
static void ti_adc108s102_enable(struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
|
|
/*
|
|
* There is nothing to be done. If there is no sampling going on,
|
|
* the chip will put itself on power-saving mode (that is because
|
|
* SPI will release CS)
|
|
*/
|
|
}
|
|
|
|
static void ti_adc108s102_disable(struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
|
|
/* Same issue as with ti_adc108s102_enable() */
|
|
}
|
|
|
|
static inline int _verify_entries(struct adc_seq_table *seq_table)
|
|
{
|
|
struct adc_seq_entry *entry;
|
|
u32_t chans_set = 0;
|
|
int i;
|
|
|
|
for (i = 0; i < seq_table->num_entries; i++) {
|
|
entry = &seq_table->entries[i];
|
|
|
|
if (entry->sampling_delay <= 0 ||
|
|
entry->channel_id > ADC108S102_CHANNELS) {
|
|
return 0;
|
|
}
|
|
|
|
if (!entry->buffer_length) {
|
|
continue;
|
|
}
|
|
|
|
chans_set++;
|
|
}
|
|
|
|
return chans_set;
|
|
}
|
|
|
|
static int ti_adc108s102_read(struct device *dev,
|
|
struct adc_seq_table *seq_table)
|
|
{
|
|
const struct ti_adc108s102_config *config = dev->config->config_info;
|
|
struct ti_adc108s102_data *adc = dev->driver_data;
|
|
struct spi_config spi_conf;
|
|
int ret = 0;
|
|
s32_t delay;
|
|
|
|
spi_conf.config = config->spi_config_flags;
|
|
spi_conf.max_sys_freq = config->spi_freq;
|
|
|
|
if (spi_configure(adc->spi, &spi_conf)) {
|
|
return -EIO;
|
|
}
|
|
|
|
if (spi_slave_select(adc->spi, config->spi_slave)) {
|
|
return -EIO;
|
|
}
|
|
|
|
/* Resetting all internal channel data */
|
|
memset(adc->chans, 0, ADC108S102_CHANNELS_SIZE);
|
|
|
|
if (_verify_entries(seq_table) == 0) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
adc->seq_table = seq_table;
|
|
|
|
/* Sampling */
|
|
while (1) {
|
|
delay = _ti_adc108s102_prepare(dev);
|
|
if (delay == ADC108S102_DONE) {
|
|
break;
|
|
}
|
|
|
|
/* convert to milliseconds */
|
|
delay = (s32_t)((MSEC_PER_SEC * (u64_t)delay) /
|
|
sys_clock_ticks_per_sec);
|
|
|
|
k_sleep(delay);
|
|
|
|
ret = _ti_adc108s102_sampling(dev);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
|
|
_ti_adc108s102_handle_result(dev);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static const struct adc_driver_api ti_adc108s102_api = {
|
|
.enable = ti_adc108s102_enable,
|
|
.disable = ti_adc108s102_disable,
|
|
.read = ti_adc108s102_read,
|
|
};
|
|
|
|
static int ti_adc108s102_init(struct device *dev)
|
|
{
|
|
const struct ti_adc108s102_config *config = dev->config->config_info;
|
|
struct ti_adc108s102_data *adc = dev->driver_data;
|
|
|
|
adc->spi = device_get_binding((char *)config->spi_port);
|
|
if (!adc->spi) {
|
|
return -EPERM;
|
|
}
|
|
|
|
SYS_LOG_DBG("ADC108s102 initialized\n");
|
|
|
|
dev->driver_api = &ti_adc108s102_api;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_ADC_TI_ADC108S102
|
|
|
|
static struct ti_adc108s102_data adc108s102_data;
|
|
|
|
static const struct ti_adc108s102_config adc108s102_config = {
|
|
.spi_port = CONFIG_ADC_TI_ADC108S102_SPI_PORT_NAME,
|
|
.spi_config_flags = CONFIG_ADC_TI_ADC108S102_SPI_CONFIGURATION,
|
|
.spi_freq = CONFIG_ADC_TI_ADC108S102_SPI_MAX_FREQ,
|
|
.spi_slave = CONFIG_ADC_TI_ADC108S102_SPI_SLAVE,
|
|
};
|
|
|
|
DEVICE_INIT(adc108s102, CONFIG_ADC_0_NAME,
|
|
ti_adc108s102_init,
|
|
&adc108s102_data, &adc108s102_config,
|
|
POST_KERNEL, CONFIG_ADC_INIT_PRIORITY);
|
|
|
|
#endif /* CONFIG_ADC_TI_ADC108S102 */
|