/* adc-ti-adc108s102.c - TI's ADC 108s102 driver implementation */ /* * Copyright (c) 2015 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include "adc_ti_adc108s102.h" #ifndef CONFIG_ADC_DEBUG #define DBG(...) { ; } #else #if defined(CONFIG_STDOUT_CONSOLE) #include #define DBG printf #else #include #define DBG printk #endif /* CONFIG_STDOUT_CONSOLE */ #endif /* CONFIG_ADC_DEBUG */ static void _ti_adc108s102_sampling(int data, int unused) { struct device *dev = INT_TO_POINTER(data); struct ti_adc108s102_data *adc = dev->driver_data; ARG_UNUSED(unused); DBG("Sampling!\n"); /* SPI deals with uint8_t buffers so multiplying by 2 the length */ spi_transceive(adc->spi, (uint8_t *) adc->cmd_buffer, adc->cmd_buf_len*2, (uint8_t *) adc->sampling_buffer, adc->sampling_buf_len*2); } static void _ti_adc108s102_completed(struct device *dev, enum adc_callback_type cb_type) { struct ti_adc108s102_data *adc = dev->driver_data; adc->seq_table = NULL; adc->cb(dev, cb_type); } 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; uint32_t s_i, i; 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; } *((uint16_t *)entry->buffer+chan->buf_idx) = sys_be16_to_cpu(adc->sampling_buffer[s_i]); chan->buf_idx += 2; } } static int32_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; int32_t sampling_delay = 0; uint32_t i; adc->cmd_buf_len = 0; adc->sampling_buf_len = 1; 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; } 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) { /* We are done */ _ti_adc108s102_completed(dev, ADC_CB_DONE); return 0; } /* dummy cmd byte */ adc->cmd_buffer[adc->cmd_buf_len] = 0; adc->cmd_buf_len++; /* 64bits timestamp */ adc->sampling_buf_len += 4; DBG("ADC108S102 is prepared..."); return sampling_delay; } static inline void _ti_adc108s102_run_with_delay(struct device *dev, int32_t delay) { struct ti_adc108s102_data *adc = dev->driver_data; fiber_delayed_start(adc->sampling_stack, ADC108S102_SAMPLING_STACK_SIZE, _ti_adc108s102_sampling, POINTER_TO_INT(dev), 0, 0, 0, delay); } static void _ti_adc108s102_spi_cb(struct device *spi_dev, enum spi_cb_type cb_type, void *user_data) { struct device *dev = user_data; int32_t delay; DBG("_ti_adc108s102_spi_cb(%d)\n", cb_type); switch (cb_type) { case SPI_CB_WRITE: /* fall through */ case SPI_CB_READ: /* fall through */ case SPI_CB_TRANSCEIVE: _ti_adc108s102_handle_result(dev); delay = _ti_adc108s102_prepare(dev); _ti_adc108s102_run_with_delay(dev, delay); break; case SPI_CB_ERROR: /* fall through */ default: _ti_adc108s102_completed(dev, ADC_CB_ERROR); break; } } static void ti_adc108s102_enable(struct device *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) { /* Same issue as with ti_adc108s102_enable() */ } static void ti_adc108s102_set_callback(struct device *dev, adc_callback_t cb) { struct ti_adc108s102_data *adc = dev->driver_data; adc->cb = cb; } static inline int _verify_entries(struct adc_seq_table *seq_table) { struct adc_seq_entry *entry; uint32_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) { struct ti_adc108s102_config *config = dev->config->config_info; struct ti_adc108s102_data *adc = dev->driver_data; struct spi_config spi_conf; spi_conf.config = config->spi_config_flags; spi_conf.max_sys_freq = config->spi_freq; spi_conf.callback = _ti_adc108s102_spi_cb; if (spi_configure(adc->spi, &spi_conf, dev)) { return DEV_FAIL; } if (spi_slave_select(adc->spi, config->spi_slave)) { return DEV_FAIL; } /* Resetting all internal channel data */ memset(adc->chans, 0, ADC108S102_CHANNELS_SIZE); if (_verify_entries(seq_table) == 0) { return DEV_INVALID_CONF; } adc->seq_table = seq_table; /* Requesting sampling right away */ _ti_adc108s102_prepare(dev); _ti_adc108s102_sampling(POINTER_TO_INT(dev), 0); return DEV_OK; } struct adc_driver_api ti_adc108s102_api = { .enable = ti_adc108s102_enable, .disable = ti_adc108s102_disable, .set_callback = ti_adc108s102_set_callback, .read = ti_adc108s102_read, }; int ti_adc108s102_init(struct device *dev) { 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 DEV_NOT_CONFIG; } DBG("ADC108s102 initialized\n"); dev->driver_api = &ti_adc108s102_api; return DEV_OK; } #ifdef CONFIG_ADC_TI_ADC108S102_0 struct ti_adc108s102_data adc108s102_0_data; struct ti_adc108s102_config adc108s102_0_config = { .spi_port = CONFIG_ADC_TI_ADC108S102_0_SPI_PORT_NAME, .spi_config_flags = CONFIG_ADC_TI_ADC108S102_0_SPI_CONFIGURATION, .spi_freq = CONFIG_ADC_TI_ADC108S102_0_SPI_MAX_FREQ, .spi_slave = CONFIG_ADC_TI_ADC108S102_0_SPI_SLAVE, }; DECLARE_DEVICE_INIT_CONFIG(adc108s102_0, CONFIG_ADC_TI_ADC108S102_0_DRV_NAME, ti_adc108s102_init, &adc108s102_0_config); SYS_DEFINE_DEVICE(adc108s102_0, &adc108s102_0_data, SECONDARY, CONFIG_ADC_TI_ADC108S102_INIT_PRIORITY); #endif /* CONFIG_ADC_TI_ADC108S102_0 */