/* 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 inline int _ti_adc108s102_sampling(struct device *dev) { struct ti_adc108s102_data *adc = dev->driver_data; DBG("Sampling!\n"); /* SPI deals with uint8_t buffers so multiplying by 2 the length */ return 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 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)) = ADC108S102_RESULT(adc->sampling_buffer[s_i]); chan->buf_idx += 2; } } static inline 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; /* 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; } 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++; DBG("ADC108S102 is prepared..."); return sampling_delay; } 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 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; uint32_t data[2] = {0, 0}; struct nano_timer timer; int ret = DEV_OK; int32_t delay; spi_conf.config = config->spi_config_flags; spi_conf.max_sys_freq = config->spi_freq; nano_timer_init(&timer, data); if (spi_configure(adc->spi, &spi_conf)) { 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; /* Sampling */ while (1) { delay = _ti_adc108s102_prepare(dev); if (delay == ADC108S102_DONE) { break; } nano_timer_start(&timer, delay); nano_task_timer_test(&timer, TICKS_UNLIMITED); ret = _ti_adc108s102_sampling(dev); if (ret != DEV_OK) { break; } _ti_adc108s102_handle_result(dev); } return ret; } struct adc_driver_api ti_adc108s102_api = { .enable = ti_adc108s102_enable, .disable = ti_adc108s102_disable, .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, }; DEVICE_INIT(adc108s102_0, CONFIG_ADC_TI_ADC108S102_0_DRV_NAME, ti_adc108s102_init, &adc108s102_0_data, &adc108s102_0_config, SECONDARY, CONFIG_ADC_TI_ADC108S102_INIT_PRIORITY); #endif /* CONFIG_ADC_TI_ADC108S102_0 */